Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
1652787
Propose test harness resource cleanup with worker evidence
jwhiting Oct 1, 2026
99b7ed9
Narrow resource cleanup proposal after independent review
jwhiting Oct 1, 2026
d3570bf
Revise resource cleanup proposal around worker lock decisions
jwhiting Oct 27, 2026
57a701d
docs: define bounded Blaxel worker recovery
jwhiting Oct 27, 2026
74d2294
Merge origin/main before deriving resource-cleanup specs
jwhiting Oct 27, 2026
cd8aa45
Specify worker resource cleanup and abandoned-run recovery
jwhiting Oct 27, 2026
9fd51f4
Derive resource cleanup proofs and refine lease specifications
jwhiting Oct 27, 2026
3fa15d4
Define live harness test placement and address proof review
jwhiting Oct 27, 2026
70f27cc
Plan resource cleanup slices after proof convergence
jwhiting Oct 27, 2026
04a6b27
Correct resource cleanup validation plan after review
jwhiting Oct 27, 2026
564a8ed
Add real worker lifetime seam before harness cleanup
jwhiting Oct 27, 2026
74485d2
Generate nested worker fixture configs within their acceptance
jwhiting Oct 27, 2026
2460d06
Specify failed and pending worker build cleanup contracts
jwhiting Oct 27, 2026
8bfd952
Dispose reusable builds at runner worker teardown
jwhiting Oct 27, 2026
d43623b
Observe built asset loading in the selected product walks
jwhiting Oct 27, 2026
a2fd5a1
Use built assets in five product walks and close remaining build life…
jwhiting Oct 27, 2026
3156e30
Place the unsupported URL document under the static web root
jwhiting Oct 27, 2026
502ba25
Keep worker build helpers compatible with the repository TypeScript t…
jwhiting Oct 27, 2026
3897645
Use the Vitest polling interval option for startup disposal
jwhiting Oct 27, 2026
036d049
Record slice one worker lifetime and built-app validation
jwhiting Oct 27, 2026
bda9b6c
Specify bounded resource diagnostics and real parent capture
jwhiting Oct 27, 2026
e4a094a
Require diagnostics for each combined Vitest member
jwhiting Oct 27, 2026
24229bd
Retain bounded resource evidence through native failures and retries
jwhiting Oct 27, 2026
86bdf6d
Exercise abrupt parent death and reserved final observations
jwhiting Oct 27, 2026
83e8c9f
Avoid inferring permission failure from any kernel-reader exit
jwhiting Oct 27, 2026
f72654e
Distinguish diagnostic identities across infrastructure attempts
jwhiting Oct 27, 2026
0db76dd
Require an attributable kernel-reader limitation in the real seam
jwhiting Oct 27, 2026
cf4fb51
Use epoch bounds supported by the installed kernel log reader
jwhiting Oct 27, 2026
734a29a
Expose the unexpected kernel-reader error in the focused seam
jwhiting Oct 27, 2026
dcc0847
Use UTC calendar bounds accepted by the worker kernel reader
jwhiting Oct 27, 2026
056f9e2
Inspect the installed dmesg interval parser on the private worker
jwhiting Oct 27, 2026
b9e9cbf
Require exact interval filtering of coarse kernel reads
jwhiting Oct 27, 2026
0e82df7
Bound kernel reads by seconds and retain only the observed interval
jwhiting Oct 27, 2026
296391c
Record slice 2 diagnostic proof and Blaxel validation
jwhiting Oct 27, 2026
1320c95
test: expose Blaxel lease recovery gaps
jwhiting Oct 27, 2026
2c0f5d6
Implement guarded worker ownership and result retention
jwhiting Oct 27, 2026
e102e20
Exercise worker recovery and private Blaxel qualification
jwhiting Oct 27, 2026
e59caa5
Serialize shutdown cleanup with outstanding worker operations
jwhiting Oct 27, 2026
1293931
Keep optional diagnostics within their bounded transport
jwhiting Oct 27, 2026
b501651
Cover renewal and cleanup of partially provisioned private workers
jwhiting Oct 27, 2026
53d800f
Preserve attempt evidence across worker checkout reset
jwhiting Oct 27, 2026
c748287
Retain recovery evidence and keep the guard on the mutating process
jwhiting Oct 27, 2026
7ffa179
Tighten live qualification and release failed architecture reservations
jwhiting Oct 27, 2026
49cfe0c
Revalidate cleanup targets and record private qualification progress
jwhiting Oct 27, 2026
720cef0
Update coordinator wiring assertions for retained shutdown evidence
jwhiting Oct 27, 2026
5b23a42
Cover audit residue preservation and unknown dispatch retention
jwhiting Oct 27, 2026
9d197e8
Wait for accepted private worker deletion to become observable
jwhiting Oct 27, 2026
d32457f
Follow retry artifact paths and limit short leases to crash experiments
jwhiting Oct 27, 2026
06b07c0
Expose evidence retention and require prepared undispatched reports b…
jwhiting Oct 27, 2026
45202ee
Retain prepared evidence before release and allow the cold-worker ren…
jwhiting Oct 27, 2026
2dc0e7d
Record slice 3 private qualification and completed proof coverage
jwhiting Oct 27, 2026
6d50559
Cover configurable Blaxel harness placement and recovery defaults
jwhiting Oct 27, 2026
7b0213b
Configure the live Blaxel harness without personal resource names
jwhiting Oct 27, 2026
dc1d9f2
Record reusable harness qualification and slice review response
jwhiting Oct 27, 2026
7c66d16
Record slice convergence and integrated harness reconciliation
jwhiting Oct 27, 2026
3077425
Record passing shared-pool full gate and private cleanup
jwhiting Oct 27, 2026
278e906
Apply bounded refinements from integrated harness review
jwhiting Oct 27, 2026
ca2f902
Prepare harness contribution documents for review
jwhiting Oct 27, 2026
6b5721c
test: reproduce unprivileged worker lease audits
jwhiting Oct 27, 2026
704f484
fix: scope fixture process audits before reading environments
jwhiting Oct 27, 2026
34ee305
Record Blaxel permission regression validation
jwhiting Oct 27, 2026
4a28597
Prepare permission regression fix for CI
jwhiting Oct 27, 2026
294f256
test: reproduce unreadable same-user processes outside the fixture
jwhiting Oct 27, 2026
2156f26
fix: enumerate only explicit fixture processes in lease seams
jwhiting Oct 27, 2026
9787188
Prepare scoped process fixtures for CI
jwhiting Oct 27, 2026
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
98 changes: 98 additions & 0 deletions docs/archive/2026-10/test-harness-resource-cleanup-plan.md

Large diffs are not rendered by default.

254 changes: 254 additions & 0 deletions docs/archive/2026-10/test-harness-resource-cleanup-proposal.md

Large diffs are not rendered by default.

25 changes: 14 additions & 11 deletions packages/web/test/e2e/browser-demo-mode.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import os from "node:os";
import path from "node:path";
import { test, expect } from "../../../../test/helpers/playwright.ts";
import { launchProductServer, type ProductServer } from "../../../../test/helpers/product-server.ts";
import { recordApplicationRequests } from "../../../../test/helpers/application-requests.ts";
import { APPLICATION_SHELL_STATES, waitForApplicationRender } from "../../../../test/helpers/application-readiness.ts";
import { configureTestMotion, pickChannelByName } from "./helpers.ts";

Expand Down Expand Up @@ -72,11 +73,10 @@ async function createURLArtifact(
return ((await response.json()) as { artifact: { id: string } }).artifact.id;
}

async function openApp(page: Page, server: ProductServer, baseURL: string | undefined): Promise<void> {
if (!baseURL) throw new Error("Expected Playwright baseURL");
const appBaseURL = await server.appURL(baseURL);
await page.goto(`${appBaseURL}/packages/web/src/index.html`);
async function openApp(page: Page, server: ProductServer, requests: ReturnType<typeof recordApplicationRequests>): Promise<void> {
await page.goto(server.serverURL);
await waitForApp(page);
requests.expectBuilt();
}

async function waitForApp(page: Page): Promise<void> {
Expand Down Expand Up @@ -106,8 +106,10 @@ test.describe("browser demo mode", () => {
let home: string;
let site: Awaited<ReturnType<typeof startExternalSite>>;
let server: ProductServer | null = null;
let requests: ReturnType<typeof recordApplicationRequests>;

test.beforeEach(async () => {
test.beforeEach(async ({ page }) => {
requests = recordApplicationRequests([page]);
home = mkdtempSync(path.join(os.tmpdir(), "television-demo-home-"));
site = await startExternalSite();
server = await launchProductServer({
Expand All @@ -117,22 +119,23 @@ test.describe("browser demo mode", () => {
});

test.afterEach(async () => {
await requests.attach(test.info());
await server?.dispose();
server = null;
await site.close();
rmSync(home, { recursive: true, force: true });
});

// spec: proofs/product/artifacts.md#^af-ac-demo-mode
test("the home-directory marker turns direct external pages on and off at app load (^af-ac-demo-mode)", async ({ page, baseURL }) => {
test("the home-directory marker turns direct external pages on and off at app load (^af-ac-demo-mode)", async ({ page }) => {
if (!server) throw new Error("Product server was not started");
const [channel] = await channels(server);
if (!channel) throw new Error("Expected a default channel");
const pageURL = `${site.origin}/one`;
await createURLArtifact(server, pageURL, channel.id);
const returnButton = page.getByRole("button", { name: RETURN_LABEL });

await openApp(page, server, baseURL);
await openApp(page, server, requests);
await expect(artifactFrame(page)).toHaveAttribute("src", /\/views\/url-unsupported\//);
await expect(returnButton).toHaveCount(0);

Expand All @@ -152,15 +155,15 @@ test.describe("browser demo mode", () => {
});

// spec: proofs/product/artifacts.md#^af-ac-demo-return
test("the artifact icon, an app reload, and a channel round trip each return to the original page (^af-ac-demo-return)", async ({ page, baseURL }) => {
test("the artifact icon, an app reload, and a channel round trip each return to the original page (^af-ac-demo-return)", async ({ page }) => {
if (!server) throw new Error("Product server was not started");
writeFileSync(path.join(home, MARKER), "");
const [channel] = await channels(server);
if (!channel) throw new Error("Expected a default channel");
await createChannel(server, "Elsewhere");
await createURLArtifact(server, `${site.origin}/one`, channel.id);

await openApp(page, server, baseURL);
await openApp(page, server, requests);
await expect(frameHeading(page)).toHaveText("Fixture page one");

await followNext(page);
Expand All @@ -181,7 +184,7 @@ test.describe("browser demo mode", () => {
});

// spec: proofs/arch/artifact-frame/artifact-bridge.md#^ab-ac-demo-inert-seam
test("bridge-shaped messages from a demo-mode page change nothing (^ab-ac-demo-inert-seam)", async ({ page, baseURL }) => {
test("bridge-shaped messages from a demo-mode page change nothing (^ab-ac-demo-inert-seam)", async ({ page }) => {
if (!server) throw new Error("Product server was not started");
writeFileSync(path.join(home, MARKER), "");
const [channel] = await channels(server);
Expand All @@ -191,7 +194,7 @@ test.describe("browser demo mode", () => {
await createURLArtifact(server, pageURL, channel.id);
await createURLArtifact(server, `${site.origin}/two`, channel.id, "Second page");

await openApp(page, server, baseURL);
await openApp(page, server, requests);
const selected = page.getByRole("option", { name: channel.name, exact: true });
await expect(selected).toHaveAttribute("aria-selected", "true");
const tabs = page.locator(".top-bar .tab");
Expand Down
3 changes: 2 additions & 1 deletion packages/web/test/e2e/gate-boot-barrier.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { expect, test, type Page } from "@playwright/test";
import { type Page } from "@playwright/test";
import { expect, test } from "../../../../test/helpers/playwright.ts";
import { mkdtempSync, rmSync } from "node:fs";
import os from "node:os";
import path from "node:path";
Expand Down
26 changes: 18 additions & 8 deletions packages/web/test/e2e/theme-product-acceptance.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import { TelevisionClient } from "@telepath-computer/television-shared";
import { test, expect } from "../../../../test/helpers/playwright.ts";
import { launchProductServer, type ProductServer } from "../../../../test/helpers/product-server.ts";
import { seedThemePackage } from "../../../../test/helpers/theme-package.ts";
import { recordApplicationRequests } from "../../../../test/helpers/application-requests.ts";
import { startStableFrontProxy } from "../../../../test/helpers/stable-front-proxy.ts";
import { waitForApplicationShell } from "./helpers.ts";
import {
APPLICATION_SHELL_STATES,
Expand Down Expand Up @@ -611,12 +613,12 @@ test("Firefox refreshes a ready Markdown editor from a fixed-dark theme to light
// proofs/arch/themes/delivery.md#^theme-delivery-t-active-package-refresh
test("theme settings persist rendered app and artifact outcomes through a built-server restart", async ({
browser,
baseURL,
}) => {
if (!baseURL) throw new Error("Expected Playwright baseURL");
const context = await browser.newContext({ colorScheme: null });
const page = await context.newPage();
const requests = recordApplicationRequests([page]);
const product = await launchProductServer();
const front = await startStableFrontProxy(product.serverURL);
try {
const themeAPath = seedThemePackage(
product.home,
Expand Down Expand Up @@ -691,9 +693,10 @@ test("theme settings persist rendered app and artifact outcomes through a built-
"https://example.com/appearance",
);

const appURL = await product.appURL(baseURL);
await page.goto(`${appURL}/packages/web/src/index.html`);
const appURL = front.url;
await page.goto(appURL);
await waitForApplicationShell(page);
requests.expectBuilt();

await openSettings(page);
await page.getByRole("button", { name: "Refresh themes" }).click();
Expand Down Expand Up @@ -843,6 +846,7 @@ test("theme settings persist rendered app and artifact outcomes through a built-
)).toHaveCount(0);

await product.restart();
front.setTarget(product.serverURL);
await waitForApplicationShell(page);
await expectAppearance("dark", FIXED_DARK);
const persistedDisplay = await fetch(new URL("/display", product.serverURL));
Expand All @@ -868,6 +872,8 @@ test("theme settings persist rendered app and artifact outcomes through a built-
expect((await expectSandboxFrame(page, "overlay")).instance)
.not.toBe(beforeAdaptiveOverlay.instance);
} finally {
await requests.attach(test.info());
await front.dispose();
await product.dispose();
await context.close();
}
Expand All @@ -880,7 +886,6 @@ test("theme settings persist rendered app and artifact outcomes through a built-
// proofs/arch/themes/delivery.md#^theme-delivery-t-frame-appearance-browser
test("executable themes run only in the Chromium application lifecycle and isolate failures", async ({
page,
baseURL,
browserName,
}) => {
test.skip(browserName !== "chromium", "Chromium owns executable-theme browser acceptance");
Expand All @@ -890,11 +895,12 @@ test("executable themes run only in the Chromium application lifecycle and isola
const reconnectBackoffBudget = 30_000;
const themeResetNavigationBudget = 30_000;
test.setTimeout(test.info().timeout + reconnectBackoffBudget + 2 * themeResetNavigationBudget);
if (!baseURL) throw new Error("Expected Playwright baseURL");

const product = await launchProductServer();
const front = await startStableFrontProxy(product.serverURL);
const secondPage = await page.context().newPage();
const applicationPages = [page, secondPage] as const;
const requests = recordApplicationRequests(applicationPages);
const selectReloadingTheme = async (value: string): Promise<void> => {
// A consented script is cleared by replacing both application documents.
// Observe that navigation before applying ordinary post-render assertions.
Expand Down Expand Up @@ -1062,13 +1068,14 @@ document.querySelector("#artifact-probe").addEventListener("click", () => {
"Executable Theme Artifact",
artifactPath,
);
const appURL = await product.appURL(baseURL);
const appURL = front.url;
await Promise.all(applicationPages.map(async (applicationPage) => {
await applicationPage.goto(
`${appURL}/packages/web/src/index.html`,
appURL,
);
await waitForApplicationShell(applicationPage);
}));
requests.expectBuilt();
await openSettings(page);
await page.getByRole("button", { name: "Refresh themes" }).click();
const themeSelect = page.locator('tv-select[name="theme"]');
Expand Down Expand Up @@ -1783,6 +1790,7 @@ document.querySelector("#artifact-probe").addEventListener("click", () => {
await expectExecutableRuns(applicationPages, 3);

await product.restart();
front.setTarget(product.serverURL);
// Allow one capped retry interval plus the usual 5s shell-ready budget.
await Promise.all(applicationPages.map((applicationPage) =>
waitForApplicationRender(
Expand Down Expand Up @@ -1845,6 +1853,8 @@ document.querySelector("#artifact-probe").addEventListener("click", () => {
expect(scriptRequests.length).toBeGreaterThan(0);
expect(scriptRequests.every((owner) => owner === "application")).toBe(true);
} finally {
await requests.attach(test.info());
await front.dispose();
await product.dispose();
await secondPage.close();
}
Expand Down
3 changes: 2 additions & 1 deletion packages/web/test/e2e/update-journey.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { expect, test, type Page } from "@playwright/test";
import { type Page } from "@playwright/test";
import { expect, test } from "../../../../test/helpers/playwright.ts";
import { mkdtempSync, rmSync } from "node:fs";
import os from "node:os";
import path from "node:path";
Expand Down
3 changes: 2 additions & 1 deletion packages/web/test/e2e/update-notification.01.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { expect, test, type Locator, type Page } from "@playwright/test";
import { type Locator, type Page } from "@playwright/test";
import { expect, test } from "../../../../test/helpers/playwright.ts";
import { mkdtempSync, rmSync } from "node:fs";
import os from "node:os";
import path from "node:path";
Expand Down
3 changes: 2 additions & 1 deletion packages/web/test/e2e/update-notification.02.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { expect, test, type Page } from "@playwright/test";
import { type Page } from "@playwright/test";
import { expect, test } from "../../../../test/helpers/playwright.ts";
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
import os from "node:os";
import path from "node:path";
Expand Down
3 changes: 2 additions & 1 deletion packages/web/test/e2e/update-reload.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { expect, test, type Page } from "@playwright/test";
import { type Page } from "@playwright/test";
import { expect, test } from "../../../../test/helpers/playwright.ts";
import { mkdtempSync, rmSync } from "node:fs";
import os from "node:os";
import path from "node:path";
Expand Down
3 changes: 2 additions & 1 deletion packages/web/test/foundation-copy.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { globSync, readFileSync, statSync } from "node:fs";
import path from "node:path";
import { describe, expect, test } from "vitest";
import { describe, expect } from "vitest";
import { test } from "../../../test/helpers/vitest.ts";
import { enumerateTrackedPaths } from "../../../scripts/test/file-inventory.mjs";
import { buildVersionedWebBundle } from "../../../test/helpers/versioned-web-bundle.ts";
import {
Expand Down
Loading
Loading