feat: cut over Memory to subjektiv product surfaces

This commit is contained in:
2026-10-03 00:06:47 +09:00
parent 07fcc249fe
commit f4966b78ea
54 changed files with 7600 additions and 848 deletions
@@ -11,23 +11,263 @@ if (
}
const workspaceId = "memory-review";
const representativeSubjectId =
"release-coordination-subject-with-a-deliberately-long-stable-identity-for-responsive-review";
const representativeMemoryId =
"memory-decision-with-a-deliberately-long-stable-identity-for-overflow-review-0000000001";
const derivedMemoryId = "memory-derived-source-0002";
const emptySubjectId = "empty-subject";
const staleSubjectId = "stale-subject";
const failedSubjectId = "failed-subject";
const ungeneratedSubjectId = "ungenerated-subject";
const errorSubjectId = "error-subject";
const paragraphs = Array.from(
{ length: sectionCount },
(_, index) =>
`## Section ${
index + 1
}\n\nThis is representative Memory content with **important context**, an identifier \`memory-item-${
}\n\nThis is representative resident Memory context with **important context**, an identifier \`memory-item-${
index + 1
}\`, and a long URL https://example.com/${"long-segment-".repeat(12)}${
index + 1
}.\n\n> A durable note for section ${index + 1}.\n\n- first detail\n- second detail`,
).join("\n\n");
const bodyMd =
`# Workspace Memory\n\nThis document is read-only.\n\n| Very wide heading | Another heading | Decision |\n| --- | --- | --- |\n| ${
const surfaceBodyMd =
`# Resident subject context\n\nThis generated surface is read-only.\n\n| Very wide heading | Another heading | Decision |\n| --- | --- | --- |\n| ${
"wide-value-".repeat(16)
} | stable | keep scrolling local |\n\n##### Deep document heading\n\n###### Deepest document heading\n\n\`\`\`rust\nfn example() { println!("${
} | stable | keep scrolling local |\n\n##### Deep surface heading\n\n###### Deepest surface heading\n\n\`\`\`rust\nfn example() { println!("${
"wide-code-".repeat(18)
}"); }\n\`\`\`\n\n[Safe link](https://example.com) [Unsafe link](javascript:alert(1))\n\n<img src=x onerror=alert(1)>\n\n${paragraphs}\n\n## T-661 UNIQUE END MARKER`;
}"); }\n\`\`\`\n\n[Safe link](https://example.com) [Unsafe link](javascript:alert(1))\n\n<img src=x onerror=alert(1)>\n\n${paragraphs}\n\n## Surface content complete`;
const detailBodyMd = `# Committed Memory detail
This immutable revision preserves its candidate evidence, source refs, and derivation refs.
| Local table overflow | Value |
| --- | --- |
| ${"detail-wide-value-".repeat(14)} | stable |
\`\`\`text
${"detail-wide-code-".repeat(18)}
\`\`\`
[Safe evidence link](https://example.com/evidence) [Unsafe evidence link](javascript:alert(2))
<script>alert("not rendered")</script>`;
const subjects = [
subject(representativeSubjectId, "Release coordination", "active", 42),
subject(emptySubjectId, "Empty ready subject", "active", 0),
subject(staleSubjectId, "Stale surface subject", "active", 19),
subject(failedSubjectId, "Failed surface subject", "active", 8),
subject(ungeneratedSubjectId, "Ungenerated subject", "active", 0),
subject(errorSubjectId, "Unavailable subject", "retired", 3),
];
function subject(id: string, role: string, state: "active" | "retired", storeRevision: number) {
return {
id,
role,
state,
store_revision: storeRevision,
created_at: "2026-01-01T00:00:00Z",
updated_at: "2026-01-02T03:04:05Z",
};
}
function memoriesFor(subjectId: string) {
if (subjectId === emptySubjectId || subjectId === ungeneratedSubjectId) return [];
if (subjectId === staleSubjectId) {
return [
memorySummary("stale-memory-1", 2, "lesson", "resolved", "A resolved stale-surface lesson"),
];
}
if (subjectId === failedSubjectId) {
return [
memorySummary(
"failed-memory-1",
1,
"constraint",
"retracted",
"A retracted failed-surface constraint",
),
];
}
return [
memorySummary(
representativeMemoryId,
3,
"decision",
"active",
"Keep subject Memory provenance typed and visible",
),
memorySummary(
"memory-resolved-0002",
2,
"lesson",
"resolved",
"The bounded reader must preserve continuations",
),
memorySummary(
"memory-retracted-0003",
1,
"working_assumption",
"retracted",
"T-672 UNIQUE END MARKER",
),
];
}
function memorySummary(
id: string,
revision: number,
kind: string,
state: string,
claim: string,
) {
return {
id,
revision,
kind,
state,
claim,
excerpt: `Read-only ${state} Memory with exact revision and provenance metadata.`,
updated_at: "2026-01-02T03:04:05Z",
};
}
function surfaceFor(subjectId: string) {
if (subjectId === representativeSubjectId) {
return {
subject_id: subjectId,
availability: "ready",
snapshot: {
snapshot_id: "surface-snapshot-0042",
body_md: surfaceBodyMd,
memory_refs: [
{ memory_id: representativeMemoryId, revision: 3 },
{ memory_id: derivedMemoryId, revision: 4 },
],
built_from_store_revision: 42,
created_at: "2026-01-02T03:04:05Z",
},
};
}
if (subjectId === emptySubjectId) {
return {
subject_id: subjectId,
availability: "ready",
snapshot: {
snapshot_id: "surface-snapshot-empty",
body_md: "",
memory_refs: [],
built_from_store_revision: 0,
created_at: "2026-01-02T03:04:05Z",
},
};
}
if (subjectId === staleSubjectId) return { subject_id: subjectId, availability: "stale" };
if (subjectId === failedSubjectId) return { subject_id: subjectId, availability: "failed" };
return { subject_id: subjectId, availability: "ungenerated" };
}
function memoryDetail(memoryId: string, requestedRevision: number | null) {
const revision = requestedRevision && requestedRevision <= 3 ? requestedRevision : 3;
const states = { 1: "retracted", 2: "resolved", 3: "active" } as const;
return {
memory_id: memoryId,
revision,
current_revision: 3,
kind: "decision",
state: states[revision as keyof typeof states],
claim: revision === 3
? "Keep subject Memory provenance typed and visible"
: `Historical provenance decision, revision ${revision}`,
body_md: detailBodyMd,
why_useful:
"Future readers can audit why a committed Memory exists without exposing unbounded session content.",
staleness: null,
change_reason: revision === 3
? "Clarified the durable read contract."
: "Immutable historical revision.",
created_at: "2026-01-01T00:00:00Z",
updated_at: `2026-01-0${revision}T03:04:05Z`,
body_offset: 0,
body_byte_offset: 0,
body_truncated: false,
source_candidate_ids: ["candidate-release-decision-0001"],
source_candidates: [{
candidate_id: "candidate-release-decision-0001",
evidence: [{
id: "evidence-message-0001",
kind: "message",
entry_range: [12, 14],
origin: {
kind: "flow_instruction",
workspace_id: workspaceId,
runtime_id: "runtime-fixture",
worker_id: "worker-fixture",
flow_selector: "builtin:coder-review",
flow_definition_id: "flow-definition-fixture",
flow_definition_revision: 7,
},
excerpt: "Use normal explicit subject routes and preserve provenance.",
summary: "The product contract was explicitly requested.",
}],
evidence_total: 1,
evidence_truncated: false,
source_refs: [{
session_id: "session-fixture-0001",
segment_id: "segment-fixture-0001",
entry_range: [12, 14],
evidence_id: "evidence-message-0001",
origin: { kind: "human_input", account_id: "account-fixture" },
evidence_kind: "message",
label: "T-672 product direction",
summary: "Bounded source reference retained with the committed revision.",
}],
source_refs_total: 1,
source_refs_truncated: false,
}],
derived_from: [{ memory_id: derivedMemoryId, revision: 4 }],
evidence_has_more: false,
};
}
function revisions(memoryId: string) {
return {
memory_id: memoryId,
current_revision: 3,
items: [
{
revision: 3,
kind: "decision",
state: "active",
claim: "Keep subject Memory provenance typed and visible",
change_reason: "Clarified the durable read contract.",
updated_at: "2026-01-03T03:04:05Z",
},
{
revision: 2,
kind: "decision",
state: "resolved",
claim: "Historical provenance decision, revision 2",
change_reason: "Resolved after endpoint integration.",
updated_at: "2026-01-02T03:04:05Z",
},
{
revision: 1,
kind: "decision",
state: "retracted",
claim: "Historical provenance decision, revision 1",
change_reason: "Retracted the legacy shape.",
updated_at: "2026-01-01T03:04:05Z",
},
],
has_more: false,
};
}
const json = (value: unknown, status = 200) =>
new Response(JSON.stringify(value), {
@@ -110,15 +350,34 @@ Deno.serve({ hostname: "127.0.0.1", port }, async (request) => {
if (url.pathname === `/api/w/${workspaceId}/working-directories`) {
return json({ workspace_id: workspaceId, items: [], diagnostics: [] });
}
if (url.pathname === `/api/w/${workspaceId}/memory`) {
return json({
body_md: bodyMd,
created_at: "2026-01-01T00:00:00Z",
updated_at: "2026-01-02T03:04:05Z",
bytes: new TextEncoder().encode(bodyMd).byteLength,
record_source: "sqlite_workspace_authority.memory_document",
});
const subjectsPath = `/api/w/${workspaceId}/subjektiv/subjects`;
if (url.pathname === subjectsPath) {
return json({ limit: 100, items: subjects, has_more: false });
}
if (url.pathname.startsWith(`${subjectsPath}/`)) {
const suffix = url.pathname.slice(subjectsPath.length + 1);
const parts = suffix.split("/").map(decodeURIComponent);
const subjectId = parts[0];
if (subjectId === errorSubjectId) return json({}, 503);
const foundSubject = subjects.find((item) => item.id === subjectId);
if (!foundSubject) return json({}, 404);
if (parts.length === 1) return json(foundSubject);
if (parts.length === 2 && parts[1] === "surface") return json(surfaceFor(subjectId));
if (parts.length === 2 && parts[1] === "memories") {
return json({ items: memoriesFor(subjectId), has_more: false });
}
if (parts.length >= 3 && parts[1] === "memories") {
const memoryId = parts[2];
if (parts.length === 4 && parts[3] === "revisions") return json(revisions(memoryId));
if (parts.length === 3) {
const requested = url.searchParams.get("revision");
return json(memoryDetail(memoryId, requested === null ? null : Number(requested)));
}
}
}
if (
url.pathname === `/api/w/${workspaceId}/protocol/ws` &&
request.headers.get("upgrade") === "websocket"
@@ -9,6 +9,10 @@ const fixtureServer = join(
"tools/web-ux/browser-tests/memory_document_fixture_server.ts",
);
const workspaceId = "memory-review";
const subjectId =
"release-coordination-subject-with-a-deliberately-long-stable-identity-for-responsive-review";
const memoryId =
"memory-decision-with-a-deliberately-long-stable-identity-for-overflow-review-0000000001";
async function freePort(): Promise<number> {
const listener = Deno.listen({ hostname: "127.0.0.1", port: 0 });
@@ -41,8 +45,8 @@ async function markerIsInsideMain(page: Page): Promise<boolean> {
return await page.evaluate(() => {
const document = (globalThis as any).document;
const main = document.querySelector("main");
const marker = [...document.querySelectorAll("h2")].find((heading) =>
heading.textContent === "T-661 UNIQUE END MARKER"
const marker = [...document.querySelectorAll("h3")].find((heading) =>
heading.textContent === "T-672 UNIQUE END MARKER"
);
if (!main || !marker) return false;
const mainRect = main.getBoundingClientRect();
@@ -51,31 +55,86 @@ async function markerIsInsideMain(page: Page): Promise<boolean> {
});
}
async function openMemoryPage(
async function assertNoPageWideOverflow(page: Page): Promise<void> {
assertEquals(
await page.evaluate(() => {
const document = (globalThis as any).document;
return document.documentElement.scrollWidth === document.documentElement.clientWidth;
}),
true,
);
}
async function assertMainOwnsVerticalScroll(page: Page): Promise<void> {
const nested = await page.locator("main").evaluate((main) =>
[...main.querySelectorAll("*")]
.filter((element) => {
const style = (globalThis as any).getComputedStyle(element);
return ["auto", "scroll"].includes(style.overflowY) &&
element.scrollHeight > element.clientHeight + 1;
})
.map((element) => `${element.tagName.toLowerCase()}.${element.className}`)
);
assertEquals(nested, []);
}
async function openSubjectPage(
page: Page,
baseUrl: string,
mobile = false,
): Promise<void> {
await page.goto(`${baseUrl}/w/${workspaceId}/memory`);
const heading = page.locator("h1", { hasText: "Workspace Memory" });
await page.goto(`${baseUrl}/w/${workspaceId}/memory/${encodeURIComponent(subjectId)}`);
const heading = page.locator("h1", { hasText: "Release coordination" });
await heading.waitFor({ state: "attached" });
if (mobile) await page.getByRole("button", { name: "Hide sidebar" }).click();
if (mobile) {
const showSidebar = page.getByRole("button", { name: "Show sidebar" });
await showSidebar.waitFor();
assertEquals(await showSidebar.getAttribute("aria-expanded"), "false");
assertEquals(
await page.locator("main").evaluate((main) => (main as unknown as { inert: boolean }).inert),
false,
);
await showSidebar.click();
const hideSidebar = page.getByRole("button", { name: "Hide sidebar" });
await hideSidebar.waitFor();
assertEquals(await hideSidebar.getAttribute("aria-expanded"), "true");
assertEquals(
await page.locator("main").evaluate((main) => (main as unknown as { inert: boolean }).inert),
true,
);
await hideSidebar.click();
await showSidebar.waitFor();
assertEquals(await showSidebar.getAttribute("aria-expanded"), "false");
assertEquals(
await page.locator("main").evaluate((main) => (main as unknown as { inert: boolean }).inert),
false,
);
}
await heading.waitFor();
}
async function swipeMainToEnd(page: Page): Promise<void> {
const session = await page.context().newCDPSession(page);
const viewport = page.viewportSize();
if (!viewport) throw new Error("touch viewport is unavailable");
const x = Math.max(20, Math.min(300, viewport.width - 20));
const startY = Math.max(120, viewport.height - 100);
const moveYs = [0.8, 0.62, 0.44, 0.26, 0.12].map((ratio) =>
Math.max(20, Math.round(viewport.height * ratio))
);
for (let attempt = 0; attempt < 100; attempt += 1) {
const state = await mainScrollState(page);
if (state.scrollTop + state.clientHeight >= state.scrollHeight - 1) return;
await session.send("Input.dispatchTouchEvent", {
type: "touchStart",
touchPoints: [{ x: 300, y: 700, id: 1 }],
touchPoints: [{ x, y: startY, id: 1 }],
});
for (const y of [580, 460, 340, 220, 100]) {
for (const y of moveYs) {
await session.send("Input.dispatchTouchEvent", {
type: "touchMove",
touchPoints: [{ x: 300, y, id: 1 }],
touchPoints: [{ x, y, id: 1 }],
});
}
await session.send("Input.dispatchTouchEvent", {
@@ -84,10 +143,10 @@ async function swipeMainToEnd(page: Page): Promise<void> {
});
await page.waitForTimeout(20);
}
throw new Error("touch input did not reach the end of the Memory document");
throw new Error("touch input did not reach the end of the resident Memory surface");
}
Deno.test("production Memory shell renders safe Markdown and scrolls to its end by wheel, keyboard, and touch", async () => {
Deno.test("production subject Memory shell renders exact states, safe Markdown, provenance, and one scroll owner", async () => {
const build = await new Deno.Command(Deno.execPath(), {
args: ["task", "build"],
cwd: workspaceRoot,
@@ -130,6 +189,13 @@ Deno.test("production Memory shell renders safe Markdown and scrolls to its end
colorScheme: "light" as const,
mobile: true,
},
{
label: "compact-mobile",
width: 320,
height: 700,
colorScheme: "dark" as const,
mobile: true,
},
]
) {
const context = await browser.newContext({
@@ -144,21 +210,28 @@ Deno.test("production Memory shell renders safe Markdown and scrolls to its end
if (message.type() === "error") errors.push(message.text());
});
page.on("pageerror", (error) => errors.push(String(error)));
await openMemoryPage(page, baseUrl, scenario.mobile);
await openSubjectPage(page, baseUrl, scenario.mobile);
const initial = await mainScrollState(page);
assert(initial.scrollHeight > initial.clientHeight);
assertEquals(await markerIsInsideMain(page), false);
await assertNoPageWideOverflow(page);
await assertMainOwnsVerticalScroll(page);
assertEquals(
await page.evaluate(() => {
const document = (globalThis as any).document;
return document.documentElement.scrollWidth === document.documentElement.clientWidth;
}),
true,
await page.locator('aside a[href$="/memory"]', { hasText: "Subjects" }).count(),
1,
);
assertEquals(await page.locator("aside a", { hasText: "Staging" }).count(), 0);
if (scenario.label === "wheel") {
assertEquals(await page.locator("h1").allTextContents(), ["Workspace Memory"]);
assertEquals(
await page.getByRole("heading", {
name: "Release coordination",
level: 1,
exact: true,
}).count(),
1,
);
assertEquals(
await page.locator("strong").filter({ hasText: "important context" }).count() > 0,
true,
@@ -167,8 +240,8 @@ Deno.test("production Memory shell renders safe Markdown and scrolls to its end
assertEquals(await page.locator("ul li").count() > 0, true);
for (
const heading of [
{ selector: "h5", text: "Deep document heading" },
{ selector: "h6", text: "Deepest document heading" },
{ selector: "h5", text: "Deep surface heading" },
{ selector: "h6", text: "Deepest surface heading" },
]
) {
const element = page.locator(heading.selector, { hasText: heading.text });
@@ -182,8 +255,17 @@ Deno.test("production Memory shell renders safe Markdown and scrolls to its end
}
assertEquals(await page.locator('a[href="https://example.com"]').count(), 1);
assertEquals(await page.locator('a[href^="javascript:"]').count(), 0);
assertEquals(await page.locator("article img, article script").count(), 0);
assertEquals(await page.getByRole("heading", { name: "Memory Document" }).count(), 0);
assertEquals(
await page.getByRole("article", { name: "Resident surface" }).locator("img, script")
.count(),
0,
);
for (const state of ["Active", "Resolved", "Retracted"]) {
assertEquals(
await page.locator(".memory-pill", { hasText: state }).count(),
1,
);
}
for (const label of ["Markdown table", "rust code block"]) {
const region = page.getByRole("region", { name: label });
@@ -194,7 +276,7 @@ Deno.test("production Memory shell renders safe Markdown and scrolls to its end
await page.locator("main").hover();
await page.mouse.wheel(0, 100_000);
} else if (scenario.label === "keyboard") {
await page.getByText("Document details", { exact: true }).focus();
await page.getByText("Surface provenance", { exact: true }).focus();
await page.keyboard.press("End");
} else {
await swipeMainToEnd(page);
@@ -213,33 +295,72 @@ Deno.test("production Memory shell renders safe Markdown and scrolls to its end
await context.close();
}
const stateContext = await browser.newContext({ viewport: { width: 1440, height: 900 } });
const emptyPage = await stateContext.newPage();
await emptyPage.route(`**/api/w/${workspaceId}/memory`, async (route) => {
await route.fulfill({
contentType: "application/json",
body: JSON.stringify({
body_md: " \n",
created_at: "2026-01-01T00:00:00Z",
updated_at: "2026-01-02T03:04:05Z",
bytes: 2,
record_source: "fixture",
}),
});
});
await emptyPage.goto(`${baseUrl}/w/${workspaceId}/memory`);
await emptyPage.getByText("Memory document is empty.").waitFor();
assertEquals(await emptyPage.getByRole("alert").count(), 0);
const detailContext = await browser.newContext({ viewport: { width: 1440, height: 900 } });
const detailPage = await detailContext.newPage();
await detailPage.goto(
`${baseUrl}/w/${workspaceId}/memory/${encodeURIComponent(subjectId)}/${
encodeURIComponent(memoryId)
}`,
);
await detailPage.getByRole("heading", {
name: "Keep subject Memory provenance typed and visible",
level: 1,
}).waitFor();
assertEquals(await detailPage.getByText("candidate-release-decision-0001").count(), 1);
assertEquals(await detailPage.getByText("T-672 product direction").count(), 1);
assertEquals(await detailPage.getByText("memory-derived-source-0002").count(), 1);
assertEquals(await detailPage.getByRole("heading", { name: "Revision history" }).count(), 1);
assertEquals(await detailPage.getByText("Revision 3", { exact: true }).count(), 1);
assertEquals(await detailPage.getByText("Revision 2", { exact: true }).count(), 1);
assertEquals(await detailPage.getByText("Revision 1", { exact: true }).count(), 1);
assertEquals(await detailPage.locator('a[href^="javascript:"]').count(), 0);
assertEquals(
await detailPage.getByRole("article", { name: "Committed Memory body" }).locator(
"script, img",
).count(),
0,
);
for (const label of ["Markdown table", "text code block"]) {
const region = detailPage.getByRole("region", { name: label });
assertEquals(await region.getAttribute("tabindex"), "0");
assert(await region.evaluate((element) => element.scrollWidth > element.clientWidth));
}
await assertNoPageWideOverflow(detailPage);
await assertMainOwnsVerticalScroll(detailPage);
await detailContext.close();
const errorPage = await stateContext.newPage();
await errorPage.route(`**/api/w/${workspaceId}/memory`, async (route) => {
await route.fulfill({ status: 503, contentType: "application/json", body: "{}" });
});
await errorPage.goto(`${baseUrl}/w/${workspaceId}/memory`);
const alert = errorPage.getByRole("alert");
await alert.waitFor();
assert((await alert.textContent())?.includes("Memory document unavailable."));
assertEquals(await errorPage.getByText("Memory document is empty.").count(), 0);
const stateContext = await browser.newContext({ viewport: { width: 390, height: 844 } });
const stateCases = [
{
id: "empty-subject",
text: "Resident surface is ready and empty.",
role: "status" as const,
},
{ id: "stale-subject", text: "Resident surface is stale.", role: "status" as const },
{
id: "failed-subject",
text: "Resident surface generation failed.",
role: "alert" as const,
},
{
id: "ungenerated-subject",
text: "Resident surface has not been generated.",
role: "status" as const,
},
{ id: "error-subject", text: "Resident surface unavailable.", role: "alert" as const },
];
for (const stateCase of stateCases) {
const page = await stateContext.newPage();
await page.goto(`${baseUrl}/w/${workspaceId}/memory/${stateCase.id}`);
const state = page.getByRole(stateCase.role).filter({ hasText: stateCase.text });
await state.waitFor();
assert((await state.textContent())?.includes(stateCase.text));
if (stateCase.id !== "empty-subject") {
assertEquals(await page.getByRole("article", { name: "Resident surface" }).count(), 0);
}
await assertNoPageWideOverflow(page);
await page.close();
}
await stateContext.close();
} finally {
await browser.close();
@@ -0,0 +1,113 @@
{
"schemaVersion": 1,
"id": "memory-subjects-dark",
"title": "Memory subjects, surfaces, and committed records — dark",
"baseUrl": "http://127.0.0.1:15286",
"colorScheme": "dark",
"reducedMotion": "reduce",
"personas": [{
"id": "fixture",
"label": "Read-only Memory fixture",
"auth": { "kind": "anonymous" }
}],
"viewports": [
{ "label": "desktop", "width": 1440, "height": 900 },
{ "label": "narrow", "width": 768, "height": 900 },
{ "label": "mobile", "width": 390, "height": 844 },
{ "label": "compact", "width": 320, "height": 700 }
],
"routes": [
{
"id": "subjects",
"label": "Subject index",
"path": "/w/memory-review/memory",
"goal": "Choose an explicit Memory subject and inspect state, role, store revision, worker availability, and long identities.",
"dataState": "Active and retired subjects spanning representative, empty, stale, failed, ungenerated, and unavailable states.",
"ready": { "kind": "selector", "selector": "[data-memory-view='subjects'] .subject-list" },
"capturePoints": [{ "id": "initial", "label": "Subjects" }]
},
{
"id": "representative",
"label": "Ready subject surface",
"path": "/w/memory-review/memory/release-coordination-subject-with-a-deliberately-long-stable-identity-for-responsive-review",
"goal": "Read the ready resident surface and scan active, resolved, and retracted committed Memories without nested vertical scrolling.",
"dataState": "Ready generated Markdown surface with long content, unsafe Markdown, wide table/code, provenance refs, and three lifecycle states.",
"ready": {
"kind": "selector",
"selector": "[data-memory-view='subject'][data-memory-state='ready'] article[aria-label='Resident surface']"
},
"capturePoints": [{ "id": "initial", "label": "Ready subject" }]
},
{
"id": "detail",
"label": "Committed Memory detail",
"path": "/w/memory-review/memory/release-coordination-subject-with-a-deliberately-long-stable-identity-for-responsive-review/memory-decision-with-a-deliberately-long-stable-identity-for-overflow-review-0000000001",
"goal": "Audit immutable Memory body, candidate evidence, source refs, derivations, and revision history.",
"dataState": "Current active revision with bounded typed provenance and active/resolved/retracted immutable history.",
"ready": { "kind": "selector", "selector": "[data-memory-view='detail'] .revision-list" },
"capturePoints": [{ "id": "initial", "label": "Memory detail" }]
},
{
"id": "empty",
"label": "Ready-empty subject",
"path": "/w/memory-review/memory/empty-subject",
"goal": "Distinguish a valid ready-empty snapshot and an empty committed Memory list from failure.",
"dataState": "Ready snapshot with empty Markdown and no refs; successful current list with no records.",
"ready": {
"kind": "selector",
"selector": "[data-memory-view='subject'][data-memory-state='ready'] [data-surface-ready-empty]"
},
"capturePoints": [{ "id": "initial", "label": "Ready empty" }]
},
{
"id": "stale",
"label": "Stale subject surface",
"path": "/w/memory-review/memory/stale-subject",
"goal": "Recognize that no snapshot is displayable while committed Memories remain readable.",
"dataState": "Stale availability without snapshot and one resolved committed Memory.",
"ready": {
"kind": "selector",
"selector": "[data-memory-view='subject'][data-memory-state='stale']"
},
"capturePoints": [{ "id": "initial", "label": "Stale" }]
},
{
"id": "failed",
"label": "Failed subject surface",
"path": "/w/memory-review/memory/failed-subject",
"goal": "See generation failure without displaying a failed or partial snapshot.",
"dataState": "Failed availability without snapshot and one retracted committed Memory.",
"ready": {
"kind": "selector",
"selector": "[data-memory-view='subject'][data-memory-state='failed']"
},
"capturePoints": [{ "id": "initial", "label": "Failed" }]
},
{
"id": "error",
"label": "Subject endpoint error",
"path": "/w/memory-review/memory/error-subject",
"goal": "Keep each read-only region explicit when subject, surface, and current Memory requests fail.",
"dataState": "Intentional HTTP 503 from all subject-scoped endpoints.",
"ready": {
"kind": "selector",
"selector": "[data-memory-view='subject'][data-memory-state='error']"
},
"capturePoints": [{ "id": "initial", "label": "Unavailable" }]
}
],
"processes": [{
"id": "memory-fixture",
"command": "deno",
"cwd": "..",
"args": [
"run",
"--allow-net",
"--allow-read",
"browser-tests/memory_document_fixture_server.ts",
"15286",
"../../web/workspace/build"
],
"readyUrl": "http://127.0.0.1:15286/health"
}]
}
@@ -0,0 +1,113 @@
{
"schemaVersion": 1,
"id": "memory-subjects-light",
"title": "Memory subjects, surfaces, and committed records — light",
"baseUrl": "http://127.0.0.1:15285",
"colorScheme": "light",
"reducedMotion": "reduce",
"personas": [{
"id": "fixture",
"label": "Read-only Memory fixture",
"auth": { "kind": "anonymous" }
}],
"viewports": [
{ "label": "desktop", "width": 1440, "height": 900 },
{ "label": "narrow", "width": 768, "height": 900 },
{ "label": "mobile", "width": 390, "height": 844 },
{ "label": "compact", "width": 320, "height": 700 }
],
"routes": [
{
"id": "subjects",
"label": "Subject index",
"path": "/w/memory-review/memory",
"goal": "Choose an explicit Memory subject and inspect state, role, store revision, worker availability, and long identities.",
"dataState": "Active and retired subjects spanning representative, empty, stale, failed, ungenerated, and unavailable states.",
"ready": { "kind": "selector", "selector": "[data-memory-view='subjects'] .subject-list" },
"capturePoints": [{ "id": "initial", "label": "Subjects" }]
},
{
"id": "representative",
"label": "Ready subject surface",
"path": "/w/memory-review/memory/release-coordination-subject-with-a-deliberately-long-stable-identity-for-responsive-review",
"goal": "Read the ready resident surface and scan active, resolved, and retracted committed Memories without nested vertical scrolling.",
"dataState": "Ready generated Markdown surface with long content, unsafe Markdown, wide table/code, provenance refs, and three lifecycle states.",
"ready": {
"kind": "selector",
"selector": "[data-memory-view='subject'][data-memory-state='ready'] article[aria-label='Resident surface']"
},
"capturePoints": [{ "id": "initial", "label": "Ready subject" }]
},
{
"id": "detail",
"label": "Committed Memory detail",
"path": "/w/memory-review/memory/release-coordination-subject-with-a-deliberately-long-stable-identity-for-responsive-review/memory-decision-with-a-deliberately-long-stable-identity-for-overflow-review-0000000001",
"goal": "Audit immutable Memory body, candidate evidence, source refs, derivations, and revision history.",
"dataState": "Current active revision with bounded typed provenance and active/resolved/retracted immutable history.",
"ready": { "kind": "selector", "selector": "[data-memory-view='detail'] .revision-list" },
"capturePoints": [{ "id": "initial", "label": "Memory detail" }]
},
{
"id": "empty",
"label": "Ready-empty subject",
"path": "/w/memory-review/memory/empty-subject",
"goal": "Distinguish a valid ready-empty snapshot and an empty committed Memory list from failure.",
"dataState": "Ready snapshot with empty Markdown and no refs; successful current list with no records.",
"ready": {
"kind": "selector",
"selector": "[data-memory-view='subject'][data-memory-state='ready'] [data-surface-ready-empty]"
},
"capturePoints": [{ "id": "initial", "label": "Ready empty" }]
},
{
"id": "stale",
"label": "Stale subject surface",
"path": "/w/memory-review/memory/stale-subject",
"goal": "Recognize that no snapshot is displayable while committed Memories remain readable.",
"dataState": "Stale availability without snapshot and one resolved committed Memory.",
"ready": {
"kind": "selector",
"selector": "[data-memory-view='subject'][data-memory-state='stale']"
},
"capturePoints": [{ "id": "initial", "label": "Stale" }]
},
{
"id": "failed",
"label": "Failed subject surface",
"path": "/w/memory-review/memory/failed-subject",
"goal": "See generation failure without displaying a failed or partial snapshot.",
"dataState": "Failed availability without snapshot and one retracted committed Memory.",
"ready": {
"kind": "selector",
"selector": "[data-memory-view='subject'][data-memory-state='failed']"
},
"capturePoints": [{ "id": "initial", "label": "Failed" }]
},
{
"id": "error",
"label": "Subject endpoint error",
"path": "/w/memory-review/memory/error-subject",
"goal": "Keep each read-only region explicit when subject, surface, and current Memory requests fail.",
"dataState": "Intentional HTTP 503 from all subject-scoped endpoints.",
"ready": {
"kind": "selector",
"selector": "[data-memory-view='subject'][data-memory-state='error']"
},
"capturePoints": [{ "id": "initial", "label": "Unavailable" }]
}
],
"processes": [{
"id": "memory-fixture",
"command": "deno",
"cwd": "..",
"args": [
"run",
"--allow-net",
"--allow-read",
"browser-tests/memory_document_fixture_server.ts",
"15285",
"../../web/workspace/build"
],
"readyUrl": "http://127.0.0.1:15285/health"
}]
}