Skip to content
Open
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
5 changes: 4 additions & 1 deletion src/components/layout/model-atlas-docs-header.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -197,10 +197,13 @@ describe("ModelAtlasDocsHeader", () => {
const drawer = document.getElementById(panelId ?? "");
expect(drawer).toBeTruthy();
expect(drawer?.getAttribute("role")).toBe("dialog");
const primaryNav = within(drawer as HTMLElement).getByRole("navigation", {
name: "Primary",
});

const expectedItems = getPrimaryNavItems(messages);
for (const item of expectedItems) {
const link = within(drawer as HTMLElement).getByRole("link", {
const link = within(primaryNav).getByRole("link", {
name: item.label,
});
expect(link.getAttribute("href")).toBe(item.href);
Expand Down
2 changes: 1 addition & 1 deletion src/features/models/components/RegistryGraphFlow.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import { PageAssetsProvider } from "@/features/docs/components/page-assets-conte
import { PageMessagesProvider } from "@/features/docs/components/page-messages-context";
import {
GraphNodeLabel,
RegistryGraphFlow,
nodeVisualRoleHasHandles,
RegistryGraphFlow,
} from "@/features/models/components/RegistryGraphFlow";
import { REGISTRY_GRAPH_FLOW_INTERACTION } from "@/features/models/components/registry-graph-flow-theme";
import {
Expand Down
4 changes: 0 additions & 4 deletions src/features/models/components/RegistryGraphFlow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -248,10 +248,6 @@ function AttentionHeadNode({
data,
}: NodeProps<Node<RegistryFlowNodeData, "attentionHead">>) {
const visualRole = data.visualRole ?? "default";
const isHeadBox =
visualRole === "query-head" ||
visualRole === "key-head" ||
visualRole === "value-head";
const hasHandles = nodeVisualRoleHasHandles(visualRole);

return (
Expand Down
5 changes: 4 additions & 1 deletion src/lib/content/content-reconciliation-sidebar-meta.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,10 @@ describe("Phase 2/3 reconciliation docs sidebar meta (US-003)", () => {
expect(sidebarUrls).toHaveLength(sectionPages.length);

const sidebarTitles = folder.children
.filter((node): node is Extract<Node, { type: "page" }> => node.type === "page")
.filter(
(node): node is Extract<Node, { type: "page" }> =>
node.type === "page",
)
.map((node) => node.name);
for (const page of sectionPages) {
expect(sidebarTitles).toContain(page.messages.title);
Expand Down
6 changes: 3 additions & 3 deletions src/lib/content/glossary-architecture-index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,9 +187,9 @@ describe("Phase 2 glossary and architecture index navigation (US-007)", () => {

for (const slug of CURRENT_GLOSSARY_SLUGS) {
const title = EXPECTED_GLOSSARY_TITLES[slug];
expect(linkNodes.some((entry) => entry.url === `/docs/glossary/${slug}`)).toBe(
true,
);
expect(
linkNodes.some((entry) => entry.url === `/docs/glossary/${slug}`),
).toBe(true);
expect(linkNodes.some((entry) => entry.name === title)).toBe(true);
}
});
Expand Down
2 changes: 1 addition & 1 deletion src/lib/content/pages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { loadPageMessages } from "@/lib/content/page-messages-load";
import {
type PageFrontmatter,
type PageMessages,
pageMessagesSchema,
pageFrontmatterSchema,
pageMessagesSchema,
} from "@/lib/content/schemas";
import { isShippedLocalizedDocsSlug } from "@/lib/content/shipped-localized-docs";
import { parseYamlFrontmatterBlock } from "@/lib/content/yaml-frontmatter";
Expand Down
33 changes: 24 additions & 9 deletions src/lib/navigation/generated-docs-page-tree.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import type { Node, Root } from "fumadocs-core/page-tree";
import { loadPublishedDocsPagesSync, type DocsPageSource } from "@/lib/content/pages";
import {
type DocsPageSource,
loadPublishedDocsPagesSync,
} from "@/lib/content/pages";
import {
getConceptById,
getModelById,
getModuleById,
getPaperById,
getSystemById,
getTrainingRegimeById,
} from "@/lib/content/registry-runtime";
Expand Down Expand Up @@ -171,7 +172,9 @@ function generateGlossaryNodes(pages: DocsPageSource[]): Node[] {
name: "Sequence And Attention",
match: (page) => {
const record = getConceptById(page.frontmatter.registryId);
return record ? GLOSSARY_SEQUENCE_AND_ATTENTION_SLUGS.has(record.slug) : false;
return record
? GLOSSARY_SEQUENCE_AND_ATTENTION_SLUGS.has(record.slug)
: false;
},
},
{
Expand Down Expand Up @@ -212,7 +215,9 @@ function generateConceptNodes(pages: DocsPageSource[]): Node[] {
},
{
name: "Inference",
match: (page) => getConceptById(page.frontmatter.registryId)?.conceptType === "inference",
match: (page) =>
getConceptById(page.frontmatter.registryId)?.conceptType ===
"inference",
},
{
name: "Architecture",
Expand All @@ -237,7 +242,9 @@ function generateModuleNodes(pages: DocsPageSource[]): Node[] {
name: "Attention Foundations",
match: (page) => {
const record = getModuleById(page.frontmatter.registryId);
return record ? MODULE_ATTENTION_FOUNDATION_SLUGS.has(record.slug) : false;
return record
? MODULE_ATTENTION_FOUNDATION_SLUGS.has(record.slug)
: false;
},
},
{
Expand Down Expand Up @@ -267,7 +274,8 @@ function generateModuleNodes(pages: DocsPageSource[]): Node[] {
{
name: "Normalization",
match: (page) =>
getModuleById(page.frontmatter.registryId)?.moduleType === "normalization",
getModuleById(page.frontmatter.registryId)?.moduleType ===
"normalization",
},
{
name: "Positional And Sequence Encoding",
Expand Down Expand Up @@ -368,7 +376,10 @@ export function buildGeneratedDocsPageTree(baseTree: Root): Root {
}

const gettingStarted = baseTree.children.find(
(node) => node.type === "page" && "url" in node && node.url === "/docs/getting-started",
(node) =>
node.type === "page" &&
"url" in node &&
node.url === "/docs/getting-started",
);

const children: Node[] = [];
Expand All @@ -380,7 +391,11 @@ export function buildGeneratedDocsPageTree(baseTree: Root): Root {
children.push({
type: "folder",
name: SECTION_TITLES[section],
children: generateSectionNodes(section, pagesBySection.get(section) ?? []),
defaultOpen: true,
children: generateSectionNodes(
section,
pagesBySection.get(section) ?? [],
),
});
}

Expand Down
10 changes: 10 additions & 0 deletions src/lib/source.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,4 +273,14 @@ describe("docs navigation source", () => {
expect(separatorNames).toContain(separatorName);
}
});

test("top-level docs sidebar sections render expanded by default", () => {
for (const node of source.pageTree.children) {
if (node.type !== "folder") {
continue;
}

expect(node.defaultOpen).toBe(true);
}
});
});
11 changes: 11 additions & 0 deletions src/lib/verify/docs-shell-convergence.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,15 @@ describe("assertDocsShellConvergence", () => {
DOCS_SHELL_CONVERGENCE_REASONS.missingGlossaryLabel,
);
});

test("reports a missing token glossary link from the rendered sidebar HTML", () => {
const missingTokenLinkHtml = UNIFIED_SHELL_HTML.replace(
`<a href="${TOKEN_GLOSSARY_URL}">Token</a>`,
"<span>Token</span>",
);

expect(assertDocsShellConvergence(missingTokenLinkHtml)).toBe(
DOCS_SHELL_CONVERGENCE_REASONS.missingTokenGlossaryLink,
);
});
});
5 changes: 1 addition & 4 deletions src/lib/verify/docs-shell-convergence.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import {
collectSidebarPageLinks,
extractNdSidebarHtml,
hasLegacyPlaceholderSidebar,
PLACEHOLDER_SIDEBAR_DESCRIPTION,
stripHtmlScripts,
TOKEN_GLOSSARY_URL,
} from "@/lib/navigation/docs-sidebar-contract";
import { source } from "@/lib/source";

/** Stable failure reasons for unified docs shell convergence checks. */
export const DOCS_SHELL_CONVERGENCE_REASONS = {
Expand Down Expand Up @@ -56,8 +54,7 @@ export function assertDocsShellConvergence(html: string): string | null {
return DOCS_SHELL_CONVERGENCE_REASONS.missingGlossaryLabel;
}

const pageTreeLinks = collectSidebarPageLinks(source.pageTree);
if (!pageTreeLinks.some((link) => link.url === TOKEN_GLOSSARY_URL)) {
if (!sidebar.includes(`href="${TOKEN_GLOSSARY_URL}"`)) {
return DOCS_SHELL_CONVERGENCE_REASONS.missingTokenGlossaryLink;
}

Expand Down
44 changes: 18 additions & 26 deletions src/tests/a11y/docs-sidebar-navigation.a11y.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,20 @@ describe("docs sidebar navigation accessibility", () => {
restoreFetchMock();
});

async function ensureSidebarFolderExpanded(
sidebar: HTMLElement,
name: string,
) {
const folder = within(sidebar).getByRole("button", { name });
if (folder.getAttribute("aria-expanded") === "true") {
return;
}

await act(async () => {
folder.click();
});
}

test("CanonicalDocsLayout exposes keyboard-reachable Token and GQA sidebar links", async () => {
captureOriginalFetch();
await installDocsSearchFetchMock();
Expand Down Expand Up @@ -54,19 +68,8 @@ describe("docs sidebar navigation accessibility", () => {
expect(within(sidebar).queryByLabelText("Toggle Theme")).toBe(null);
expect(sidebar.querySelector("[data-theme-toggle]")).toBe(null);

const glossaryFolder = within(sidebar).getByRole("button", {
name: "Glossary",
});
await act(async () => {
glossaryFolder.click();
});

const modulesFolder = within(sidebar).getByRole("button", {
name: "Modules",
});
await act(async () => {
modulesFolder.click();
});
await ensureSidebarFolderExpanded(sidebar, "Glossary");
await ensureSidebarFolderExpanded(sidebar, "Modules");

const tokenLink = within(sidebar).getByRole("link", { name: "Token" });
expect(tokenLink.getAttribute("href")).toBe(TOKEN_GLOSSARY_URL);
Expand Down Expand Up @@ -113,19 +116,8 @@ describe("docs sidebar navigation accessibility", () => {
});
expect(homeLink.getAttribute("href")).toBe("/vi");

const glossaryFolder = within(sidebar).getByRole("button", {
name: "Glossary",
});
await act(async () => {
glossaryFolder.click();
});

const modulesFolder = within(sidebar).getByRole("button", {
name: "Modules",
});
await act(async () => {
modulesFolder.click();
});
await ensureSidebarFolderExpanded(sidebar, "Glossary");
await ensureSidebarFolderExpanded(sidebar, "Modules");

const tokenLink = within(sidebar).getByRole("link", { name: "Token" });
expect(tokenLink.getAttribute("href")).toBe("/vi/docs/glossary/token");
Expand Down
5 changes: 4 additions & 1 deletion src/tests/a11y/primary-navigation.a11y.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,13 @@ describe("primary navigation accessibility smoke", () => {
const panel = document.getElementById(panelId ?? "");
expect(panel).toBeTruthy();
expect(panel?.getAttribute("role")).toBe("dialog");
const primaryNav = within(panel as HTMLElement).getByRole("navigation", {
name: "Primary",
});

const expectedItems = getPrimaryNavItems(context.messages);
for (const item of expectedItems) {
const link = within(panel as HTMLElement).getByRole("link", {
const link = within(primaryNav).getByRole("link", {
name: item.label,
});
expect(link.getAttribute("href")).toBe(item.href);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
readBuiltAppServerHtml,
} from "@/lib/build/built-app-html-test-utils";
import { PHASE_1_GROUPED_QUERY_ATTENTION_MODULE_URL } from "@/lib/content/phase-1-published-resources";
import { extractNdPageHtml } from "@/lib/navigation/docs-page-footer-contract";
import { stripHtmlScripts } from "@/lib/navigation/docs-sidebar-contract";
import { shouldRunBuiltHtmlConvergenceTests } from "@/lib/verify/server-lifecycle";

Expand Down Expand Up @@ -38,11 +39,12 @@ describe("Phase 1 attention tag landing built-app HTML", () => {
}

const visibleHtml = stripHtmlScripts(html);
const gqaLinkCount = visibleHtml.split(GQA_HREF).length - 1;
const ndPageHtml = extractNdPageHtml(visibleHtml);
const gqaLinkCount = ndPageHtml.split(GQA_HREF).length - 1;

expect(gqaLinkCount).toBe(1);
expect(visibleHtml).toContain("Grouped-Query Attention");
expect(visibleHtml).toContain('href="/search?tag=attention"');
expect(visibleHtml).not.toContain("lorem");
expect(ndPageHtml).toContain("Grouped-Query Attention");
expect(ndPageHtml).toContain('href="/search?tag=attention"');
expect(ndPageHtml).not.toContain("lorem");
});
});
16 changes: 13 additions & 3 deletions src/tests/search/search-api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@
const SAMPLE_URL = SAMPLE_MODULE_URL;
const TOKEN_URL = TOKEN_GLOSSARY_URL;

function createStaticClientTestUrl(label: string): string {
return `${TEST_DOCS_SEARCH_URL}?static-client=${label}&test-run=${crypto.randomUUID()}`;
}

describe("Phase 1 /api/search regression", () => {
for (const assertion of PHASE_1_SEARCH_ASSERTIONS) {
test(assertion.label, async () => {
Expand Down Expand Up @@ -325,7 +329,9 @@
test("orama static client returns grouped-query attention for GQA", async () => {
globalThis.fetch = createDocsSearchRouteFetch();

const client = oramaStaticClient({ from: TEST_DOCS_SEARCH_URL });
const client = oramaStaticClient({
from: createStaticClientTestUrl("gqa"),
});
const results = await client.search("GQA");

expect(results.length).toBeGreaterThan(0);
Expand All @@ -335,17 +341,21 @@
test("orama static client returns non-empty attention results before app-level reranking", async () => {
globalThis.fetch = createDocsSearchRouteFetch();

const client = oramaStaticClient({ from: TEST_DOCS_SEARCH_URL });
const client = oramaStaticClient({
from: createStaticClientTestUrl("attention"),
});
const results = await client.search("attention");

expect(results.length).toBeGreaterThan(0);
expect(resultsIncludeUrl(results, PHASE_1_ATTENTION_MODULE_URL)).toBe(true);

Check failure on line 350 in src/tests/search/search-api.test.ts

View workflow job for this annotation

GitHub Actions / test

error: expect(received).toBe(expected)

Expected: true Received: false at <anonymous> (/home/runner/work/ai-model-reference/ai-model-reference/src/tests/search/search-api.test.ts:350:70)
});

test("orama static client includes grouped-query attention for KV cache", async () => {
globalThis.fetch = createDocsSearchRouteFetch();

const client = oramaStaticClient({ from: TEST_DOCS_SEARCH_URL });
const client = oramaStaticClient({
from: createStaticClientTestUrl("kv-cache"),
});
const results = await client.search("KV cache");

expect(results.length).toBeGreaterThan(0);
Expand Down
Loading