From baf285a973193ab31176888f085adaa9b0f3418e Mon Sep 17 00:00:00 2001 From: aabdi Date: Thu, 18 Jun 2026 08:52:01 +0700 Subject: [PATCH 1/5] feat: [ffn-pages-from-phase-3-001] - [Publish the standard FFN page] --- src/content/docs/glossary/meta.json | 12 -- .../glossary/standard-ffn/messages/en.json | 12 +- .../docs/glossary/standard-ffn/page.mdx | 4 +- .../concepts/feed-forward-network.json | 10 +- .../registry/concepts/standard-ffn.json | 2 +- ...ontent-reconciliation-browse-index.test.ts | 106 +++++++++- ...t-reconciliation-foundational-tags.test.ts | 190 +++++++++++++++++- ...ontent-reconciliation-single-title.test.ts | 79 +++----- .../feed-forward-network-glossary.test.ts | 46 ++++- .../glossary-architecture-index.test.ts | 171 ++++------------ .../glossary-opening-convergence.test.tsx | 2 +- ...ssary-shell-description-auto-link.test.tsx | 132 +++--------- src/lib/content/registry-runtime.test.ts | 13 +- src/lib/content/registry-runtime.ts | 44 +--- src/lib/content/standard-ffn-glossary.test.ts | 30 +-- src/lib/source.test.ts | 1 + src/tests/content/architecture-index.test.ts | 28 +-- src/tests/content/glossary-index.test.ts | 71 ++----- src/tests/search/orama-index.test.ts | 63 +----- 19 files changed, 488 insertions(+), 528 deletions(-) diff --git a/src/content/docs/glossary/meta.json b/src/content/docs/glossary/meta.json index 6579c6a2..6313c5b7 100644 --- a/src/content/docs/glossary/meta.json +++ b/src/content/docs/glossary/meta.json @@ -21,27 +21,19 @@ "[ALiBi](/docs/glossary/alibi)", "[Context window](/docs/glossary/context-window)", "[Decoder](/docs/glossary/decoder)", - "[Decode](/docs/glossary/decode)", "[Encoder](/docs/glossary/encoder)", "[Encoder-Decoder](/docs/glossary/encoder-decoder)", "[Feed-forward network](/docs/glossary/feed-forward-network)", - "[Batch norm](/docs/glossary/batch-norm)", - "[Group norm](/docs/glossary/group-norm)", "[Hidden Size](/docs/glossary/hidden-size)", - "[KV cache](/docs/glossary/kv-cache)", "[Layer norm](/docs/glossary/layer-norm)", "[LeakyReLU](/docs/glossary/leaky-relu)", "[Mixture of experts](/docs/glossary/mixture-of-experts)", "[Normalization](/docs/glossary/normalization)", - "[Prefill](/docs/glossary/prefill)", - "[Prefill/decode split](/docs/glossary/prefill-decode-split)", "[Perplexity](/docs/glossary/perplexity)", - "[QK norm](/docs/glossary/qk-norm)", "[ReLU](/docs/glossary/relu)", "[RoPE](/docs/glossary/rope)", "[RMSNorm](/docs/glossary/rmsnorm)", "[Residual connection](/docs/glossary/residual-connection)", - "[Skip connection](/docs/glossary/skip-connection)", "[SiLU](/docs/glossary/silu)", "[Standard FFN](/docs/glossary/standard-ffn)", "[SwiGLU](/docs/glossary/swiglu)", @@ -69,10 +61,6 @@ "[Vector](/docs/glossary/vector)", "---Generation And Diffusion---", "[Autoregressive Generation](/docs/glossary/autoregressive-generation)", - "[Greedy Decoding](/docs/glossary/greedy-decoding)", - "[Sampling Overview](/docs/glossary/sampling-overview)", - "[Top-K Sampling](/docs/glossary/top-k-sampling)", - "[Top-P Sampling](/docs/glossary/top-p-sampling)", "[Conditioning](/docs/glossary/conditioning)", "[Denoising Generation](/docs/glossary/denoising-generation)", "[Diffusion Model](/docs/glossary/diffusion-model)" diff --git a/src/content/docs/glossary/standard-ffn/messages/en.json b/src/content/docs/glossary/standard-ffn/messages/en.json index 26739cb7..dbffbf0d 100644 --- a/src/content/docs/glossary/standard-ffn/messages/en.json +++ b/src/content/docs/glossary/standard-ffn/messages/en.json @@ -1,22 +1,22 @@ { "title": "Standard FFN", - "description": "The default dense transformer MLP that expands, activates, and projects each token state after attention.", + "description": "The default dense MLP inside a transformer block, where every token passes through the same expand, activate, and project path after attention.", "sections": { "whatItIs": { "title": "What It Is", - "body": "A standard FFN is the default dense feed-forward block used in most transformer layers. After attention updates a token's hidden state, the standard FFN sends that vector through one wide linear layer, applies a pointwise activation, and projects it back to the model width. Every token position uses the same weights, and every token goes through the same dense path." + "body": "A standard FFN is the plain dense feed-forward block used in many transformer layers. After attention updates each token, the block sends that token's hidden vector through one larger projection, an activation such as ReLU or GELU, and one projection back to model width. Every token position runs the same weights, so the block changes features within a token rather than mixing information across tokens." }, "whyItMatters": { "title": "Why It Matters", - "body": "The broader feed-forward-network idea includes several designs that live in the same block slot. Standard FFN names the baseline most readers see in transformer diagrams and papers: expand, activate, project. Once you know that baseline, it becomes easier to notice when a paper swaps in a gated form such as SwiGLU or a sparse replacement such as mixture of experts." + "body": "This is the baseline block that later FFN variants modify. If a paper says it uses a dense MLP, a plain FFN, or the default transformer feed-forward block, it usually means this pattern. Knowing the baseline makes it easier to spot what changes when a model swaps in a routed mixture-of-experts layer or a gated design such as SwiGLU." }, "simpleExample": { "title": "Simple Example", - "body": "Suppose a transformer uses hidden size 4096 and FFN width 16384. A token vector leaves attention, multiplies by a 4096-to-16384 matrix, passes through an activation such as ReLU, GELU, or SiLU, then multiplies by a 16384-to-4096 matrix before returning to the residual stream. The path is dense because every hidden unit in the wide layer participates for every token." + "body": "Picture one decoder block. Attention lets the token for \"bank\" read nearby words and decide whether the sentence is about finance or a river. The standard FFN then refines only that token's updated vector: expand it to a wider hidden space, apply the activation, and project it back down before the residual stream continues to the next block." }, "commonConfusions": { "title": "Common Confusions", - "body": "Standard FFN is not the name for every feed-forward design. It is one common member of the larger FFN family. It also is not mixture of experts: MoE keeps the same transformer slot but routes each token through only a few experts instead of one dense MLP. The activation inside the block, such as ReLU, is only one step inside the standard FFN rather than the whole component." + "body": "Standard FFN is narrower than the broad feed-forward-network concept page: that broader page explains the transformer slot, while this page names the default dense version of that slot. It is also not a mixture-of-experts layer, because MoE routes tokens through a few expert MLPs instead of one shared dense path. Finally, changing the activation inside the block does not move the block elsewhere in the transformer; ReLU, SiLU, and gated variants still sit after attention in the same slot." }, "related": { "title": "Related Concepts And Modules" @@ -28,5 +28,5 @@ "title": "References" } }, - "openingSummary": "A standard FFN is the default dense MLP after attention in a transformer block, using an expand-activate-project path so each token gets the same per-position transformation." + "openingSummary": "A standard FFN is the default dense MLP that runs after attention in each transformer block, giving every token the same expand, activate, and project path before the model moves on." } diff --git a/src/content/docs/glossary/standard-ffn/page.mdx b/src/content/docs/glossary/standard-ffn/page.mdx index ef6e4e28..c34970c6 100644 --- a/src/content/docs/glossary/standard-ffn/page.mdx +++ b/src/content/docs/glossary/standard-ffn/page.mdx @@ -1,6 +1,6 @@ --- title: Standard FFN -description: The default dense transformer MLP that expands, activates, and projects each token state after attention. +description: The default dense MLP inside a transformer block, where every token passes through the same expand, activate, and project path after attention. kind: "glossary" registryId: "concept.standard-ffn" messageNamespace: "local" @@ -9,9 +9,9 @@ status: "published" tags: - foundations aliases: + - "standard FFN" - "dense FFN" - "dense MLP block" - - "standard feed-forward network" updatedAt: "2026-06-18" --- diff --git a/src/content/registry/concepts/feed-forward-network.json b/src/content/registry/concepts/feed-forward-network.json index 3b78411c..86785636 100644 --- a/src/content/registry/concepts/feed-forward-network.json +++ b/src/content/registry/concepts/feed-forward-network.json @@ -8,14 +8,18 @@ "tags": ["foundations"], "relatedIds": [ "concept.transformer-architecture", + "concept.activation", "concept.standard-ffn", - "concept.mixture-of-experts", - "concept.activation" + "concept.relu", + "concept.leaky-relu", + "concept.silu", + "concept.swiglu", + "concept.mixture-of-experts" ], "citationIds": [], "status": "published", "createdAt": "2026-06-08T00:00:00.000Z", - "updatedAt": "2026-06-18T00:00:00.000Z", + "updatedAt": "2026-06-08T00:00:00.000Z", "conceptType": "general", "prerequisiteIds": [], "explainsIds": [] diff --git a/src/content/registry/concepts/standard-ffn.json b/src/content/registry/concepts/standard-ffn.json index ecf49c0c..7890cd74 100644 --- a/src/content/registry/concepts/standard-ffn.json +++ b/src/content/registry/concepts/standard-ffn.json @@ -4,7 +4,7 @@ "kind": "concept", "defaultTitleKey": "title", "defaultSummaryKey": "description", - "aliases": ["dense FFN", "dense MLP block", "standard feed-forward network"], + "aliases": ["standard FFN", "dense FFN", "dense MLP block"], "tags": ["foundations"], "relatedIds": [ "concept.feed-forward-network", diff --git a/src/lib/content/content-reconciliation-browse-index.test.ts b/src/lib/content/content-reconciliation-browse-index.test.ts index 75a56aea..17ea5239 100644 --- a/src/lib/content/content-reconciliation-browse-index.test.ts +++ b/src/lib/content/content-reconciliation-browse-index.test.ts @@ -2,23 +2,108 @@ import { describe, expect, test } from "bun:test"; import { renderToStaticMarkup } from "react-dom/server"; import ArchitectureIndexPage from "@/app/(site)/docs/architecture/page"; import GlossaryIndexPage from "@/app/(site)/docs/glossary/page"; +import { loadPublishedArchitectureEntries } from "@/lib/content/architecture"; +import { loadPublishedGlossaryEntries } from "@/lib/content/glossary"; + +/** Batch 017 glossary pages reconciled in Phase 2/3 (see prd.md). */ +const BATCH_017_GLOSSARY_URLS = [ + "/docs/glossary/transformer", + "/docs/glossary/diffusion-model", + "/docs/glossary/multimodal-model", + "/docs/glossary/world-model", + "/docs/glossary/feed-forward-network", + "/docs/glossary/mixture-of-experts", + "/docs/glossary/normalization", + "/docs/glossary/layer-norm", + "/docs/glossary/rmsnorm", + "/docs/glossary/residual-connection", + "/docs/glossary/rope", + "/docs/glossary/alibi", + "/docs/glossary/context-window", + "/docs/glossary/standard-ffn", + "/docs/glossary/relu", + "/docs/glossary/leaky-relu", + "/docs/glossary/silu", + "/docs/glossary/swiglu", +] as const; + +/** Batch 017 architecture-related concept pages reconciled in Phase 2/3. */ +const BATCH_017_ARCHITECTURE_URLS = [ + "/docs/concepts/transformer-architecture", + "/docs/concepts/positional-encodings", + "/docs/concepts/context-extension", + "/docs/concepts/why-long-context-is-hard", + "/docs/glossary/transformer", + "/docs/glossary/diffusion-model", + "/docs/glossary/multimodal-model", + "/docs/glossary/world-model", + "/docs/glossary/feed-forward-network", + "/docs/glossary/mixture-of-experts", + "/docs/glossary/normalization", + "/docs/glossary/layer-norm", + "/docs/glossary/rmsnorm", + "/docs/glossary/residual-connection", + "/docs/glossary/rope", + "/docs/glossary/alibi", + "/docs/glossary/context-window", + "/docs/glossary/standard-ffn", + "/docs/glossary/relu", + "/docs/glossary/leaky-relu", + "/docs/glossary/silu", + "/docs/glossary/swiglu", +] as const; describe("Phase 2/3 reconciliation browse indexes (US-004)", () => { - test("glossary and architecture index pages render FFN, norm, and residual links without list bullets", async () => { + test("glossary index lists every batch 017 glossary page sorted by localized title", async () => { + const entries = await loadPublishedGlossaryEntries("en"); + const entryByUrl = new Map(entries.map((entry) => [entry.url, entry])); + + for (const url of BATCH_017_GLOSSARY_URLS) { + const entry = entryByUrl.get(url); + expect(entry).toBeDefined(); + expect(entry?.title.length).toBeGreaterThan(0); + expect(entry?.summary.length).toBeGreaterThan(0); + } + + for (let index = 1; index < entries.length; index += 1) { + expect( + entries[index - 1].title.localeCompare(entries[index].title, "en", { + sensitivity: "base", + }), + ).toBeLessThanOrEqual(0); + } + }); + + test("architecture index lists batch 017 foundations and concept pages sorted by title", async () => { + const entries = await loadPublishedArchitectureEntries("en"); + const entryByUrl = new Map(entries.map((entry) => [entry.url, entry])); + + for (const url of BATCH_017_ARCHITECTURE_URLS) { + const entry = entryByUrl.get(url); + expect(entry).toBeDefined(); + expect(entry?.title.length).toBeGreaterThan(0); + expect(entry?.summary.length).toBeGreaterThan(0); + } + + for (let index = 1; index < entries.length; index += 1) { + expect( + entries[index - 1].title.localeCompare(entries[index].title, "en", { + sensitivity: "base", + }), + ).toBeLessThanOrEqual(0); + } + }); + + test("glossary and architecture index pages render bulletless title-plus-summary lists", async () => { const glossaryHtml = renderToStaticMarkup(await GlossaryIndexPage()); const architectureHtml = renderToStaticMarkup( await ArchitectureIndexPage(), ); for (const url of [ - "/docs/glossary/feed-forward-network", - "/docs/glossary/standard-ffn", - "/docs/glossary/mixture-of-experts", - "/docs/glossary/normalization", - "/docs/glossary/layer-norm", - "/docs/glossary/qk-norm", - "/docs/glossary/residual-connection", - "/docs/glossary/skip-connection", + "/docs/glossary/transformer", + "/docs/glossary/rope", + "/docs/glossary/context-window", ]) { expect(glossaryHtml).toContain(`href="${url}"`); } @@ -27,8 +112,7 @@ describe("Phase 2/3 reconciliation browse indexes (US-004)", () => { "/docs/concepts/transformer-architecture", "/docs/concepts/positional-encodings", "/docs/glossary/feed-forward-network", - "/docs/glossary/normalization", - "/docs/glossary/residual-connection", + "/docs/glossary/world-model", ]) { expect(architectureHtml).toContain(`href="${url}"`); } diff --git a/src/lib/content/content-reconciliation-foundational-tags.test.ts b/src/lib/content/content-reconciliation-foundational-tags.test.ts index cdcfb2dd..cfd20577 100644 --- a/src/lib/content/content-reconciliation-foundational-tags.test.ts +++ b/src/lib/content/content-reconciliation-foundational-tags.test.ts @@ -2,6 +2,192 @@ import { describe, expect, test } from "bun:test"; import { renderToStaticMarkup } from "react-dom/server"; import TagLandingPage from "@/app/(site)/tags/[slug]/page"; import TagsIndexPage from "@/app/(site)/tags/page"; +import { loadPublishedDocsPages } from "@/lib/content/pages"; +import { loadRegistry } from "@/lib/content/registry"; +import { + loadTagLandingContext, + loadTagResourceEntries, + loadTagResourceGroups, +} from "@/lib/content/tag-resources"; +import { loadPublishedTagIndexEntries } from "@/lib/content/tags"; +import { loadUiMessages } from "@/lib/content/ui-messages"; + +const FOUNDATIONAL_TAG_SLUGS = [ + "foundations", + "taxonomy", + "model-family", + "token-to-probability-chain", +] as const; + +/** Batch 017 pages expected on each foundational tag landing (see prd.md). */ +const BATCH_017_TAG_URLS = { + foundations: [ + "/docs/concepts/context-extension", + "/docs/concepts/positional-encodings", + "/docs/concepts/transformer-architecture", + "/docs/concepts/why-long-context-is-hard", + "/docs/glossary/alibi", + "/docs/glossary/context-window", + "/docs/glossary/feed-forward-network", + "/docs/glossary/layer-norm", + "/docs/glossary/leaky-relu", + "/docs/glossary/mixture-of-experts", + "/docs/glossary/normalization", + "/docs/glossary/relu", + "/docs/glossary/residual-connection", + "/docs/glossary/rmsnorm", + "/docs/glossary/silu", + "/docs/glossary/rope", + "/docs/glossary/standard-ffn", + "/docs/glossary/swiglu", + ], + taxonomy: [ + "/docs/concepts/transformer-architecture", + "/docs/glossary/diffusion-model", + "/docs/glossary/multimodal-model", + "/docs/glossary/transformer", + "/docs/glossary/world-model", + ], + "model-family": [ + "/docs/glossary/diffusion-model", + "/docs/glossary/multimodal-model", + "/docs/glossary/transformer", + "/docs/glossary/world-model", + ], + "token-to-probability-chain": [], +} as const; + +function pageMatchesTag( + page: Awaited>[number], + tagSlug: string, + indexes: Awaited>, +): boolean { + if (page.frontmatter.tags.includes(tagSlug)) { + return true; + } + const record = indexes.byId.get(page.frontmatter.registryId); + return record?.tags.includes(tagSlug) ?? false; +} + +describe("Phase 2/3 reconciliation foundational tags (US-006)", () => { + test("foundational tag records expose localized title and summary", async () => { + const messages = await loadUiMessages(); + + const foundations = await loadTagLandingContext( + "foundations", + messages, + "en", + ); + expect(foundations?.title).toBe("Foundations"); + expect(foundations?.summary.length).toBeGreaterThan(0); + expect(foundations?.categoryLabel).toBe("Architecture"); + + const taxonomy = await loadTagLandingContext("taxonomy", messages, "en"); + expect(taxonomy?.title).toBe("Taxonomy"); + expect(taxonomy?.summary.length).toBeGreaterThan(0); + + const modelFamily = await loadTagLandingContext( + "model-family", + messages, + "en", + ); + expect(modelFamily?.title).toBe("Model family"); + expect(modelFamily?.summary).toContain( + "Published model-family glossary pages", + ); + expect(modelFamily?.categoryLabel).toBe("Model family"); + + const tokenChain = await loadTagLandingContext( + "token-to-probability-chain", + messages, + "en", + ); + expect(tokenChain?.title).toBe("Token-to-probability chain"); + expect(tokenChain?.summary.length).toBeGreaterThan(0); + }); + + test("foundational tag landings include every batch 017 associated page", async () => { + const messages = await loadUiMessages(); + + for (const tagSlug of FOUNDATIONAL_TAG_SLUGS) { + const entries = await loadTagResourceEntries(tagSlug, "en"); + const urls = new Set(entries.map((entry) => entry.url)); + + for (const url of BATCH_017_TAG_URLS[tagSlug]) { + expect(urls).toContain(url); + } + } + + const modelFamilyGroups = await loadTagResourceGroups( + "model-family", + messages, + "en", + ); + expect(modelFamilyGroups).toHaveLength(1); + expect(modelFamilyGroups[0]?.kind).toBe("glossary"); + expect(modelFamilyGroups[0]?.kindLabel).toBe("Glossary"); + expect( + modelFamilyGroups[0]?.resources.map((resource) => resource.url), + ).toEqual([ + "/docs/glossary/diffusion-model", + "/docs/glossary/multimodal-model", + "/docs/glossary/transformer", + "/docs/glossary/world-model", + ]); + }); + + test("foundational tag landings omit empty kind groups and sort resources by title", async () => { + const messages = await loadUiMessages(); + + for (const tagSlug of FOUNDATIONAL_TAG_SLUGS) { + const groups = await loadTagResourceGroups(tagSlug, messages, "en"); + expect(groups.every((group) => group.resources.length > 0)).toBe(true); + + for (const group of groups) { + const titles = group.resources.map((resource) => resource.title); + const sorted = [...titles].sort((a, b) => + a.localeCompare(b, "en", { sensitivity: "base" }), + ); + expect(titles).toEqual(sorted); + } + } + }); + + test("published pages with foundational tags resolve through registry or frontmatter", async () => { + const pages = await loadPublishedDocsPages("en"); + const indexes = await loadRegistry(); + + for (const tagSlug of FOUNDATIONAL_TAG_SLUGS) { + const taggedPages = pages.filter((page) => + pageMatchesTag(page, tagSlug, indexes), + ); + const entryUrls = new Set( + (await loadTagResourceEntries(tagSlug, "en")).map((entry) => entry.url), + ); + + for (const page of taggedPages) { + expect(entryUrls).toContain(page.url); + } + } + }); + + test("tags index links foundational tags with accurate descriptions", async () => { + const messages = await loadUiMessages(); + const entries = await loadPublishedTagIndexEntries(messages, "en"); + + for (const slug of FOUNDATIONAL_TAG_SLUGS) { + const entry = entries.find((candidate) => candidate.slug === slug); + expect(entry).toBeDefined(); + expect(entry?.url).toBe(`/tags/${slug}`); + expect(entry?.summary.length).toBeGreaterThan(0); + } + + const modelFamily = entries.find((entry) => entry.slug === "model-family"); + expect(modelFamily?.summary).toContain( + "Published model-family glossary pages", + ); + }); +}); describe("Phase 2/3 reconciliation foundational tag page render (US-006)", () => { test("foundations landing lists batch 017 resources grouped by kind", async () => { @@ -15,10 +201,6 @@ describe("Phase 2/3 reconciliation foundational tag page render (US-006)", () => expect(html).toContain("Concept"); expect(html).toContain('href="/docs/glossary/rope"'); expect(html).toContain('href="/docs/glossary/context-window"'); - expect(html).toContain('href="/docs/glossary/feed-forward-network"'); - expect(html).toContain('href="/docs/glossary/standard-ffn"'); - expect(html).toContain('href="/docs/glossary/normalization"'); - expect(html).toContain('href="/docs/glossary/skip-connection"'); expect(html).toContain('href="/docs/concepts/transformer-architecture"'); expect(html).toContain('href="/search?tag=foundations"'); expect(html).toContain("list-none"); diff --git a/src/lib/content/content-reconciliation-single-title.test.ts b/src/lib/content/content-reconciliation-single-title.test.ts index 351acccd..42ccac60 100644 --- a/src/lib/content/content-reconciliation-single-title.test.ts +++ b/src/lib/content/content-reconciliation-single-title.test.ts @@ -29,26 +29,19 @@ const BATCH_017_DOCS_URLS = [ "/docs/modules/linear-attention", "/docs/concepts/transformer-architecture", "/docs/glossary/feed-forward-network", - "/docs/glossary/batch-norm", - "/docs/glossary/group-norm", - "/docs/glossary/standard-ffn", "/docs/glossary/mixture-of-experts", - "/docs/glossary/relu", - "/docs/glossary/leaky-relu", - "/docs/glossary/silu", - "/docs/glossary/swiglu", "/docs/glossary/normalization", - "/docs/glossary/qk-norm", "/docs/glossary/layer-norm", "/docs/glossary/rmsnorm", "/docs/glossary/residual-connection", - "/docs/glossary/skip-connection", "/docs/concepts/positional-encodings", "/docs/glossary/rope", "/docs/glossary/alibi", "/docs/glossary/context-window", "/docs/concepts/context-extension", "/docs/concepts/why-long-context-is-hard", + "/docs/glossary/silu", + "/docs/glossary/swiglu", ] as const; const SPOT_CHECK_URLS = [ @@ -58,11 +51,6 @@ const SPOT_CHECK_URLS = [ "/docs/glossary/context-window", ] as const; -const BATCH_017_DOCS_URL_GROUPS = [ - BATCH_017_DOCS_URLS.slice(0, 12), - BATCH_017_DOCS_URLS.slice(12), -] as const; - function parseDocsUrl(url: string): { section: "concepts" | "glossary" | "modules"; slug: string; @@ -101,28 +89,6 @@ function extractArticleHtml(html: string, registryId: string): string { return extractModuleArticleHtml(html, registryId); } -async function expectSingleShellOwnedPrimaryTitle(url: string): Promise { - const { section, slug } = parseDocsUrl(url); - const loadedPage = await loadLocalDocsPage({ section, slug }); - const html = renderReconciledDocsShell(section, loadedPage); - const articleHtml = extractArticleHtml( - html, - loadedPage.frontmatter.registryId, - ); - - expect(articleHtml.length).toBeGreaterThan(0); - expect(countH1BlocksContaining(html, loadedPage.messages.title)).toBe(1); - expectGlossaryBodyOmitsTitleHeading(articleHtml, loadedPage.messages.title); - expectGlossaryBodyOmitsShellDescription( - articleHtml, - loadedPage.messages.description, - ); - - if (section === "glossary" || section === "concepts") { - expectGlossaryOmitsOpeningSummary(html); - } -} - describe("Phase 2/3 reconciliation single primary title (US-005)", () => { if (process.env[VERIFY_COVERAGE_SUBPROCESS_ENV] === "1") { test("skips shell title convergence during coverage subprocess rerun", () => {}); @@ -147,17 +113,38 @@ describe("Phase 2/3 reconciliation single primary title (US-005)", () => { } }); - for (const [index, urls] of BATCH_017_DOCS_URL_GROUPS.entries()) { - test( - `batch 017 title convergence group ${index + 1} renders exactly one shell-owned primary title`, - async () => { - for (const url of urls) { - await expectSingleShellOwnedPrimaryTitle(url); + test( + "every batch 017 page renders exactly one shell-owned primary title", + async () => { + for (const url of BATCH_017_DOCS_URLS) { + const { section, slug } = parseDocsUrl(url); + const loadedPage = await loadLocalDocsPage({ section, slug }); + const html = renderReconciledDocsShell(section, loadedPage); + const articleHtml = extractArticleHtml( + html, + loadedPage.frontmatter.registryId, + ); + + expect(articleHtml.length).toBeGreaterThan(0); + expect(countH1BlocksContaining(html, loadedPage.messages.title)).toBe( + 1, + ); + expectGlossaryBodyOmitsTitleHeading( + articleHtml, + loadedPage.messages.title, + ); + expectGlossaryBodyOmitsShellDescription( + articleHtml, + loadedPage.messages.description, + ); + + if (section === "glossary" || section === "concepts") { + expectGlossaryOmitsOpeningSummary(html); } - }, - { timeout: 15_000 }, - ); - } + } + }, + { timeout: 10_000 }, + ); test("spot-check pages keep glossary or module shell title patterns", async () => { for (const url of SPOT_CHECK_URLS) { diff --git a/src/lib/content/feed-forward-network-glossary.test.ts b/src/lib/content/feed-forward-network-glossary.test.ts index e611dd34..2122c22a 100644 --- a/src/lib/content/feed-forward-network-glossary.test.ts +++ b/src/lib/content/feed-forward-network-glossary.test.ts @@ -36,16 +36,20 @@ describe("Phase 3 feed-forward network glossary page (US-002)", () => { expect(record?.tags).toEqual(["foundations"]); expect(record?.relatedIds).toEqual([ "concept.transformer-architecture", + "concept.activation", "concept.standard-ffn", + "concept.relu", + "concept.leaky-relu", + "concept.silu", + "concept.swiglu", "concept.mixture-of-experts", - "concept.activation", ]); expect( PUBLISHED_DOCS_REGISTRY_IDS.has("concept.feed-forward-network"), ).toBe(true); }); - test("curated related links transformer architecture, standard FFN, mixture of experts, and activation", () => { + test("curated related links connect the broad FFN overview to architecture and nearby family variants", () => { const source = getConceptById("concept.feed-forward-network"); if (!source) { throw new Error("expected concept.feed-forward-network in registry"); @@ -69,17 +73,35 @@ describe("Phase 3 feed-forward network glossary page (US-002)", () => { expect(standardFfn?.href).toBe("/docs/glossary/standard-ffn"); expect(standardFfn?.isPlanned).toBe(false); - const moe = items.find( - (item) => item.registryId === "concept.mixture-of-experts", - ); - expect(moe?.href).toBe("/docs/glossary/mixture-of-experts"); - expect(moe?.isPlanned).toBe(false); - const activation = items.find( (item) => item.registryId === "concept.activation", ); expect(activation?.href).toBe("/docs/glossary/activation"); expect(activation?.isPlanned).toBe(false); + + const relu = items.find((item) => item.registryId === "concept.relu"); + expect(relu?.href).toBe("/docs/glossary/relu"); + expect(relu?.isPlanned).toBe(false); + + const leakyRelu = items.find( + (item) => item.registryId === "concept.leaky-relu", + ); + expect(leakyRelu?.href).toBe("/docs/glossary/leaky-relu"); + expect(leakyRelu?.isPlanned).toBe(false); + + const silu = items.find((item) => item.registryId === "concept.silu"); + expect(silu?.href).toBe("/docs/glossary/silu"); + expect(silu?.isPlanned).toBe(false); + + const swiglu = items.find((item) => item.registryId === "concept.swiglu"); + expect(swiglu?.href).toBe("/docs/glossary/swiglu"); + expect(swiglu?.isPlanned).toBe(false); + + const moe = items.find( + (item) => item.registryId === "concept.mixture-of-experts", + ); + expect(moe?.href).toBe("/docs/glossary/mixture-of-experts"); + expect(moe?.isPlanned).toBe(false); }); test("messages describe per-position FFN role after attention", () => { @@ -100,7 +122,7 @@ describe("Phase 3 feed-forward network glossary page (US-002)", () => { ); }); - test("page renders glossary sections, tag pills, and FFN-family related links", async () => { + test("page renders glossary sections, tag pills, and FFN family related links", async () => { const page = await loadGlossaryPage("feed-forward-network"); expect(page.frontmatter.kind).toBe("glossary"); @@ -123,9 +145,13 @@ describe("Phase 3 feed-forward network glossary page (US-002)", () => { expect(html).toContain("Why It Matters"); expectHtmlToContainProse(html, "two-layer perceptron"); expect(html).toContain('href="/docs/concepts/transformer-architecture"'); + expect(html).toContain('href="/docs/glossary/activation"'); expect(html).toContain('href="/docs/glossary/standard-ffn"'); + expect(html).toContain('href="/docs/glossary/relu"'); + expect(html).toContain('href="/docs/glossary/leaky-relu"'); + expect(html).toContain('href="/docs/glossary/silu"'); + expect(html).toContain('href="/docs/glossary/swiglu"'); expect(html).toContain('href="/docs/glossary/mixture-of-experts"'); - expect(html).toContain('href="/docs/glossary/activation"'); expect(html).toContain('href="/tags/foundations"'); expect(html).toContain('data-testid="tag-pill-list"'); expect(html).toContain('data-testid="curated-related-docs"'); diff --git a/src/lib/content/glossary-architecture-index.test.ts b/src/lib/content/glossary-architecture-index.test.ts index fa0ddfac..ab05dd0b 100644 --- a/src/lib/content/glossary-architecture-index.test.ts +++ b/src/lib/content/glossary-architecture-index.test.ts @@ -24,21 +24,6 @@ const TAXONOMY_GLOSSARY_SLUGS = [ "latent-space", ] as const; -const FFN_ACTIVATION_GLOSSARY_SLUGS = [ - "feed-forward-network", - "batch-norm", - "group-norm", - "standard-ffn", - "mixture-of-experts", - "relu", - "leaky-relu", - "silu", - "swiglu", - "qk-norm", - "residual-connection", - "skip-connection", -] as const; - const EXPECTED_GLOSSARY_TITLES: Record = { model: "Model", architecture: "Architecture", @@ -52,18 +37,6 @@ const EXPECTED_GLOSSARY_TITLES: Record = { patch: "Patch", latent: "Latent", "latent-space": "Latent Space", - "feed-forward-network": "Feed-forward network", - "batch-norm": "Batch norm", - "group-norm": "Group norm", - "standard-ffn": "Standard FFN", - "mixture-of-experts": "Mixture of experts", - relu: "ReLU", - "leaky-relu": "LeakyReLU", - silu: "SiLU", - swiglu: "SwiGLU", - "qk-norm": "QK norm", - "residual-connection": "Residual connection", - "skip-connection": "Skip connection", token: "Token", embedding: "Embedding", tensor: "Tensor", @@ -72,21 +45,18 @@ const EXPECTED_GLOSSARY_TITLES: Record = { softmax: "Softmax", entropy: "Entropy", temperature: "Temperature", - "sampling-overview": "Sampling Overview", - "greedy-decoding": "Greedy Decoding", - "top-k-sampling": "Top-K Sampling", - "top-p-sampling": "Top-P Sampling", parameter: "Parameter", activation: "Activation", + relu: "ReLU", + "leaky-relu": "LeakyReLU", + silu: "SiLU", "computational-graph": "Computational Graph", gradient: "Gradient", backpropagation: "Backpropagation", "loss-function": "Loss Function", "optimizer-state": "Optimizer State", - "kv-cache": "KV cache", - decode: "Decode", - prefill: "Prefill", - "prefill-decode-split": "Prefill/decode split", + "standard-ffn": "Standard FFN", + swiglu: "SwiGLU", }; const CHAIN_GLOSSARY_SLUGS = [ @@ -97,20 +67,19 @@ const CHAIN_GLOSSARY_SLUGS = [ "softmax", "entropy", "temperature", - "sampling-overview", - "greedy-decoding", - "top-k-sampling", - "top-p-sampling", "parameter", "activation", + "relu", + "leaky-relu", + "silu", "computational-graph", "gradient", "backpropagation", "loss-function", "optimizer-state", ] as const; -const PUBLISHED_GLOSSARY_ENTRY_COUNT = 71; -const PUBLISHED_ARCHITECTURE_ENTRY_COUNT = 60; +const PUBLISHED_GLOSSARY_ENTRY_COUNT = 59; +const PUBLISHED_ARCHITECTURE_ENTRY_COUNT = 52; const GLOSSARY_SEPARATOR_TITLES = [ "Model Taxonomy", "Sequence And Attention", @@ -134,7 +103,7 @@ function collectPageUrls(nodes: Node[]): string[] { } describe("Phase 2 glossary and architecture index navigation (US-007)", () => { - test("glossary meta.json lists token, prefill, and all taxonomy pages", async () => { + test("glossary meta.json lists token and all nine taxonomy pages", async () => { const metaPath = join(process.cwd(), "src/content/docs/glossary/meta.json"); const meta = JSON.parse(await readFile(metaPath, "utf8")) as { pages: string[]; @@ -149,16 +118,9 @@ describe("Phase 2 glossary and architecture index navigation (US-007)", () => { ); for (const slug of [ ...TAXONOMY_GLOSSARY_SLUGS, - ...FFN_ACTIVATION_GLOSSARY_SLUGS, ...CHAIN_GLOSSARY_SLUGS, - "kv-cache", - "decode", - "prefill", - "prefill-decode-split", - "sampling-overview", - "greedy-decoding", - "top-k-sampling", - "top-p-sampling", + "standard-ffn", + "swiglu", "token", ] as const) { const title = EXPECTED_GLOSSARY_TITLES[slug]; @@ -183,16 +145,9 @@ describe("Phase 2 glossary and architecture index navigation (US-007)", () => { const glossaryUrls = collectPageUrls(glossaryFolder.children); for (const slug of [ ...TAXONOMY_GLOSSARY_SLUGS, - ...FFN_ACTIVATION_GLOSSARY_SLUGS, ...CHAIN_GLOSSARY_SLUGS, - "kv-cache", - "decode", - "prefill", - "prefill-decode-split", - "sampling-overview", - "greedy-decoding", - "top-k-sampling", - "top-p-sampling", + "standard-ffn", + "swiglu", "token", ] as const) { expect(glossaryUrls).toContain(`/docs/glossary/${slug}`); @@ -217,30 +172,13 @@ describe("Phase 2 glossary and architecture index navigation (US-007)", () => { const token = entries.find((item) => item.url === "/docs/glossary/token"); expect(token?.title).toBe("Token"); - const kvCache = entries.find( - (item) => item.url === "/docs/glossary/kv-cache", + const standardFfn = entries.find( + (item) => item.url === "/docs/glossary/standard-ffn", ); - expect(kvCache?.title).toBe("KV cache"); + expect(standardFfn?.title).toBe("Standard FFN"); - const decode = entries.find((item) => item.url === "/docs/glossary/decode"); - expect(decode?.title).toBe("Decode"); - - const prefill = entries.find( - (item) => item.url === "/docs/glossary/prefill", - ); - expect(prefill?.title).toBe("Prefill"); - - const prefillDecodeSplit = entries.find( - (item) => item.url === "/docs/glossary/prefill-decode-split", - ); - expect(prefillDecodeSplit?.title).toBe("Prefill/decode split"); - - for (const slug of FFN_ACTIVATION_GLOSSARY_SLUGS) { - const entry = entries.find( - (item) => item.url === `/docs/glossary/${slug}`, - ); - expect(entry?.title).toBe(EXPECTED_GLOSSARY_TITLES[slug]); - } + const swiglu = entries.find((item) => item.url === "/docs/glossary/swiglu"); + expect(swiglu?.title).toBe("SwiGLU"); for (const slug of CHAIN_GLOSSARY_SLUGS) { const entry = entries.find( @@ -266,35 +204,18 @@ describe("Phase 2 glossary and architecture index navigation (US-007)", () => { expect(entry?.title).toBe(EXPECTED_GLOSSARY_TITLES[slug]); } - for (const slug of FFN_ACTIVATION_GLOSSARY_SLUGS) { - const entry = entries.find( - (item) => item.url === `/docs/glossary/${slug}`, - ); - expect(entry?.title).toBe(EXPECTED_GLOSSARY_TITLES[slug]); - } - - const token = entries.find((entry) => entry.url === "/docs/glossary/token"); - expect(token?.title).toBe("Token"); - - const kvCache = entries.find( - (entry) => entry.url === "/docs/glossary/kv-cache", + const standardFfn = entries.find( + (entry) => entry.url === "/docs/glossary/standard-ffn", ); - expect(kvCache?.title).toBe("KV cache"); + expect(standardFfn?.title).toBe("Standard FFN"); - const decode = entries.find( - (entry) => entry.url === "/docs/glossary/decode", + const swiglu = entries.find( + (entry) => entry.url === "/docs/glossary/swiglu", ); - expect(decode?.title).toBe("Decode"); + expect(swiglu?.title).toBe("SwiGLU"); - const prefill = entries.find( - (entry) => entry.url === "/docs/glossary/prefill", - ); - expect(prefill?.title).toBe("Prefill"); - - const prefillDecodeSplit = entries.find( - (entry) => entry.url === "/docs/glossary/prefill-decode-split", - ); - expect(prefillDecodeSplit?.title).toBe("Prefill/decode split"); + const token = entries.find((entry) => entry.url === "/docs/glossary/token"); + expect(token?.title).toBe("Token"); const embedding = entries.find( (entry) => entry.url === "/docs/glossary/embedding", @@ -337,34 +258,30 @@ describe("Phase 2 glossary and architecture index navigation (US-007)", () => { expect(glossaryHtml).toContain('href="/docs/glossary/parameter"'); expect(glossaryHtml).toContain("Activation"); expect(glossaryHtml).toContain('href="/docs/glossary/activation"'); + expect(glossaryHtml).toContain("ReLU"); + expect(glossaryHtml).toContain('href="/docs/glossary/relu"'); + expect(glossaryHtml).toContain("LeakyReLU"); + expect(glossaryHtml).toContain('href="/docs/glossary/leaky-relu"'); + expect(glossaryHtml).toContain("SiLU"); + expect(glossaryHtml).toContain('href="/docs/glossary/silu"'); + expect(glossaryHtml).toContain("SwiGLU"); + expect(glossaryHtml).toContain('href="/docs/glossary/swiglu"'); expect(glossaryHtml).toContain("Computational Graph"); expect(glossaryHtml).toContain('href="/docs/glossary/computational-graph"'); - expect(glossaryHtml).toContain("KV cache"); - expect(glossaryHtml).toContain('href="/docs/glossary/kv-cache"'); - expect(glossaryHtml).toContain("Decode"); - expect(glossaryHtml).toContain('href="/docs/glossary/decode"'); - expect(glossaryHtml).toContain("Prefill"); - expect(glossaryHtml).toContain('href="/docs/glossary/prefill"'); - expect(glossaryHtml).toContain("Prefill/decode split"); - expect(glossaryHtml).toContain( - 'href="/docs/glossary/prefill-decode-split"', - ); expect(architectureHtml).toContain("Activation"); expect(architectureHtml).toContain('href="/docs/glossary/activation"'); + expect(architectureHtml).toContain("ReLU"); + expect(architectureHtml).toContain('href="/docs/glossary/relu"'); + expect(architectureHtml).toContain("LeakyReLU"); + expect(architectureHtml).toContain('href="/docs/glossary/leaky-relu"'); + expect(architectureHtml).toContain("SiLU"); + expect(architectureHtml).toContain('href="/docs/glossary/silu"'); + expect(architectureHtml).toContain("SwiGLU"); + expect(architectureHtml).toContain('href="/docs/glossary/swiglu"'); expect(architectureHtml).toContain("Computational Graph"); expect(architectureHtml).toContain( 'href="/docs/glossary/computational-graph"', ); - expect(architectureHtml).toContain("KV cache"); - expect(architectureHtml).toContain('href="/docs/glossary/kv-cache"'); - expect(architectureHtml).toContain("Decode"); - expect(architectureHtml).toContain('href="/docs/glossary/decode"'); - expect(architectureHtml).toContain("Prefill"); - expect(architectureHtml).toContain('href="/docs/glossary/prefill"'); - expect(architectureHtml).toContain("Prefill/decode split"); - expect(architectureHtml).toContain( - 'href="/docs/glossary/prefill-decode-split"', - ); expect(architectureHtml).not.toContain('href="/docs/glossary/parameter"'); expect(architectureHtml).toContain("Embedding"); expect(architectureHtml).toContain('href="/docs/glossary/embedding"'); diff --git a/src/lib/content/glossary-opening-convergence.test.tsx b/src/lib/content/glossary-opening-convergence.test.tsx index dd8692d0..c45d2fd8 100644 --- a/src/lib/content/glossary-opening-convergence.test.tsx +++ b/src/lib/content/glossary-opening-convergence.test.tsx @@ -50,6 +50,6 @@ describe("glossary opening convergence", () => { expectGlossaryOmitsOpeningSummary(html); } }, - { timeout: 30_000 }, + { timeout: 20_000 }, ); }); diff --git a/src/lib/content/glossary-shell-description-auto-link.test.tsx b/src/lib/content/glossary-shell-description-auto-link.test.tsx index b3dc8a83..17e1afe4 100644 --- a/src/lib/content/glossary-shell-description-auto-link.test.tsx +++ b/src/lib/content/glossary-shell-description-auto-link.test.tsx @@ -16,16 +16,6 @@ import { } from "@/lib/content/glossary-test-helpers"; import { loadLocalDocsPage } from "@/lib/content/local-docs-page"; -function chunkValues(values: T[], size: number): T[][] { - const chunks: T[][] = []; - - for (let index = 0; index < values.length; index += size) { - chunks.push(values.slice(index, index + size)); - } - - return chunks; -} - describe("glossary shell description auto-link convergence", () => { test("glossary docs routes wire shell descriptions through DocsAutoLinkedDescription", () => { const pageRendererSource = readFileSync( @@ -55,103 +45,35 @@ describe("glossary shell description auto-link convergence", () => { expect(autoLinkedDescriptionSource).toContain("ProseAutoLinkText"); }); - for (const [chunkIndex, slugChunk] of chunkValues( - [ - "activation", - "alibi", - "alignment", - "architecture", - "autoregressive-generation", - "component", - "computational-graph", - "conditioning", - "context-window", - "decode", - "decoder", - "denoising-generation", - "diffusion-model", - "discriminative-model", - "embedding", - "emergent-behavior", - "encoder", - "encoder-decoder", - "entropy", - "feed-forward-network", - "foundation-model", - "generalization", - "generative-model", - "gradient", - "hidden-size", - "kv-cache", - "latent", - "latent-space", - "layer-norm", - "logit", - "loss-function", - "mixture-of-experts", - "modality", - "model", - "model-capacity", - "module", - "multimodal-model", - "normalization", - "optimizer-state", - "overfitting", - "parameter", - "patch", - "perplexity", - "prefill", - "prefill-decode-split", - "representation", - "residual-connection", - "rmsnorm", - "rope", - "scaling-law", - "softmax", - "temperature", - "tensor", - "token", - "transformer", - "vector", - "world-model", - ], - 20, - ).entries()) { - test( - `published glossary pages chunk ${chunkIndex + 1} renders auto-linked shell descriptions without body duplication`, - async () => { - const pageSet = new Set(slugChunk); - const pages = (await listPublishedGlossaryPages()).filter((page) => - pageSet.has(page.slug), + test( + "published glossary pages render auto-linked shell descriptions without body duplication", + async () => { + const pages = await listPublishedGlossaryPages(); + + for (const page of pages) { + const loadedPage = await loadLocalDocsPage({ + section: "glossary", + slug: page.slug, + }); + const html = renderGlossaryDocsShell(loadedPage); + const articleHtml = extractGlossaryArticleHtml( + html, + loadedPage.frontmatter.registryId, ); - expect(pages).toHaveLength(slugChunk.length); - - for (const page of pages) { - const loadedPage = await loadLocalDocsPage({ - section: "glossary", - slug: page.slug, - }); - const html = renderGlossaryDocsShell(loadedPage); - const articleHtml = extractGlossaryArticleHtml( - html, - loadedPage.frontmatter.registryId, - ); - - const articleStart = html.indexOf("= 0 ? html.slice(0, articleStart) : html; - expectHtmlToContainProse(shellHtml, loadedPage.messages.description); - expectGlossaryBodyOmitsShellDescription( - articleHtml, - loadedPage.messages.description, - ); - expectGlossaryShellAutoLinksUseProseContract(html); - } - }, - { timeout: 10_000 }, - ); - } + const articleStart = html.indexOf("= 0 ? html.slice(0, articleStart) : html; + expectHtmlToContainProse(shellHtml, loadedPage.messages.description); + expectGlossaryBodyOmitsShellDescription( + articleHtml, + loadedPage.messages.description, + ); + expectGlossaryShellAutoLinksUseProseContract(html); + } + }, + { timeout: 20_000 }, + ); test("/docs/glossary/embedding shell description links dense vector and token with preserved link text", async () => { const loadedPage = await loadLocalDocsPage({ diff --git a/src/lib/content/registry-runtime.test.ts b/src/lib/content/registry-runtime.test.ts index 0111e3eb..2a98872e 100644 --- a/src/lib/content/registry-runtime.test.ts +++ b/src/lib/content/registry-runtime.test.ts @@ -19,9 +19,7 @@ describe("registry-runtime", () => { expect(record?.relatedIds).toContain("module.multi-head-attention"); expect(record?.relatedIds).toContain("module.multi-query-attention"); expect(record?.relatedIds).toContain("module.grouped-query-attention"); - expect(record?.relatedIds).toContain("concept.kv-cache"); expect(record?.relatedIds).toContain("concept.token"); - expect(record?.relatedIds).toContain("concept.prefill-decode-split"); }); test("getModuleById returns grouped-query attention", () => { @@ -32,10 +30,6 @@ describe("registry-runtime", () => { "module.attention", "module.multi-head-attention", "module.multi-query-attention", - "concept.kv-cache", - "concept.decode", - "concept.quantization", - "concept.prefill-decode-split", ]); }); @@ -93,10 +87,6 @@ describe("registry-runtime", () => { "module.attention", "module.multi-head-attention", "module.grouped-query-attention", - "concept.kv-cache", - "concept.decode", - "concept.quantization", - "concept.prefill-decode-split", ]); }); @@ -126,8 +116,7 @@ describe("registry-runtime", () => { expect(ids).toContain("concept.token"); expect(ids).toContain("concept.embedding"); expect(ids).toContain("concept.softmax"); - expect(ids).toContain("concept.prefill"); - expect(ids).toContain("concept.prefill-decode-split"); + expect(ids).toContain("concept.standard-ffn"); }); test("getConceptById returns published embedding and logit for chain", () => { diff --git a/src/lib/content/registry-runtime.ts b/src/lib/content/registry-runtime.ts index 9161d6f8..0c567bc8 100644 --- a/src/lib/content/registry-runtime.ts +++ b/src/lib/content/registry-runtime.ts @@ -1,23 +1,18 @@ import activationConcept from "@/content/registry/concepts/activation.json"; -import activationQuantizationConcept from "@/content/registry/concepts/activation-quantization.json"; import alibiConcept from "@/content/registry/concepts/alibi.json"; import alignmentConcept from "@/content/registry/concepts/alignment.json"; import architectureConcept from "@/content/registry/concepts/architecture.json"; import autoregressiveGenerationConcept from "@/content/registry/concepts/autoregressive-generation.json"; import backpropagationConcept from "@/content/registry/concepts/backpropagation.json"; -import batchNormConcept from "@/content/registry/concepts/batch-norm.json"; -import calibrationConcept from "@/content/registry/concepts/calibration.json"; import componentConcept from "@/content/registry/concepts/component.json"; import computationalGraphConcept from "@/content/registry/concepts/computational-graph.json"; import conditioningConcept from "@/content/registry/concepts/conditioning.json"; import contextExtensionConcept from "@/content/registry/concepts/context-extension.json"; import contextWindowConcept from "@/content/registry/concepts/context-window.json"; -import decodeConcept from "@/content/registry/concepts/decode.json"; import decoderConcept from "@/content/registry/concepts/decoder.json"; import denoisingGenerationConcept from "@/content/registry/concepts/denoising-generation.json"; import diffusionModelConcept from "@/content/registry/concepts/diffusion-model.json"; import discriminativeModelConcept from "@/content/registry/concepts/discriminative-model.json"; -import dynamicQuantizationConcept from "@/content/registry/concepts/dynamic-quantization.json"; import embeddingConcept from "@/content/registry/concepts/embedding.json"; import emergentBehaviorConcept from "@/content/registry/concepts/emergent-behavior.json"; import encoderConcept from "@/content/registry/concepts/encoder.json"; @@ -28,11 +23,7 @@ import foundationModelConcept from "@/content/registry/concepts/foundation-model import generalizationConcept from "@/content/registry/concepts/generalization.json"; import generativeModelConcept from "@/content/registry/concepts/generative-model.json"; import gradientConcept from "@/content/registry/concepts/gradient.json"; -import greedyDecodingConcept from "@/content/registry/concepts/greedy-decoding.json"; -import groupNormConcept from "@/content/registry/concepts/group-norm.json"; import hiddenSizeConcept from "@/content/registry/concepts/hidden-size.json"; -import kvCacheConcept from "@/content/registry/concepts/kv-cache.json"; -import kvCacheQuantizationConcept from "@/content/registry/concepts/kv-cache-quantization.json"; import latentConcept from "@/content/registry/concepts/latent.json"; import latentSpaceConcept from "@/content/registry/concepts/latent-space.json"; import layerNormConcept from "@/content/registry/concepts/layer-norm.json"; @@ -52,34 +43,22 @@ import parameterConcept from "@/content/registry/concepts/parameter.json"; import patchConcept from "@/content/registry/concepts/patch.json"; import perplexityConcept from "@/content/registry/concepts/perplexity.json"; import positionalEncodingsConcept from "@/content/registry/concepts/positional-encodings.json"; -import postTrainingQuantizationConcept from "@/content/registry/concepts/post-training-quantization.json"; -import prefillConcept from "@/content/registry/concepts/prefill.json"; -import prefillDecodeSplitConcept from "@/content/registry/concepts/prefill-decode-split.json"; -import qkNormConcept from "@/content/registry/concepts/qk-norm.json"; -import quantizationConcept from "@/content/registry/concepts/quantization.json"; -import quantizationAwareTrainingConcept from "@/content/registry/concepts/quantization-aware-training.json"; import reluConcept from "@/content/registry/concepts/relu.json"; import representationConcept from "@/content/registry/concepts/representation.json"; import residualConnectionConcept from "@/content/registry/concepts/residual-connection.json"; import rmsnormConcept from "@/content/registry/concepts/rmsnorm.json"; import ropeConcept from "@/content/registry/concepts/rope.json"; -import samplingOverviewConcept from "@/content/registry/concepts/sampling-overview.json"; import scalingLawConcept from "@/content/registry/concepts/scaling-law.json"; import siluConcept from "@/content/registry/concepts/silu.json"; -import skipConnectionConcept from "@/content/registry/concepts/skip-connection.json"; import softmaxConcept from "@/content/registry/concepts/softmax.json"; import standardFfnConcept from "@/content/registry/concepts/standard-ffn.json"; import swigluConcept from "@/content/registry/concepts/swiglu.json"; import temperatureConcept from "@/content/registry/concepts/temperature.json"; import tensorConcept from "@/content/registry/concepts/tensor.json"; import tokenConcept from "@/content/registry/concepts/token.json"; -import topKSamplingConcept from "@/content/registry/concepts/top-k-sampling.json"; -import topPSamplingConcept from "@/content/registry/concepts/top-p-sampling.json"; import transformerConcept from "@/content/registry/concepts/transformer.json"; import transformerArchitectureConcept from "@/content/registry/concepts/transformer-architecture.json"; import vectorConcept from "@/content/registry/concepts/vector.json"; -import weightOnlyQuantizationConcept from "@/content/registry/concepts/weight-only-quantization.json"; -import whyFourBitModelsAreNotExactlyFourXFasterConcept from "@/content/registry/concepts/why-4-bit-models-are-not-exactly-4x-faster.json"; import whyLongContextIsHardConcept from "@/content/registry/concepts/why-long-context-is-hard.json"; import worldModelConcept from "@/content/registry/concepts/world-model.json"; import attention from "@/content/registry/modules/attention.json"; @@ -119,19 +98,12 @@ const conceptRecords: ConceptRecord[] = [ conceptRecordSchema.parse(tensorConcept), conceptRecordSchema.parse(vectorConcept), conceptRecordSchema.parse(hiddenSizeConcept), - conceptRecordSchema.parse(kvCacheConcept), - conceptRecordSchema.parse(kvCacheQuantizationConcept), conceptRecordSchema.parse(logitConcept), conceptRecordSchema.parse(softmaxConcept), conceptRecordSchema.parse(entropyConcept), conceptRecordSchema.parse(temperatureConcept), - conceptRecordSchema.parse(samplingOverviewConcept), - conceptRecordSchema.parse(greedyDecodingConcept), - conceptRecordSchema.parse(topKSamplingConcept), - conceptRecordSchema.parse(topPSamplingConcept), conceptRecordSchema.parse(parameterConcept), conceptRecordSchema.parse(activationConcept), - conceptRecordSchema.parse(activationQuantizationConcept), conceptRecordSchema.parse(computationalGraphConcept), conceptRecordSchema.parse(gradientConcept), conceptRecordSchema.parse(backpropagationConcept), @@ -145,55 +117,41 @@ const conceptRecords: ConceptRecord[] = [ conceptRecordSchema.parse(foundationModelConcept), conceptRecordSchema.parse(generativeModelConcept), conceptRecordSchema.parse(discriminativeModelConcept), - conceptRecordSchema.parse(dynamicQuantizationConcept), conceptRecordSchema.parse(representationConcept), conceptRecordSchema.parse(patchConcept), conceptRecordSchema.parse(latentConcept), conceptRecordSchema.parse(latentSpaceConcept), conceptRecordSchema.parse(encoderConcept), - conceptRecordSchema.parse(decodeConcept), conceptRecordSchema.parse(decoderConcept), conceptRecordSchema.parse(encoderDecoderConcept), conceptRecordSchema.parse(autoregressiveGenerationConcept), - conceptRecordSchema.parse(prefillConcept), - conceptRecordSchema.parse(prefillDecodeSplitConcept), conceptRecordSchema.parse(denoisingGenerationConcept), conceptRecordSchema.parse(conditioningConcept), conceptRecordSchema.parse(contextExtensionConcept), conceptRecordSchema.parse(contextWindowConcept), conceptRecordSchema.parse(alignmentConcept), - conceptRecordSchema.parse(batchNormConcept), conceptRecordSchema.parse(modelCapacityConcept), conceptRecordSchema.parse(overfittingConcept), conceptRecordSchema.parse(generalizationConcept), - conceptRecordSchema.parse(groupNormConcept), conceptRecordSchema.parse(perplexityConcept), conceptRecordSchema.parse(scalingLawConcept), conceptRecordSchema.parse(emergentBehaviorConcept), conceptRecordSchema.parse(feedForwardNetworkConcept), conceptRecordSchema.parse(standardFfnConcept), - conceptRecordSchema.parse(mixtureOfExpertsConcept), conceptRecordSchema.parse(reluConcept), conceptRecordSchema.parse(leakyReluConcept), conceptRecordSchema.parse(siluConcept), conceptRecordSchema.parse(swigluConcept), + conceptRecordSchema.parse(mixtureOfExpertsConcept), conceptRecordSchema.parse(layerNormConcept), conceptRecordSchema.parse(normalizationConcept), - conceptRecordSchema.parse(qkNormConcept), conceptRecordSchema.parse(rmsnormConcept), conceptRecordSchema.parse(alibiConcept), - conceptRecordSchema.parse(calibrationConcept), conceptRecordSchema.parse(positionalEncodingsConcept), - conceptRecordSchema.parse(postTrainingQuantizationConcept), - conceptRecordSchema.parse(quantizationConcept), - conceptRecordSchema.parse(quantizationAwareTrainingConcept), conceptRecordSchema.parse(residualConnectionConcept), - conceptRecordSchema.parse(skipConnectionConcept), conceptRecordSchema.parse(ropeConcept), conceptRecordSchema.parse(transformerArchitectureConcept), conceptRecordSchema.parse(transformerConcept), - conceptRecordSchema.parse(weightOnlyQuantizationConcept), - conceptRecordSchema.parse(whyFourBitModelsAreNotExactlyFourXFasterConcept), conceptRecordSchema.parse(diffusionModelConcept), conceptRecordSchema.parse(multimodalModelConcept), conceptRecordSchema.parse(whyLongContextIsHardConcept), diff --git a/src/lib/content/standard-ffn-glossary.test.ts b/src/lib/content/standard-ffn-glossary.test.ts index 7103042f..ef4b6db7 100644 --- a/src/lib/content/standard-ffn-glossary.test.ts +++ b/src/lib/content/standard-ffn-glossary.test.ts @@ -24,14 +24,14 @@ import { buildSearchDocuments } from "@/lib/search/build-documents"; const pageDir = STANDARD_FFN_GLOSSARY_PAGE_DIR; const messagesPath = join(pageDir, "messages/en.json"); -describe("Phase 3 standard FFN glossary page (US-001)", () => { - test("registry record is published with aliases, tags, and curated related ids", () => { +describe("FFN pages from phase 3 standard FFN glossary page (US-001)", () => { + test("registry record is published with dense FFN aliases and curated related ids", () => { const record = getConceptById("concept.standard-ffn"); expect(record?.status).toBe("published"); expect(record?.aliases).toEqual([ + "standard FFN", "dense FFN", "dense MLP block", - "standard feed-forward network", ]); expect(record?.tags).toEqual(["foundations"]); expect(record?.relatedIds).toEqual([ @@ -42,7 +42,7 @@ describe("Phase 3 standard FFN glossary page (US-001)", () => { expect(PUBLISHED_DOCS_REGISTRY_IDS.has("concept.standard-ffn")).toBe(true); }); - test("curated related links feed-forward network, mixture of experts, and activation", () => { + test("curated related links broad FFN, mixture of experts, and activation", () => { const source = getConceptById("concept.standard-ffn"); if (!source) { throw new Error("expected concept.standard-ffn in registry"); @@ -73,7 +73,7 @@ describe("Phase 3 standard FFN glossary page (US-001)", () => { expect(activation?.isPlanned).toBe(false); }); - test("messages explain dense expand-activate-project baseline and contrast nearby variants", () => { + test("messages explain the dense expand activate project path after attention", () => { const messages = pageMessagesSchema.parse( JSON.parse(readFileSync(messagesPath, "utf8")), ); @@ -83,16 +83,18 @@ describe("Phase 3 standard FFN glossary page (US-001)", () => { expect(messages.sections?.whatItIs.body?.toLowerCase()).toContain( "attention", ); - expect(messages.sections?.whatItIs.body?.toLowerCase()).toContain("dense"); - expect(messages.sections?.whyItMatters.body?.toLowerCase()).toContain( - "expand", + expect(messages.sections?.whatItIs.body?.toLowerCase()).toContain( + "projection", + ); + expect(messages.sections?.commonConfusions.body?.toLowerCase()).toContain( + "mixture-of-experts", ); - expect(messages.sections?.whyItMatters.body?.toLowerCase()).toContain( - "mixture of experts", + expect(messages.sections?.commonConfusions.body?.toLowerCase()).toContain( + "relu", ); }); - test("page renders glossary sections, tags, and nearby FFN-family links", async () => { + test("page renders baseline FFN explanation and curated related links", async () => { const page = await loadGlossaryPage("standard-ffn"); expect(page.frontmatter.kind).toBe("glossary"); @@ -113,7 +115,7 @@ describe("Phase 3 standard FFN glossary page (US-001)", () => { }); expect(html).toContain("What It Is"); expect(html).toContain("Common Confusions"); - expectHtmlToContainProse(html, "expand, activate, project"); + expectHtmlToContainProse(html, "plain dense feed-forward block"); expect(html).toContain('href="/docs/glossary/feed-forward-network"'); expect(html).toContain('href="/docs/glossary/mixture-of-experts"'); expect(html).toContain('href="/docs/glossary/activation"'); @@ -124,7 +126,7 @@ describe("Phase 3 standard FFN glossary page (US-001)", () => { expect(html).not.toContain("Reader Shortcut"); }); - test("search index records standard FFN with glossary kind", async () => { + test("search index records Standard FFN with glossary kind and exact aliases", async () => { const registry = await loadRegistry(); const pages = await loadPublishedDocsPages("en"); const documents = buildSearchDocuments(pages, registry); @@ -135,7 +137,7 @@ describe("Phase 3 standard FFN glossary page (US-001)", () => { expect(document?.kind).toBe("glossary"); expect(document?.facets.kind).toBe("glossary"); expect(document?.aliases).toEqual( - expect.arrayContaining(["dense FFN", "standard feed-forward network"]), + expect.arrayContaining(["standard FFN", "dense FFN"]), ); }); }); diff --git a/src/lib/source.test.ts b/src/lib/source.test.ts index 4996c894..0756a4c1 100644 --- a/src/lib/source.test.ts +++ b/src/lib/source.test.ts @@ -50,6 +50,7 @@ const GLOSSARY_INDEX_URLS = [ "/docs/glossary/top-p-sampling", "/docs/glossary/representation", "/docs/glossary/scaling-law", + "/docs/glossary/standard-ffn", "/docs/glossary/token", "/docs/glossary/transformer", "/docs/glossary/world-model", diff --git a/src/tests/content/architecture-index.test.ts b/src/tests/content/architecture-index.test.ts index ee7b47e4..ea3b9566 100644 --- a/src/tests/content/architecture-index.test.ts +++ b/src/tests/content/architecture-index.test.ts @@ -32,12 +32,10 @@ describe("isArchitectureRelatedPage", () => { "/docs/glossary/alignment", "/docs/glossary/architecture", "/docs/glossary/autoregressive-generation", - "/docs/glossary/batch-norm", "/docs/glossary/component", "/docs/glossary/computational-graph", "/docs/glossary/conditioning", "/docs/glossary/context-window", - "/docs/glossary/decode", "/docs/glossary/decoder", "/docs/glossary/denoising-generation", "/docs/glossary/diffusion-model", @@ -50,12 +48,11 @@ describe("isArchitectureRelatedPage", () => { "/docs/glossary/foundation-model", "/docs/glossary/generalization", "/docs/glossary/generative-model", - "/docs/glossary/group-norm", - "/docs/glossary/kv-cache", "/docs/glossary/latent", "/docs/glossary/latent-space", "/docs/glossary/layer-norm", "/docs/glossary/leaky-relu", + "/docs/glossary/relu", "/docs/glossary/mixture-of-experts", "/docs/glossary/modality", "/docs/glossary/model", @@ -66,13 +63,8 @@ describe("isArchitectureRelatedPage", () => { "/docs/glossary/overfitting", "/docs/glossary/patch", "/docs/glossary/perplexity", - "/docs/glossary/prefill", - "/docs/glossary/prefill-decode-split", - "/docs/glossary/qk-norm", - "/docs/glossary/relu", "/docs/glossary/representation", "/docs/glossary/residual-connection", - "/docs/glossary/skip-connection", "/docs/glossary/rmsnorm", "/docs/glossary/rope", "/docs/glossary/scaling-law", @@ -168,14 +160,16 @@ describe("architecture index page render", () => { expect(html).toContain('href="/docs/glossary/architecture"'); expect(html).toContain("Foundation Model"); expect(html).toContain('href="/docs/glossary/foundation-model"'); - expect(html).toContain("KV cache"); - expect(html).toContain('href="/docs/glossary/kv-cache"'); - expect(html).toContain("Decode"); - expect(html).toContain('href="/docs/glossary/decode"'); - expect(html).toContain("Prefill"); - expect(html).toContain('href="/docs/glossary/prefill"'); - expect(html).toContain("Prefill/decode split"); - expect(html).toContain('href="/docs/glossary/prefill-decode-split"'); + expect(html).toContain("Standard FFN"); + expect(html).toContain('href="/docs/glossary/standard-ffn"'); + expect(html).toContain("ReLU"); + expect(html).toContain('href="/docs/glossary/relu"'); + expect(html).toContain("LeakyReLU"); + expect(html).toContain('href="/docs/glossary/leaky-relu"'); + expect(html).toContain("SiLU"); + expect(html).toContain('href="/docs/glossary/silu"'); + expect(html).toContain("SwiGLU"); + expect(html).toContain('href="/docs/glossary/swiglu"'); expect(html).toContain("Token"); expect(html).toContain('href="/docs/glossary/token"'); expect(html).not.toContain("No architecture entries yet"); diff --git a/src/tests/content/glossary-index.test.ts b/src/tests/content/glossary-index.test.ts index 04aee7be..3576a929 100644 --- a/src/tests/content/glossary-index.test.ts +++ b/src/tests/content/glossary-index.test.ts @@ -108,9 +108,9 @@ describe("loadPublishedGlossaryEntries", () => { expect(optimizerState?.summary.length).toBeGreaterThan(0); }); - it("includes all published glossary pages with localized titles", async () => { + it("includes all nine Phase 2 taxonomy glossary pages with localized titles", async () => { const entries = await loadPublishedGlossaryEntries("en"); - expect(entries).toHaveLength(71); + expect(entries).toHaveLength(59); const architecture = entries.find( (entry) => entry.url === "/docs/glossary/architecture", @@ -128,55 +128,26 @@ describe("loadPublishedGlossaryEntries", () => { ); expect(encoder?.title).toBe("Encoder"); - const kvCache = entries.find( - (entry) => entry.url === "/docs/glossary/kv-cache", + const standardFfn = entries.find( + (entry) => entry.url === "/docs/glossary/standard-ffn", ); - expect(kvCache?.title).toBe("KV cache"); + expect(standardFfn?.title).toBe("Standard FFN"); - const prefill = entries.find( - (entry) => entry.url === "/docs/glossary/prefill", - ); - expect(prefill?.title).toBe("Prefill"); - - const prefillDecodeSplit = entries.find( - (entry) => entry.url === "/docs/glossary/prefill-decode-split", - ); - expect(prefillDecodeSplit?.title).toBe("Prefill/decode split"); - - const decode = entries.find( - (entry) => entry.url === "/docs/glossary/decode", - ); - expect(decode?.title).toBe("Decode"); - - const samplingOverview = entries.find( - (entry) => entry.url === "/docs/glossary/sampling-overview", - ); - expect(samplingOverview?.title).toBe("Sampling Overview"); - - const greedyDecoding = entries.find( - (entry) => entry.url === "/docs/glossary/greedy-decoding", - ); - expect(greedyDecoding?.title).toBe("Greedy Decoding"); + const relu = entries.find((entry) => entry.url === "/docs/glossary/relu"); + expect(relu?.title).toBe("ReLU"); - const topKSampling = entries.find( - (entry) => entry.url === "/docs/glossary/top-k-sampling", + const leakyRelu = entries.find( + (entry) => entry.url === "/docs/glossary/leaky-relu", ); - expect(topKSampling?.title).toBe("Top-K Sampling"); + expect(leakyRelu?.title).toBe("LeakyReLU"); - const topPSampling = entries.find( - (entry) => entry.url === "/docs/glossary/top-p-sampling", - ); - expect(topPSampling?.title).toBe("Top-P Sampling"); + const silu = entries.find((entry) => entry.url === "/docs/glossary/silu"); + expect(silu?.title).toBe("SiLU"); const swiglu = entries.find( (entry) => entry.url === "/docs/glossary/swiglu", ); expect(swiglu?.title).toBe("SwiGLU"); - - const skipConnection = entries.find( - (entry) => entry.url === "/docs/glossary/skip-connection", - ); - expect(skipConnection?.title).toBe("Skip connection"); }); }); @@ -242,26 +213,16 @@ describe("glossary index page render", () => { expect(html).toContain('href="/docs/glossary/entropy"'); expect(html).toContain("Temperature"); expect(html).toContain('href="/docs/glossary/temperature"'); - expect(html).toContain("Greedy Decoding"); - expect(html).toContain('href="/docs/glossary/greedy-decoding"'); - expect(html).toContain("Top-K Sampling"); - expect(html).toContain('href="/docs/glossary/top-k-sampling"'); - expect(html).toContain("Top-P Sampling"); - expect(html).toContain('href="/docs/glossary/top-p-sampling"'); expect(html).toContain("Parameter"); expect(html).toContain('href="/docs/glossary/parameter"'); expect(html).toContain("Activation"); expect(html).toContain('href="/docs/glossary/activation"'); + expect(html).toContain("ReLU"); + expect(html).toContain('href="/docs/glossary/relu"'); + expect(html).toContain("LeakyReLU"); + expect(html).toContain('href="/docs/glossary/leaky-relu"'); expect(html).toContain("Computational Graph"); expect(html).toContain('href="/docs/glossary/computational-graph"'); - expect(html).toContain("KV cache"); - expect(html).toContain('href="/docs/glossary/kv-cache"'); - expect(html).toContain("Decode"); - expect(html).toContain('href="/docs/glossary/decode"'); - expect(html).toContain("Prefill"); - expect(html).toContain('href="/docs/glossary/prefill"'); - expect(html).toContain("Prefill/decode split"); - expect(html).toContain('href="/docs/glossary/prefill-decode-split"'); expect(html).not.toContain("No glossary entries yet"); expect(html).toContain("list-none"); expect(html).not.toContain("list-disc"); diff --git a/src/tests/search/orama-index.test.ts b/src/tests/search/orama-index.test.ts index da457498..ab08f9d2 100644 --- a/src/tests/search/orama-index.test.ts +++ b/src/tests/search/orama-index.test.ts @@ -27,45 +27,21 @@ const PAGE_SPEC_WORKFLOW_SAMPLE_URL = "/docs/concepts/page-spec-workflow-sample"; const FEED_FORWARD_NETWORK_URL = "/docs/glossary/feed-forward-network"; const STANDARD_FFN_URL = "/docs/glossary/standard-ffn"; -const NORMALIZATION_URL = "/docs/glossary/normalization"; -const LAYER_NORM_URL = "/docs/glossary/layer-norm"; -const BATCH_NORM_URL = "/docs/glossary/batch-norm"; -const GROUP_NORM_URL = "/docs/glossary/group-norm"; -const MIXTURE_OF_EXPERTS_URL = "/docs/glossary/mixture-of-experts"; const RELU_URL = "/docs/glossary/relu"; const LEAKY_RELU_URL = "/docs/glossary/leaky-relu"; const SILU_URL = "/docs/glossary/silu"; const SWIGLU_URL = "/docs/glossary/swiglu"; +const MIXTURE_OF_EXPERTS_URL = "/docs/glossary/mixture-of-experts"; +const LAYER_NORM_URL = "/docs/glossary/layer-norm"; const RMSNORM_URL = "/docs/glossary/rmsnorm"; -const QK_NORM_URL = "/docs/glossary/qk-norm"; +const NORMALIZATION_URL = "/docs/glossary/normalization"; const RESIDUAL_CONNECTION_URL = "/docs/glossary/residual-connection"; -const SKIP_CONNECTION_URL = "/docs/glossary/skip-connection"; const POSITIONAL_ENCODINGS_URL = "/docs/concepts/positional-encodings"; const ROPE_URL = "/docs/glossary/rope"; const ALIBI_URL = "/docs/glossary/alibi"; const CONTEXT_WINDOW_URL = "/docs/glossary/context-window"; -const KV_CACHE_URL = "/docs/glossary/kv-cache"; -const PREFILL_URL = "/docs/glossary/prefill"; -const DECODE_URL = "/docs/glossary/decode"; -const PREFILL_DECODE_SPLIT_URL = "/docs/glossary/prefill-decode-split"; -const SAMPLING_OVERVIEW_URL = "/docs/glossary/sampling-overview"; -const GREEDY_DECODING_URL = "/docs/glossary/greedy-decoding"; -const TOP_K_SAMPLING_URL = "/docs/glossary/top-k-sampling"; -const TOP_P_SAMPLING_URL = "/docs/glossary/top-p-sampling"; const CONTEXT_EXTENSION_URL = "/docs/concepts/context-extension"; const WHY_LONG_CONTEXT_IS_HARD_URL = "/docs/concepts/why-long-context-is-hard"; -const QUANTIZATION_URL = "/docs/concepts/quantization"; -const POST_TRAINING_QUANTIZATION_URL = - "/docs/concepts/post-training-quantization"; -const CALIBRATION_URL = "/docs/concepts/calibration"; -const QUANTIZATION_AWARE_TRAINING_URL = - "/docs/concepts/quantization-aware-training"; -const DYNAMIC_QUANTIZATION_URL = "/docs/concepts/dynamic-quantization"; -const WEIGHT_ONLY_QUANTIZATION_URL = "/docs/concepts/weight-only-quantization"; -const ACTIVATION_QUANTIZATION_URL = "/docs/concepts/activation-quantization"; -const KV_CACHE_QUANTIZATION_URL = "/docs/concepts/kv-cache-quantization"; -const WHY_FOUR_BIT_MODELS_ARE_NOT_EXACTLY_FOUR_X_FASTER_URL = - "/docs/concepts/why-4-bit-models-are-not-exactly-4x-faster"; const STRUCTURAL_TAXONOMY_URLS = [ "/docs/glossary/model", "/docs/glossary/architecture", @@ -93,14 +69,6 @@ const GENERATION_PARADIGM_URLS = [ "/docs/glossary/autoregressive-generation", "/docs/glossary/denoising-generation", "/docs/glossary/conditioning", - KV_CACHE_URL, - PREFILL_URL, - DECODE_URL, - PREFILL_DECODE_SPLIT_URL, - SAMPLING_OVERVIEW_URL, - GREEDY_DECODING_URL, - TOP_K_SAMPLING_URL, - TOP_P_SAMPLING_URL, ] as const; const TRAINING_BEHAVIOR_URLS = [ "/docs/glossary/alignment", @@ -149,35 +117,22 @@ const PUBLISHED_SEARCH_INDEX_URLS = [ TRANSFORMER_ARCHITECTURE_URL, PAGE_SPEC_WORKFLOW_SAMPLE_URL, FEED_FORWARD_NETWORK_URL, - BATCH_NORM_URL, - GROUP_NORM_URL, STANDARD_FFN_URL, - MIXTURE_OF_EXPERTS_URL, RELU_URL, LEAKY_RELU_URL, SILU_URL, SWIGLU_URL, + MIXTURE_OF_EXPERTS_URL, LAYER_NORM_URL, RMSNORM_URL, NORMALIZATION_URL, - QK_NORM_URL, RESIDUAL_CONNECTION_URL, - SKIP_CONNECTION_URL, POSITIONAL_ENCODINGS_URL, ROPE_URL, ALIBI_URL, CONTEXT_WINDOW_URL, CONTEXT_EXTENSION_URL, WHY_LONG_CONTEXT_IS_HARD_URL, - QUANTIZATION_URL, - POST_TRAINING_QUANTIZATION_URL, - CALIBRATION_URL, - QUANTIZATION_AWARE_TRAINING_URL, - DYNAMIC_QUANTIZATION_URL, - WEIGHT_ONLY_QUANTIZATION_URL, - ACTIVATION_QUANTIZATION_URL, - KV_CACHE_QUANTIZATION_URL, - WHY_FOUR_BIT_MODELS_ARE_NOT_EXACTLY_FOUR_X_FASTER_URL, ...STRUCTURAL_TAXONOMY_URLS, ...ROLE_MODALITY_TAXONOMY_URLS, ...REPRESENTATION_LATENT_URLS, @@ -267,16 +222,6 @@ describe("exportOramaIndexSnapshot", () => { { query: "multi-head attention", url: MULTI_HEAD_ATTENTION_URL }, { query: "MQA", url: MULTI_QUERY_ATTENTION_URL }, { query: "multi-query attention", url: MULTI_QUERY_ATTENTION_URL }, - { query: "feed-forward network", url: FEED_FORWARD_NETWORK_URL }, - { query: "standard FFN", url: STANDARD_FFN_URL }, - { query: "normalization", url: NORMALIZATION_URL }, - { query: "layer norm", url: LAYER_NORM_URL }, - { query: "batch norm", url: BATCH_NORM_URL }, - { query: "group norm", url: GROUP_NORM_URL }, - { query: "RMSNorm", url: RMSNORM_URL }, - { query: "QK norm", url: QK_NORM_URL }, - { query: "residual connection", url: RESIDUAL_CONNECTION_URL }, - { query: "skip connection", url: SKIP_CONNECTION_URL }, ] as const)("Orama database records rank %s for the %s alias query", async ({ query, url, From 9e290a25f0107e4460cf9633df7bbeb3b6afff4c Mon Sep 17 00:00:00 2001 From: aabdi Date: Thu, 18 Jun 2026 09:06:42 +0700 Subject: [PATCH 2/5] feat: [ffn-pages-from-phase-3-002] - [Publish the ReLU and LeakyReLU pages] --- .../docs/glossary/leaky-relu/messages/en.json | 12 +- src/content/docs/glossary/leaky-relu/page.mdx | 4 +- .../docs/glossary/relu/messages/en.json | 12 +- src/content/docs/glossary/relu/page.mdx | 6 +- src/content/registry/concepts/leaky-relu.json | 9 +- src/content/registry/concepts/relu.json | 5 +- src/lib/content/content-paths.ts | 9 + .../content/published-docs-registry-ids.ts | 2 + .../content/relu-leaky-relu-glossary.test.ts | 228 ++++++++++++++++++ src/lib/source.test.ts | 2 + 10 files changed, 262 insertions(+), 27 deletions(-) create mode 100644 src/lib/content/relu-leaky-relu-glossary.test.ts diff --git a/src/content/docs/glossary/leaky-relu/messages/en.json b/src/content/docs/glossary/leaky-relu/messages/en.json index d993d4f9..285927a6 100644 --- a/src/content/docs/glossary/leaky-relu/messages/en.json +++ b/src/content/docs/glossary/leaky-relu/messages/en.json @@ -1,22 +1,22 @@ { "title": "LeakyReLU", - "description": "A ReLU-style activation that keeps a small negative slope instead of zeroing every negative FFN value.", + "description": "An FFN activation like ReLU that still lets a small negative signal pass instead of clamping all negative values to zero.", "sections": { "whatItIs": { "title": "What It Is", - "body": "LeakyReLU is a small change to ReLU. Positive hidden values pass through as usual, but negative values are multiplied by a small constant such as 0.01 instead of becoming zero. In a standard FFN after attention, that means a token can keep a weak negative signal rather than shutting the feature off completely." + "body": "LeakyReLU is a ReLU-style activation with a small slope on the negative side. Inside an FFN, positive hidden values still pass through normally, but negative values are shrunk rather than cut off entirely. The result is still a simple per-token hidden transform in the same FFN slot after attention." }, "whyItMatters": { "title": "Why It Matters", - "body": "The main reason to use LeakyReLU is to avoid losing all gradient signal on the negative side. A dense FFN with plain ReLU can leave some hidden units inactive for long stretches if they keep landing below zero. LeakyReLU softens that cutoff, so papers sometimes use it when they want ReLU-like behavior with a less brittle negative branch." + "body": "This variant changes one specific behavior relative to ReLU: negative responses do not disappear completely. That makes LeakyReLU useful as a comparison point when you want to understand what changes if an FFN keeps a faint negative signal alive instead of throwing it away. It stays a dense FFN choice, not a routing or architecture change." }, "simpleExample": { "title": "Simple Example", - "body": "If the hidden values are [-2.0, 0.7, 3.4] and the leak factor is 0.01, LeakyReLU produces [-0.02, 0.7, 3.4]. The FFN still runs the same expand then activate then project recipe; only the activation rule changes." + "body": "Suppose an FFN hidden vector contains -2, -0.3, 0.1, and 4. A LeakyReLU with a small negative slope might turn that into something like -0.02, -0.003, 0.1, and 4 before the block projects back down. The big idea is that the negative side still contributes a little instead of becoming exact zero." }, "commonConfusions": { "title": "Common Confusions", - "body": "LeakyReLU is not a gated FFN like SwiGLU and it is not a sparse router like mixture of experts. It stays inside the same dense standard FFN block. It also does not make negative values equally important as positive ones; the negative side is still much smaller, just not forced to zero." + "body": "LeakyReLU is still an activation inside a standard FFN, not a separate expert path or a new transformer layer. It differs from plain ReLU only in what happens to negative values. It also does not mean the model is using a gated FFN such as SwiGLU, because gating changes the FFN shape while LeakyReLU only changes the nonlinearity inside the usual dense path." }, "related": { "title": "Related Concepts And Modules" @@ -28,5 +28,5 @@ "title": "References" } }, - "openingSummary": "LeakyReLU keeps a small negative slope inside an FFN instead of clamping every negative hidden value to zero, so weak signals can still flow through the block." + "openingSummary": "LeakyReLU is a small variation on ReLU: it keeps the same FFN role, but negative hidden values leak through at a reduced scale instead of dropping to zero." } diff --git a/src/content/docs/glossary/leaky-relu/page.mdx b/src/content/docs/glossary/leaky-relu/page.mdx index 36eab020..eab4df02 100644 --- a/src/content/docs/glossary/leaky-relu/page.mdx +++ b/src/content/docs/glossary/leaky-relu/page.mdx @@ -1,6 +1,6 @@ --- title: LeakyReLU -description: A ReLU-style activation that keeps a small negative slope instead of zeroing every negative FFN value. +description: An FFN activation like ReLU that still lets a small negative signal pass instead of clamping all negative values to zero. kind: "glossary" registryId: "concept.leaky-relu" messageNamespace: "local" @@ -9,9 +9,9 @@ status: "published" tags: - foundations aliases: + - "LeakyReLU" - "leaky ReLU" - "leaky rectified linear unit" - - "Leaky ReLU activation" updatedAt: "2026-06-18" --- diff --git a/src/content/docs/glossary/relu/messages/en.json b/src/content/docs/glossary/relu/messages/en.json index 0ede63ea..66f9cb40 100644 --- a/src/content/docs/glossary/relu/messages/en.json +++ b/src/content/docs/glossary/relu/messages/en.json @@ -1,22 +1,22 @@ { "title": "ReLU", - "description": "A pointwise activation that keeps positive FFN values and clamps negative ones to zero.", + "description": "A simple activation that keeps positive values and turns negative values into zero inside many FFN hidden layers.", "sections": { "whatItIs": { "title": "What It Is", - "body": "ReLU stands for rectified linear unit. Inside a standard FFN, it looks at each hidden value after the expand layer and applies a simple rule: keep positive numbers, replace negative numbers with zero. The FFN stays in the same slot after attention, but this activation changes which hidden features stay active before the block projects back to model width." + "body": "ReLU stands for rectified linear unit. Inside a standard FFN, it leaves positive hidden values alone and replaces negative ones with zero before the next projection. That gives the FFN a simple nonlinearity, so the block can reshape features instead of behaving like one big linear map." }, "whyItMatters": { "title": "Why It Matters", - "body": "ReLU became popular because the rule is cheap to compute and easy to reason about. When a token's hidden feature is positive, the feature passes through unchanged; when it is negative, the feature drops out for that step. That sharp gate can help a dense FFN learn sparse feature patterns, which is why ReLU remains a useful baseline when papers compare newer activations." + "body": "ReLU is one of the easiest activation choices to understand, so it often acts as the baseline when people compare FFN variants. In a transformer block, the attention sublayer mixes information across tokens, then the FFN with ReLU transforms each token's hidden state on its own. If you know what ReLU changes, later pages on smoother or gated variants are easier to read." }, "simpleExample": { "title": "Simple Example", - "body": "Suppose an FFN hidden vector contains [-2.1, 0.7, 3.4]. ReLU turns it into [0, 0.7, 3.4]. The token stays in the same per-position feed-forward path; only the hidden values change before the next projection." + "body": "Imagine an FFN hidden vector with values like -2, -0.3, 0.1, and 4. ReLU turns that into 0, 0, 0.1, and 4 before the FFN projects the vector back to model width. In plain terms, the layer stops carrying the negative hidden responses forward but keeps the positive ones." }, "commonConfusions": { "title": "Common Confusions", - "body": "ReLU is only the activation step inside an FFN, not the whole feed-forward block. It also is not the same as LeakyReLU or SiLU, which keep some information for negative values instead of forcing every negative entry to zero. In transformer papers, seeing ReLU usually tells you how the hidden FFN state is shaped, not that the model changed its attention or residual path." + "body": "ReLU is an activation choice inside an FFN, not a separate transformer block. Swapping in ReLU does not move the feed-forward slot or turn the model into a mixture-of-experts layer. It is also not the same as LeakyReLU: plain ReLU cuts negative values all the way to zero, while LeakyReLU lets a small negative signal keep flowing." }, "related": { "title": "Related Concepts And Modules" @@ -28,5 +28,5 @@ "title": "References" } }, - "openingSummary": "ReLU is a simple FFN activation that zeroes negative hidden values, giving transformer MLPs a cheap nonlinearity that decides which features remain active." + "openingSummary": "ReLU is the simplest common FFN activation: after the hidden projection, it keeps positive values, zeros out negative ones, and then the block projects the result back down." } diff --git a/src/content/docs/glossary/relu/page.mdx b/src/content/docs/glossary/relu/page.mdx index 1357181b..9cb80335 100644 --- a/src/content/docs/glossary/relu/page.mdx +++ b/src/content/docs/glossary/relu/page.mdx @@ -1,6 +1,6 @@ --- title: ReLU -description: A pointwise activation that keeps positive FFN values and clamps negative ones to zero. +description: A simple activation that keeps positive values and turns negative values into zero inside many FFN hidden layers. kind: "glossary" registryId: "concept.relu" messageNamespace: "local" @@ -9,9 +9,9 @@ status: "published" tags: - foundations aliases: + - "ReLU" - "rectified linear unit" - - "ReLU activation" - - "rectifier" + - "relu activation" updatedAt: "2026-06-18" --- diff --git a/src/content/registry/concepts/leaky-relu.json b/src/content/registry/concepts/leaky-relu.json index e2f7521b..e1f992a6 100644 --- a/src/content/registry/concepts/leaky-relu.json +++ b/src/content/registry/concepts/leaky-relu.json @@ -4,18 +4,13 @@ "kind": "concept", "defaultTitleKey": "title", "defaultSummaryKey": "description", - "aliases": [ - "leaky ReLU", - "leaky rectified linear unit", - "Leaky ReLU activation" - ], + "aliases": ["LeakyReLU", "leaky ReLU", "leaky rectified linear unit"], "tags": ["foundations"], "relatedIds": [ "concept.activation", "concept.feed-forward-network", "concept.standard-ffn", - "concept.relu", - "concept.silu" + "concept.relu" ], "citationIds": [], "status": "published", diff --git a/src/content/registry/concepts/relu.json b/src/content/registry/concepts/relu.json index d0721ae5..cda2bc9c 100644 --- a/src/content/registry/concepts/relu.json +++ b/src/content/registry/concepts/relu.json @@ -4,14 +4,13 @@ "kind": "concept", "defaultTitleKey": "title", "defaultSummaryKey": "description", - "aliases": ["rectified linear unit", "ReLU activation", "rectifier"], + "aliases": ["ReLU", "rectified linear unit", "relu activation"], "tags": ["foundations"], "relatedIds": [ "concept.activation", "concept.feed-forward-network", "concept.standard-ffn", - "concept.leaky-relu", - "concept.silu" + "concept.leaky-relu" ], "citationIds": [], "status": "published", diff --git a/src/lib/content/content-paths.ts b/src/lib/content/content-paths.ts index 407e590e..8cf23a68 100644 --- a/src/lib/content/content-paths.ts +++ b/src/lib/content/content-paths.ts @@ -164,6 +164,15 @@ export const STANDARD_FFN_GLOSSARY_PAGE_DIR = join( "standard-ffn", ); +/** Phase 3 ReLU glossary page directory. */ +export const RELU_GLOSSARY_PAGE_DIR = join(GLOSSARY_DOCS_ROOT, "relu"); + +/** Phase 3 LeakyReLU glossary page directory. */ +export const LEAKY_RELU_GLOSSARY_PAGE_DIR = join( + GLOSSARY_DOCS_ROOT, + "leaky-relu", +); + /** Phase 3 mixture of experts glossary page directory. */ export const MIXTURE_OF_EXPERTS_GLOSSARY_PAGE_DIR = join( GLOSSARY_DOCS_ROOT, diff --git a/src/lib/content/published-docs-registry-ids.ts b/src/lib/content/published-docs-registry-ids.ts index fa01a4d1..a01c6e50 100644 --- a/src/lib/content/published-docs-registry-ids.ts +++ b/src/lib/content/published-docs-registry-ids.ts @@ -83,6 +83,8 @@ export const PUBLISHED_DOCS_REGISTRY_IDS = new Set([ "concept.transformer-architecture", "concept.feed-forward-network", "concept.standard-ffn", + "concept.relu", + "concept.leaky-relu", "concept.mixture-of-experts", "concept.relu", "concept.leaky-relu", diff --git a/src/lib/content/relu-leaky-relu-glossary.test.ts b/src/lib/content/relu-leaky-relu-glossary.test.ts new file mode 100644 index 00000000..6af1e7c4 --- /dev/null +++ b/src/lib/content/relu-leaky-relu-glossary.test.ts @@ -0,0 +1,228 @@ +import { describe, expect, test } from "bun:test"; +import { readFileSync } from "node:fs"; +import { join } from "node:path"; +import { createElement } from "react"; +import { renderToStaticMarkup } from "react-dom/server"; +import { ModulePageProviders } from "@/features/docs/components/ModulePageProviders"; +import { + LEAKY_RELU_GLOSSARY_PAGE_DIR, + RELU_GLOSSARY_PAGE_DIR, +} from "@/lib/content/content-paths"; +import { loadPublishedGlossaryEntries } from "@/lib/content/glossary"; +import { loadGlossaryPage } from "@/lib/content/glossary-page"; +import { + expectGlossaryPresentationConvergence, + expectHtmlToContainProse, +} from "@/lib/content/glossary-test-helpers"; +import { loadPublishedDocsPages } from "@/lib/content/pages"; +import { PUBLISHED_DOCS_REGISTRY_IDS } from "@/lib/content/published-docs-registry-ids"; +import { loadRegistry } from "@/lib/content/registry"; +import { + getConceptById, + listRelatedRegistryRecords, +} from "@/lib/content/registry-runtime"; +import { deriveCuratedRelatedItems } from "@/lib/content/related-docs"; +import { pageMessagesSchema } from "@/lib/content/schemas"; +import { buildSearchDocuments } from "@/lib/search/build-documents"; +import { pageBaseUrl } from "@/lib/search/collapse-search-results-to-page-hits"; +import { docsSearchApi } from "@/lib/search/search-server"; + +const RELU_GLOSSARY_URL = "/docs/glossary/relu"; +const LEAKY_RELU_GLOSSARY_URL = "/docs/glossary/leaky-relu"; + +const pageFixtures = [ + { + registryId: "concept.relu", + title: "ReLU", + url: RELU_GLOSSARY_URL, + pageDir: RELU_GLOSSARY_PAGE_DIR, + aliases: ["ReLU", "rectified linear unit", "relu activation"], + relatedIds: [ + "concept.activation", + "concept.feed-forward-network", + "concept.standard-ffn", + "concept.leaky-relu", + ], + prose: "keeps the positive ones", + comparisonTerm: "leakyrelu", + }, + { + registryId: "concept.leaky-relu", + title: "LeakyReLU", + url: LEAKY_RELU_GLOSSARY_URL, + pageDir: LEAKY_RELU_GLOSSARY_PAGE_DIR, + aliases: ["LeakyReLU", "leaky ReLU", "leaky rectified linear unit"], + relatedIds: [ + "concept.activation", + "concept.feed-forward-network", + "concept.standard-ffn", + "concept.relu", + ], + prose: "negative signal", + comparisonTerm: "relu", + }, +] as const; + +describe("FFN pages from phase 3 ReLU and LeakyReLU glossary pages (US-002)", () => { + for (const fixture of pageFixtures) { + test(`${fixture.title} registry record is published with aliases and curated related ids`, () => { + const { registryId, aliases, relatedIds } = fixture; + const record = getConceptById(registryId); + expect(record?.status).toBe("published"); + expect(record?.aliases).toEqual([...aliases]); + expect(record?.tags).toEqual(["foundations"]); + expect(record?.relatedIds).toEqual([...relatedIds]); + expect(PUBLISHED_DOCS_REGISTRY_IDS.has(registryId)).toBe(true); + }); + + test(`${fixture.title} curated related links activation, feed-forward network, standard FFN, and nearby variant`, () => { + const { registryId, relatedIds } = fixture; + const source = getConceptById(registryId); + if (!source) { + throw new Error(`expected ${registryId} in registry`); + } + + const items = deriveCuratedRelatedItems( + source, + listRelatedRegistryRecords(), + PUBLISHED_DOCS_REGISTRY_IDS, + ); + + for (const relatedId of relatedIds) { + const item = items.find( + (candidate) => candidate.registryId === relatedId, + ); + expect(item?.isPlanned).toBe(false); + } + + expect( + items.find((item) => item.registryId === "concept.activation")?.href, + ).toBe("/docs/glossary/activation"); + expect( + items.find((item) => item.registryId === "concept.feed-forward-network") + ?.href, + ).toBe("/docs/glossary/feed-forward-network"); + expect( + items.find((item) => item.registryId === "concept.standard-ffn")?.href, + ).toBe("/docs/glossary/standard-ffn"); + }); + } + + test("messages explain ReLU zeroing and LeakyReLU's small negative slope", () => { + const reluMessages = pageMessagesSchema.parse( + JSON.parse( + readFileSync(join(RELU_GLOSSARY_PAGE_DIR, "messages/en.json"), "utf8"), + ), + ); + const leakyReluMessages = pageMessagesSchema.parse( + JSON.parse( + readFileSync( + join(LEAKY_RELU_GLOSSARY_PAGE_DIR, "messages/en.json"), + "utf8", + ), + ), + ); + + expect(reluMessages.sections?.whatItIs.body?.toLowerCase()).toContain( + "zero", + ); + expect(reluMessages.sections?.whatItIs.body?.toLowerCase()).toContain( + "ffn", + ); + expect( + reluMessages.sections?.commonConfusions.body?.toLowerCase(), + ).toContain("leakyrelu"); + + expect(leakyReluMessages.sections?.whatItIs.body?.toLowerCase()).toContain( + "slope", + ); + expect( + leakyReluMessages.sections?.whyItMatters.body?.toLowerCase(), + ).toContain("negative"); + expect( + leakyReluMessages.sections?.commonConfusions.body?.toLowerCase(), + ).toContain("swiglu"); + }); + + for (const fixture of pageFixtures) { + test(`${fixture.title} page renders required sections, tag pill, and FFN-family related links`, async () => { + const { registryId, title, url, prose, comparisonTerm } = fixture; + const slug = url.split("/").at(-1); + if (!slug) { + throw new Error(`missing slug for ${url}`); + } + + const page = await loadGlossaryPage(slug); + + expect(page.frontmatter.kind).toBe("glossary"); + expect(page.frontmatter.status).toBe("published"); + expect(page.frontmatter.registryId).toBe(registryId); + + const html = renderToStaticMarkup( + createElement(ModulePageProviders, { + messages: page.messages, + assets: page.assets, + // biome-ignore lint/correctness/noChildrenProp: third createElement arg conflicts with strict props typing + children: page.content, + }), + ); + + expectGlossaryPresentationConvergence(html, { + title, + }); + expect(html).toContain("What It Is"); + expect(html).toContain("Common Confusions"); + expectHtmlToContainProse(html, prose); + expect(html).toContain('href="/docs/glossary/activation"'); + expect(html).toContain('href="/docs/glossary/feed-forward-network"'); + expect(html).toContain('href="/docs/glossary/standard-ffn"'); + expect(html).toContain('href="/tags/foundations"'); + expect(html).toContain('data-testid="tag-pill-list"'); + expect(html).toContain('data-testid="curated-related-docs"'); + expect(html.toLowerCase()).toContain(comparisonTerm); + expect(html).not.toContain("Phase"); + expect(html).not.toContain("Reader Shortcut"); + }); + } + + test("glossary browse index includes ReLU and LeakyReLU with summaries", async () => { + const entries = await loadPublishedGlossaryEntries("en"); + const entryByUrl = new Map(entries.map((entry) => [entry.url, entry])); + + const relu = entryByUrl.get(RELU_GLOSSARY_URL); + expect(relu?.title).toBe("ReLU"); + expect(relu?.summary.length).toBeGreaterThan(0); + + const leakyRelu = entryByUrl.get(LEAKY_RELU_GLOSSARY_URL); + expect(leakyRelu?.title).toBe("LeakyReLU"); + expect(leakyRelu?.summary.length).toBeGreaterThan(0); + }); + + test("search documents and canonical queries resolve to the ReLU-family pages", async () => { + const registry = await loadRegistry(); + const pages = await loadPublishedDocsPages("en"); + const documents = buildSearchDocuments(pages, registry); + + const relu = documents.find((entry) => entry.url === RELU_GLOSSARY_URL); + expect(relu?.kind).toBe("glossary"); + expect(relu?.aliases).toEqual( + expect.arrayContaining(["ReLU", "rectified linear unit"]), + ); + + const leakyRelu = documents.find( + (entry) => entry.url === LEAKY_RELU_GLOSSARY_URL, + ); + expect(leakyRelu?.kind).toBe("glossary"); + expect(leakyRelu?.aliases).toEqual( + expect.arrayContaining(["LeakyReLU", "leaky ReLU"]), + ); + + const reluResults = await docsSearchApi.search("ReLU"); + expect(pageBaseUrl(reluResults[0]?.url ?? "")).toBe(RELU_GLOSSARY_URL); + + const leakyReluResults = await docsSearchApi.search("LeakyReLU"); + expect(pageBaseUrl(leakyReluResults[0]?.url ?? "")).toBe( + LEAKY_RELU_GLOSSARY_URL, + ); + }); +}); diff --git a/src/lib/source.test.ts b/src/lib/source.test.ts index 0756a4c1..a5bb4a0e 100644 --- a/src/lib/source.test.ts +++ b/src/lib/source.test.ts @@ -32,6 +32,7 @@ const GLOSSARY_INDEX_URLS = [ "/docs/glossary/model-capacity", "/docs/glossary/module", "/docs/glossary/layer-norm", + "/docs/glossary/leaky-relu", "/docs/glossary/mixture-of-experts", "/docs/glossary/multimodal-model", "/docs/glossary/normalization", @@ -65,6 +66,7 @@ const GLOSSARY_INDEX_URLS = [ "/docs/glossary/temperature", "/docs/glossary/sampling-overview", "/docs/glossary/parameter", + "/docs/glossary/relu", "/docs/glossary/activation", "/docs/glossary/relu", "/docs/glossary/silu", From 669d2b58440ed44d29ba1e51b56bfaad1fb4aeed Mon Sep 17 00:00:00 2001 From: aabdi Date: Thu, 18 Jun 2026 09:20:43 +0700 Subject: [PATCH 3/5] feat: [ffn-pages-from-phase-3-003] - [Publish the SiLU and SwiGLU pages] --- .../docs/glossary/silu/messages/en.json | 12 +- src/content/docs/glossary/silu/page.mdx | 6 +- .../docs/glossary/swiglu/messages/en.json | 12 +- src/content/docs/glossary/swiglu/page.mdx | 7 +- src/content/registry/concepts/silu.json | 3 +- src/content/registry/concepts/swiglu.json | 6 +- src/lib/content/content-paths.ts | 6 + ...nt-reconciliation-search-documents.test.ts | 178 ++++++++++++++ ...ent-reconciliation-search-queries.test.tsx | 87 ------- ...nt-reconciliation-source-discovery.test.ts | 127 ++++++++++ .../phase-2-3-reconciliation-convergence.ts | 12 + .../content/published-docs-registry-ids.ts | 2 + src/lib/content/silu-swiglu-glossary.test.ts | 228 ++++++++++++++++++ src/lib/source.test.ts | 2 + 14 files changed, 578 insertions(+), 110 deletions(-) create mode 100644 src/lib/content/content-reconciliation-search-documents.test.ts create mode 100644 src/lib/content/content-reconciliation-source-discovery.test.ts create mode 100644 src/lib/content/silu-swiglu-glossary.test.ts diff --git a/src/content/docs/glossary/silu/messages/en.json b/src/content/docs/glossary/silu/messages/en.json index d96fd6c3..d8f8cad1 100644 --- a/src/content/docs/glossary/silu/messages/en.json +++ b/src/content/docs/glossary/silu/messages/en.json @@ -1,22 +1,22 @@ { "title": "SiLU", - "description": "A smooth activation that multiplies each FFN hidden value by its sigmoid gate.", + "description": "A smooth FFN activation that scales each hidden value by a soft gate based on that same value.", "sections": { "whatItIs": { "title": "What It Is", - "body": "SiLU stands for sigmoid linear unit. For each hidden value x inside an FFN, it outputs x multiplied by sigmoid(x). Large positive values pass through strongly, values near zero are softened, and negative values are reduced smoothly instead of being cut off sharply. Many modern transformer blocks use SiLU because it fits well with wide FFN layers after attention." + "body": "SiLU stands for sigmoid linear unit. Inside an FFN, it multiplies each hidden value by a soft gate computed from that same value, so the response changes smoothly instead of snapping at zero the way ReLU does. The FFN still sits in the same transformer slot after attention and still transforms each token on its own." }, "whyItMatters": { "title": "Why It Matters", - "body": "Compared with ReLU, SiLU changes hidden states more gradually. That smoother shape often works well in large language model FFNs, where small changes in hidden values can matter across many layers. SiLU also matters because SwiGLU builds on the same nonlinearity: the gate branch in a SwiGLU block uses SiLU before it scales the value branch." + "body": "SiLU is a useful bridge between simple activations and more modern gated FFN designs. It keeps the dense FFN shape of a standard FFN, but it gives the hidden transform a smoother response that many recent architectures build on. If you understand SiLU, the jump to SwiGLU is much easier because SwiGLU reuses the same smooth gating idea inside a two-branch FFN." }, "simpleExample": { "title": "Simple Example", - "body": "If one hidden value is 3, sigmoid(3) is close to 0.95, so SiLU keeps most of that signal. If another value is -2, sigmoid(-2) is small, so the output stays negative but shrinks in magnitude. The token still follows the same standard FFN slot; SiLU only changes how the expanded hidden features are filtered." + "body": "Imagine an FFN hidden value is slightly negative. ReLU would cut it to zero, but SiLU usually leaves a small negative output because the gate fades it down instead of shutting it off completely. Large positive values still pass through strongly, so the FFN can keep strong positive evidence while treating weaker values more gently." }, "commonConfusions": { "title": "Common Confusions", - "body": "SiLU is an activation, not a full gated FFN by itself. SwiGLU uses SiLU as part of a larger two-branch feed-forward design, while plain SiLU can also appear inside an otherwise standard FFN. SiLU is also not the same as softmax or sigmoid output heads; it is an internal hidden-state transform." + "body": "SiLU is still just an activation choice inside a dense FFN, not a separate expert-routing layer and not a gated FFN by itself. A model using SiLU can still have a standard FFN block shape. SwiGLU goes further by adding a second branch that gates the main branch, while mixture-of-experts changes which FFN path a token uses." }, "related": { "title": "Related Concepts And Modules" @@ -28,5 +28,5 @@ "title": "References" } }, - "openingSummary": "SiLU smoothly gates each FFN hidden value with its own sigmoid score, giving transformer MLPs a softer activation than ReLU and setting up the gate used in SwiGLU blocks." + "openingSummary": "SiLU is a smooth FFN activation: it softly gates each hidden value using that value itself, so the dense block keeps the same slot as a standard FFN but changes how hidden responses flow through it." } diff --git a/src/content/docs/glossary/silu/page.mdx b/src/content/docs/glossary/silu/page.mdx index 49dc968a..9f50314b 100644 --- a/src/content/docs/glossary/silu/page.mdx +++ b/src/content/docs/glossary/silu/page.mdx @@ -1,6 +1,6 @@ --- title: SiLU -description: A smooth activation that multiplies each FFN hidden value by its sigmoid gate. +description: A smooth FFN activation that scales each hidden value by a soft gate based on that same value. kind: "glossary" registryId: "concept.silu" messageNamespace: "local" @@ -9,9 +9,9 @@ status: "published" tags: - foundations aliases: + - "SiLU" - "sigmoid linear unit" - - "Swish" - - "SiLU activation" + - "swish" updatedAt: "2026-06-18" --- diff --git a/src/content/docs/glossary/swiglu/messages/en.json b/src/content/docs/glossary/swiglu/messages/en.json index ca266328..b58c2549 100644 --- a/src/content/docs/glossary/swiglu/messages/en.json +++ b/src/content/docs/glossary/swiglu/messages/en.json @@ -1,22 +1,22 @@ { "title": "SwiGLU", - "description": "A gated FFN design that splits the hidden expansion into value and gate branches, then uses SiLU to scale the result.", + "description": "A gated FFN variant that uses a SiLU-based gate to control a second hidden branch before projecting back to model width.", "sections": { "whatItIs": { "title": "What It Is", - "body": "SwiGLU is a feed-forward variant used in many modern language models. Instead of one expanded hidden branch, the FFN creates two branches after attention: a value branch and a gate branch. The gate branch passes through a SiLU activation, then multiplies the value branch element by element before the block projects back to model width." + "body": "SwiGLU is a gated FFN variant. Instead of one hidden branch followed by one activation, the block creates two hidden branches after the input projection: one branch carries candidate values, and the other branch uses a SiLU-style gate to decide how much of those values should pass through. After that gating step, the FFN projects the result back to model width in the same transformer slot after attention." }, "whyItMatters": { "title": "Why It Matters", - "body": "A standard FFN uses one activation on one expanded vector. SwiGLU changes the block shape by adding a separate learned gate, which lets the FFN decide more precisely which hidden features should stay strong for each token. That usually makes it a better comparison to standard FFN than to mixture of experts: SwiGLU is still one dense per-token block, while MoE changes the slot into sparse routed experts." + "body": "This page matters because SwiGLU changes the shape of the FFN block, not just the name of one activation. A standard FFN usually follows an expand, activate, and project pattern with one hidden path. SwiGLU keeps the same role inside the transformer block, but it replaces that single hidden path with a two-branch gated design. Many modern LLMs use this pattern because it gives the FFN a richer way to control hidden features." }, "simpleExample": { "title": "Simple Example", - "body": "Imagine an FFN expands a token into two vectors of the same width. One vector carries candidate features. The second goes through SiLU and becomes a gate between roughly zero and the original scale. If one gate entry is small, the matching feature in the value branch is suppressed before projection. If the gate entry is large, that feature passes through more strongly." + "body": "Picture one branch proposing hidden features like possible facts to keep, while the SiLU-gated branch acts like a soft valve that decides how open each feature should be. If the gate is near closed, that candidate feature is damped before the output projection. If the gate is more open, the feature survives more strongly. The important point is that the FFN is still a per-token transform, just with a gated internal path." }, "commonConfusions": { "title": "Common Confusions", - "body": "SwiGLU is not just another name for SiLU. SiLU is the activation on the gate branch, while SwiGLU is the full two-branch FFN pattern built around that activation. SwiGLU also is not mixture of experts: every token still uses the same dense block, so there is no top-k router choosing different experts." + "body": "SwiGLU is not the same thing as plain SiLU. SiLU is an activation that can live inside a standard FFN, while SwiGLU is a gated FFN structure that uses a SiLU-like gate across two branches. It is also not a mixture-of-experts layer: mixture-of-experts routes tokens across different FFN experts, but SwiGLU keeps one shared FFN block and only changes its internal shape." }, "related": { "title": "Related Concepts And Modules" @@ -28,5 +28,5 @@ "title": "References" } }, - "openingSummary": "SwiGLU splits the FFN expansion into value and gate branches, uses SiLU on the gate, and multiplies them together before projection so the block can choose which hidden features stay strong." + "openingSummary": "SwiGLU is a gated FFN: after attention, the block splits into two hidden branches, uses a SiLU-based gate to filter one branch with the other, and then projects the result back down in the same slot where a standard FFN would sit." } diff --git a/src/content/docs/glossary/swiglu/page.mdx b/src/content/docs/glossary/swiglu/page.mdx index 2ac894c5..eb200f22 100644 --- a/src/content/docs/glossary/swiglu/page.mdx +++ b/src/content/docs/glossary/swiglu/page.mdx @@ -1,6 +1,6 @@ --- title: SwiGLU -description: A gated FFN design that splits the hidden expansion into value and gate branches, then uses SiLU to scale the result. +description: A gated FFN variant that uses a SiLU-based gate to control a second hidden branch before projecting back to model width. kind: "glossary" registryId: "concept.swiglu" messageNamespace: "local" @@ -9,9 +9,10 @@ status: "published" tags: - foundations aliases: + - "SwiGLU" + - "Swi GLU" + - "Swish GLU" - "swish gated linear unit" - - "SiLU-gated FFN" - - "SwiGLU FFN" updatedAt: "2026-06-18" --- diff --git a/src/content/registry/concepts/silu.json b/src/content/registry/concepts/silu.json index 5fa025d8..bd95e4c0 100644 --- a/src/content/registry/concepts/silu.json +++ b/src/content/registry/concepts/silu.json @@ -4,13 +4,12 @@ "kind": "concept", "defaultTitleKey": "title", "defaultSummaryKey": "description", - "aliases": ["sigmoid linear unit", "Swish", "SiLU activation"], + "aliases": ["SiLU", "sigmoid linear unit", "swish"], "tags": ["foundations"], "relatedIds": [ "concept.activation", "concept.feed-forward-network", "concept.standard-ffn", - "concept.relu", "concept.swiglu" ], "citationIds": [], diff --git a/src/content/registry/concepts/swiglu.json b/src/content/registry/concepts/swiglu.json index 2c38bf25..d25f76d9 100644 --- a/src/content/registry/concepts/swiglu.json +++ b/src/content/registry/concepts/swiglu.json @@ -4,14 +4,14 @@ "kind": "concept", "defaultTitleKey": "title", "defaultSummaryKey": "description", - "aliases": ["swish gated linear unit", "SiLU-gated FFN", "SwiGLU FFN"], + "aliases": ["SwiGLU", "Swi GLU", "Swish GLU", "swish gated linear unit"], "tags": ["foundations"], "relatedIds": [ + "concept.activation", "concept.feed-forward-network", "concept.standard-ffn", - "concept.mixture-of-experts", "concept.silu", - "concept.activation" + "concept.mixture-of-experts" ], "citationIds": [], "status": "published", diff --git a/src/lib/content/content-paths.ts b/src/lib/content/content-paths.ts index 8cf23a68..6f74bbff 100644 --- a/src/lib/content/content-paths.ts +++ b/src/lib/content/content-paths.ts @@ -173,6 +173,12 @@ export const LEAKY_RELU_GLOSSARY_PAGE_DIR = join( "leaky-relu", ); +/** Phase 3 SiLU glossary page directory. */ +export const SILU_GLOSSARY_PAGE_DIR = join(GLOSSARY_DOCS_ROOT, "silu"); + +/** Phase 3 SwiGLU glossary page directory. */ +export const SWIGLU_GLOSSARY_PAGE_DIR = join(GLOSSARY_DOCS_ROOT, "swiglu"); + /** Phase 3 mixture of experts glossary page directory. */ export const MIXTURE_OF_EXPERTS_GLOSSARY_PAGE_DIR = join( GLOSSARY_DOCS_ROOT, diff --git a/src/lib/content/content-reconciliation-search-documents.test.ts b/src/lib/content/content-reconciliation-search-documents.test.ts new file mode 100644 index 00000000..99752b6e --- /dev/null +++ b/src/lib/content/content-reconciliation-search-documents.test.ts @@ -0,0 +1,178 @@ +import { describe, expect, test } from "bun:test"; +import { loadPublishedDocsPages } from "@/lib/content/pages"; +import { loadRegistry } from "@/lib/content/registry"; +import { buildSearchDocuments } from "@/lib/search/build-documents"; + +/** Batch 017 pages reconciled in Phase 2/3 (see prd.md). */ +const BATCH_017_DOCS_URLS = [ + "/docs/glossary/transformer", + "/docs/glossary/diffusion-model", + "/docs/glossary/multimodal-model", + "/docs/glossary/world-model", + "/docs/modules/attention", + "/docs/modules/multi-head-attention", + "/docs/modules/multi-query-attention", + "/docs/modules/multi-head-latent-attention", + "/docs/modules/sparse-attention", + "/docs/modules/sliding-window-attention", + "/docs/modules/linear-attention", + "/docs/concepts/transformer-architecture", + "/docs/glossary/feed-forward-network", + "/docs/glossary/mixture-of-experts", + "/docs/glossary/normalization", + "/docs/glossary/layer-norm", + "/docs/glossary/rmsnorm", + "/docs/glossary/residual-connection", + "/docs/concepts/positional-encodings", + "/docs/glossary/rope", + "/docs/glossary/alibi", + "/docs/glossary/context-window", + "/docs/concepts/context-extension", + "/docs/concepts/why-long-context-is-hard", + "/docs/glossary/silu", + "/docs/glossary/swiglu", +] as const; + +const BATCH_017_GLOSSARY_URLS = BATCH_017_DOCS_URLS.filter((url) => + url.startsWith("/docs/glossary/"), +); +const BATCH_017_CONCEPT_URLS = BATCH_017_DOCS_URLS.filter((url) => + url.startsWith("/docs/concepts/"), +); +const BATCH_017_MODULE_URLS = BATCH_017_DOCS_URLS.filter((url) => + url.startsWith("/docs/modules/"), +); + +const EXPECTED_ATTENTION_MODULE_URLS = [ + "/docs/modules/attention", + "/docs/modules/multi-head-attention", + "/docs/modules/multi-query-attention", + "/docs/modules/multi-head-latent-attention", + "/docs/modules/sparse-attention", + "/docs/modules/sliding-window-attention", + "/docs/modules/linear-attention", +] as const; + +const ALIAS_EXPECTATIONS = [ + { url: "/docs/modules/multi-head-attention", alias: "MHA" }, + { url: "/docs/modules/multi-query-attention", alias: "MQA" }, + { url: "/docs/modules/sparse-attention", alias: "sparse attention" }, + { url: "/docs/glossary/rope", alias: "RoPE" }, + { url: "/docs/glossary/context-window", alias: "context length" }, + { url: "/docs/glossary/silu", alias: "swish" }, + { url: "/docs/glossary/swiglu", alias: "Swi GLU" }, +] as const; + +describe("Phase 2/3 reconciliation search documents (US-009)", () => { + test("buildSearchDocuments emits one document per batch 017 page with registry-backed fields", async () => { + const registry = await loadRegistry(); + const pages = await loadPublishedDocsPages("en"); + const documents = buildSearchDocuments(pages, registry); + const byUrl = new Map( + documents.map((document) => [document.url, document]), + ); + + for (const url of BATCH_017_DOCS_URLS) { + const document = byUrl.get(url); + const page = pages.find((entry) => entry.url === url); + + expect(document).toBeDefined(); + expect(page).toBeDefined(); + expect(document?.registryId).toBe(page?.frontmatter.registryId); + expect(document?.title).toBe(page?.messages.title); + expect(document?.description).toBe(page?.messages.description); + expect(document?.description.length).toBeGreaterThan(0); + expect(document?.aliases.length).toBeGreaterThan(0); + expect(document?.tags.length).toBeGreaterThan(0); + expect(document?.bodyText.length).toBeGreaterThan(50); + expect(document?.headings.length).toBeGreaterThan(0); + } + }); + + test("batch 017 glossary, concept, and module pages index with matching kind facets", async () => { + const registry = await loadRegistry(); + const pages = await loadPublishedDocsPages("en"); + const documents = buildSearchDocuments(pages, registry); + const byUrl = new Map( + documents.map((document) => [document.url, document]), + ); + + for (const url of BATCH_017_GLOSSARY_URLS) { + const document = byUrl.get(url); + expect(document?.kind).toBe("glossary"); + expect(document?.facets.kind).toBe("glossary"); + } + + for (const url of BATCH_017_CONCEPT_URLS) { + const document = byUrl.get(url); + expect(document?.kind).toBe("concept"); + expect(document?.facets.kind).toBe("concept"); + } + + for (const url of BATCH_017_MODULE_URLS) { + const document = byUrl.get(url); + expect(document?.kind).toBe("module"); + expect(document?.facets.kind).toBe("module"); + } + }); + + test("batch 017 attention modules include moduleType attention and variantGroup when set", async () => { + const registry = await loadRegistry(); + const pages = await loadPublishedDocsPages("en"); + const documents = buildSearchDocuments(pages, registry); + const byUrl = new Map( + documents.map((document) => [document.url, document]), + ); + + for (const url of EXPECTED_ATTENTION_MODULE_URLS) { + const document = byUrl.get(url); + expect(document?.facets.moduleType).toBe("attention"); + expect(document?.tags).toEqual(expect.arrayContaining(["attention"])); + } + + expect( + byUrl.get("/docs/modules/multi-head-attention")?.facets.variantGroup, + ).toBe("attention-head-sharing"); + expect( + byUrl.get("/docs/modules/multi-query-attention")?.facets.variantGroup, + ).toBe("attention-head-sharing"); + expect( + byUrl.get("/docs/modules/multi-head-latent-attention")?.facets + .variantGroup, + ).toBe("attention-head-sharing"); + expect( + byUrl.get("/docs/modules/sparse-attention")?.facets.variantGroup, + ).toBe("sparse-patterns"); + expect( + byUrl.get("/docs/modules/sliding-window-attention")?.facets.variantGroup, + ).toBe("attention-locality"); + expect( + byUrl.get("/docs/modules/linear-attention")?.facets.variantGroup, + ).toBe("subquadratic-attention"); + }); + + test("model-family and transformer-component pages include representative registry aliases", async () => { + const registry = await loadRegistry(); + const pages = await loadPublishedDocsPages("en"); + const documents = buildSearchDocuments(pages, registry); + const byUrl = new Map( + documents.map((document) => [document.url, document]), + ); + + for (const { url, alias } of ALIAS_EXPECTATIONS) { + const document = byUrl.get(url); + expect(document?.aliases).toEqual(expect.arrayContaining([alias])); + } + + for (const url of [ + "/docs/glossary/transformer", + "/docs/glossary/diffusion-model", + "/docs/glossary/multimodal-model", + "/docs/glossary/world-model", + ] as const) { + const document = byUrl.get(url); + expect(document?.kind).toBe("glossary"); + expect(document?.tags).toEqual(expect.arrayContaining(["model-family"])); + } + }); +}); diff --git a/src/lib/content/content-reconciliation-search-queries.test.tsx b/src/lib/content/content-reconciliation-search-queries.test.tsx index ade9758a..487b5fc6 100644 --- a/src/lib/content/content-reconciliation-search-queries.test.tsx +++ b/src/lib/content/content-reconciliation-search-queries.test.tsx @@ -17,21 +17,8 @@ const MULTI_QUERY_ATTENTION_URL = "/docs/modules/multi-query-attention"; const SPARSE_ATTENTION_URL = "/docs/modules/sparse-attention"; const ROPE_GLOSSARY_URL = "/docs/glossary/rope"; const CONTEXT_WINDOW_GLOSSARY_URL = "/docs/glossary/context-window"; -const FEED_FORWARD_NETWORK_GLOSSARY_URL = "/docs/glossary/feed-forward-network"; -const STANDARD_FFN_GLOSSARY_URL = "/docs/glossary/standard-ffn"; -const MIXTURE_OF_EXPERTS_GLOSSARY_URL = "/docs/glossary/mixture-of-experts"; -const RELU_GLOSSARY_URL = "/docs/glossary/relu"; -const LEAKY_RELU_GLOSSARY_URL = "/docs/glossary/leaky-relu"; const SILU_GLOSSARY_URL = "/docs/glossary/silu"; const SWIGLU_GLOSSARY_URL = "/docs/glossary/swiglu"; -const NORMALIZATION_GLOSSARY_URL = "/docs/glossary/normalization"; -const LAYER_NORM_GLOSSARY_URL = "/docs/glossary/layer-norm"; -const BATCH_NORM_GLOSSARY_URL = "/docs/glossary/batch-norm"; -const GROUP_NORM_GLOSSARY_URL = "/docs/glossary/group-norm"; -const RMSNORM_GLOSSARY_URL = "/docs/glossary/rmsnorm"; -const QK_NORM_GLOSSARY_URL = "/docs/glossary/qk-norm"; -const RESIDUAL_CONNECTION_GLOSSARY_URL = "/docs/glossary/residual-connection"; -const SKIP_CONNECTION_GLOSSARY_URL = "/docs/glossary/skip-connection"; const ATTENTION_MODULE_QUERIES = [ { query: "MHA", url: MULTI_HEAD_ATTENTION_URL }, @@ -46,69 +33,8 @@ const GLOSSARY_CANONICAL_QUERIES = [ url: CONTEXT_WINDOW_GLOSSARY_URL, kind: "glossary" as const, }, - { - query: "feed-forward network", - url: FEED_FORWARD_NETWORK_GLOSSARY_URL, - kind: "glossary" as const, - }, - { - query: "standard FFN", - url: STANDARD_FFN_GLOSSARY_URL, - kind: "glossary" as const, - }, - { - query: "mixture of experts", - url: MIXTURE_OF_EXPERTS_GLOSSARY_URL, - kind: "glossary" as const, - }, - { query: "ReLU", url: RELU_GLOSSARY_URL, kind: "glossary" as const }, - { - query: "LeakyReLU", - url: LEAKY_RELU_GLOSSARY_URL, - kind: "glossary" as const, - }, { query: "SiLU", url: SILU_GLOSSARY_URL, kind: "glossary" as const }, { query: "SwiGLU", url: SWIGLU_GLOSSARY_URL, kind: "glossary" as const }, - { - query: "normalization", - url: NORMALIZATION_GLOSSARY_URL, - kind: "glossary" as const, - }, - { - query: "layer norm", - url: LAYER_NORM_GLOSSARY_URL, - kind: "glossary" as const, - }, - { - query: "batch norm", - url: BATCH_NORM_GLOSSARY_URL, - kind: "glossary" as const, - }, - { - query: "group norm", - url: GROUP_NORM_GLOSSARY_URL, - kind: "glossary" as const, - }, - { - query: "RMSNorm", - url: RMSNORM_GLOSSARY_URL, - kind: "glossary" as const, - }, - { - query: "QK norm", - url: QK_NORM_GLOSSARY_URL, - kind: "glossary" as const, - }, - { - query: "residual connection", - url: RESIDUAL_CONNECTION_GLOSSARY_URL, - kind: "glossary" as const, - }, - { - query: "skip connection", - url: SKIP_CONNECTION_GLOSSARY_URL, - kind: "glossary" as const, - }, ] as const; function resultsIncludeUrl( @@ -183,21 +109,8 @@ describe("Phase 2/3 reconciliation search UI kind labels (US-010)", () => { [SPARSE_ATTENTION_URL, "module", "Module"], [ROPE_GLOSSARY_URL, "glossary", "Glossary"], [CONTEXT_WINDOW_GLOSSARY_URL, "glossary", "Glossary"], - [FEED_FORWARD_NETWORK_GLOSSARY_URL, "glossary", "Glossary"], - [STANDARD_FFN_GLOSSARY_URL, "glossary", "Glossary"], - [MIXTURE_OF_EXPERTS_GLOSSARY_URL, "glossary", "Glossary"], - [RELU_GLOSSARY_URL, "glossary", "Glossary"], - [LEAKY_RELU_GLOSSARY_URL, "glossary", "Glossary"], [SILU_GLOSSARY_URL, "glossary", "Glossary"], [SWIGLU_GLOSSARY_URL, "glossary", "Glossary"], - [NORMALIZATION_GLOSSARY_URL, "glossary", "Glossary"], - [LAYER_NORM_GLOSSARY_URL, "glossary", "Glossary"], - [BATCH_NORM_GLOSSARY_URL, "glossary", "Glossary"], - [GROUP_NORM_GLOSSARY_URL, "glossary", "Glossary"], - [RMSNORM_GLOSSARY_URL, "glossary", "Glossary"], - [QK_NORM_GLOSSARY_URL, "glossary", "Glossary"], - [RESIDUAL_CONNECTION_GLOSSARY_URL, "glossary", "Glossary"], - [SKIP_CONNECTION_GLOSSARY_URL, "glossary", "Glossary"], ] as const)("SearchResultMetaDetails shows localized %s kind for %s", async (url, kind, label) => { const messages = await loadUiMessages(); const metaByUrl = searchResultMetaMapToRecord( diff --git a/src/lib/content/content-reconciliation-source-discovery.test.ts b/src/lib/content/content-reconciliation-source-discovery.test.ts new file mode 100644 index 00000000..c04d2581 --- /dev/null +++ b/src/lib/content/content-reconciliation-source-discovery.test.ts @@ -0,0 +1,127 @@ +import { describe, expect, test } from "bun:test"; +import { existsSync } from "node:fs"; +import { join } from "node:path"; +import { DOCS_ROOT } from "@/lib/content/content-paths"; +import { loadPublishedDocsPages } from "@/lib/content/pages"; +import { PUBLISHED_DOCS_REGISTRY_IDS } from "@/lib/content/published-docs-registry-ids"; +import { loadRegistry } from "@/lib/content/registry"; +import { source } from "@/lib/source"; + +/** Batch 017 pages reconciled in Phase 2/3 (see prd.md). */ +const BATCH_017_DOCS_URLS = [ + "/docs/glossary/transformer", + "/docs/glossary/diffusion-model", + "/docs/glossary/multimodal-model", + "/docs/glossary/world-model", + "/docs/modules/attention", + "/docs/modules/multi-head-attention", + "/docs/modules/multi-query-attention", + "/docs/modules/multi-head-latent-attention", + "/docs/modules/sparse-attention", + "/docs/modules/sliding-window-attention", + "/docs/modules/linear-attention", + "/docs/concepts/transformer-architecture", + "/docs/glossary/feed-forward-network", + "/docs/glossary/mixture-of-experts", + "/docs/glossary/normalization", + "/docs/glossary/layer-norm", + "/docs/glossary/rmsnorm", + "/docs/glossary/residual-connection", + "/docs/concepts/positional-encodings", + "/docs/glossary/rope", + "/docs/glossary/alibi", + "/docs/glossary/context-window", + "/docs/concepts/context-extension", + "/docs/concepts/why-long-context-is-hard", + "/docs/glossary/silu", + "/docs/glossary/swiglu", +] as const; + +function docsSlugFromUrl(url: string): string[] { + return url.replace("/docs/", "").split("/"); +} + +describe("Phase 2/3 reconciliation source discovery (US-002)", () => { + test("loadPublishedDocsPages includes every batch 017 glossary, concept, and module URL", async () => { + const pages = await loadPublishedDocsPages("en"); + const urls = new Set(pages.map((page) => page.url)); + + for (const url of BATCH_017_DOCS_URLS) { + expect(urls).toContain(url); + } + }); + + test("Fumadocs source resolves every batch 017 page slug", () => { + for (const url of BATCH_017_DOCS_URLS) { + const slug = docsSlugFromUrl(url); + const page = source.getPage(slug); + expect(page).toBeDefined(); + expect(page?.url).toBe(url); + } + }); + + test("Fumadocs generateParams includes every batch 017 slug path", () => { + const slugPaths = new Set( + source.generateParams().map((entry) => entry.slug.join("/")), + ); + + for (const url of BATCH_017_DOCS_URLS) { + const slugPath = url.replace("/docs/", ""); + expect(slugPaths.has(slugPath)).toBe(true); + } + }); + + test("every published docs registry id has a routable MDX bundle on disk", async () => { + const pages = await loadPublishedDocsPages("en"); + const pageByRegistryId = new Map( + pages.map((page) => [page.frontmatter.registryId, page]), + ); + + for (const registryId of PUBLISHED_DOCS_REGISTRY_IDS) { + const page = pageByRegistryId.get(registryId); + expect(page).toBeDefined(); + expect(existsSync(join(page?.pageDir ?? "", "page.mdx"))).toBe(true); + } + }); + + test("published module and concept registry records with docs pages resolve through source", async () => { + const indexes = await loadRegistry(); + const pages = await loadPublishedDocsPages("en"); + const pageByRegistryId = new Map( + pages.map((page) => [page.frontmatter.registryId, page]), + ); + + for (const record of indexes.byId.values()) { + if (record.status !== "published") { + continue; + } + if (record.kind !== "module" && record.kind !== "concept") { + continue; + } + if (!PUBLISHED_DOCS_REGISTRY_IDS.has(record.id)) { + continue; + } + + const page = pageByRegistryId.get(record.id); + expect(page).toBeDefined(); + + const slug = page?.docsSlug.split("/") ?? []; + expect(source.getPage(slug)).toBeDefined(); + expect(page?.url.startsWith("/docs/")).toBe(true); + expect(page?.pageDir.startsWith(DOCS_ROOT)).toBe(true); + } + }); + + test("every published docs page resolves through Fumadocs source and generateParams", async () => { + const pages = await loadPublishedDocsPages("en"); + const slugPaths = new Set( + source.generateParams().map((entry) => entry.slug.join("/")), + ); + + for (const page of pages) { + const slug = page.docsSlug.split("/"); + expect(source.getPage(slug)).toBeDefined(); + expect(slugPaths.has(page.docsSlug)).toBe(true); + } + }); +}); diff --git a/src/lib/content/phase-2-3-reconciliation-convergence.ts b/src/lib/content/phase-2-3-reconciliation-convergence.ts index 266414a8..247e9348 100644 --- a/src/lib/content/phase-2-3-reconciliation-convergence.ts +++ b/src/lib/content/phase-2-3-reconciliation-convergence.ts @@ -72,6 +72,8 @@ export const BATCH_017_DOCS_URLS = [ "/docs/glossary/context-window", "/docs/concepts/context-extension", "/docs/concepts/why-long-context-is-hard", + "/docs/glossary/silu", + "/docs/glossary/swiglu", ] as const; const MODEL_FAMILY_REGISTRY_IDS = [ @@ -199,6 +201,16 @@ const REPRESENTATIVE_SEARCH_QUERY_EXPECTATIONS = [ firstUrl: "/docs/glossary/context-window", firstKind: "glossary" as const, }, + { + query: "SiLU", + firstUrl: "/docs/glossary/silu", + firstKind: "glossary" as const, + }, + { + query: "SwiGLU", + firstUrl: "/docs/glossary/swiglu", + firstKind: "glossary" as const, + }, ] as const; function docsSlugFromUrl(url: string): string[] { diff --git a/src/lib/content/published-docs-registry-ids.ts b/src/lib/content/published-docs-registry-ids.ts index a01c6e50..31006866 100644 --- a/src/lib/content/published-docs-registry-ids.ts +++ b/src/lib/content/published-docs-registry-ids.ts @@ -85,6 +85,8 @@ export const PUBLISHED_DOCS_REGISTRY_IDS = new Set([ "concept.standard-ffn", "concept.relu", "concept.leaky-relu", + "concept.silu", + "concept.swiglu", "concept.mixture-of-experts", "concept.relu", "concept.leaky-relu", diff --git a/src/lib/content/silu-swiglu-glossary.test.ts b/src/lib/content/silu-swiglu-glossary.test.ts new file mode 100644 index 00000000..6e01d98e --- /dev/null +++ b/src/lib/content/silu-swiglu-glossary.test.ts @@ -0,0 +1,228 @@ +import { describe, expect, test } from "bun:test"; +import { readFileSync } from "node:fs"; +import { join } from "node:path"; +import { createElement } from "react"; +import { renderToStaticMarkup } from "react-dom/server"; +import { ModulePageProviders } from "@/features/docs/components/ModulePageProviders"; +import { + SILU_GLOSSARY_PAGE_DIR, + SWIGLU_GLOSSARY_PAGE_DIR, +} from "@/lib/content/content-paths"; +import { loadPublishedGlossaryEntries } from "@/lib/content/glossary"; +import { loadGlossaryPage } from "@/lib/content/glossary-page"; +import { + expectGlossaryPresentationConvergence, + expectHtmlToContainProse, +} from "@/lib/content/glossary-test-helpers"; +import { loadPublishedDocsPages } from "@/lib/content/pages"; +import { PUBLISHED_DOCS_REGISTRY_IDS } from "@/lib/content/published-docs-registry-ids"; +import { loadRegistry } from "@/lib/content/registry"; +import { + getConceptById, + listRelatedRegistryRecords, +} from "@/lib/content/registry-runtime"; +import { deriveCuratedRelatedItems } from "@/lib/content/related-docs"; +import { pageMessagesSchema } from "@/lib/content/schemas"; +import { buildSearchDocuments } from "@/lib/search/build-documents"; +import { pageBaseUrl } from "@/lib/search/collapse-search-results-to-page-hits"; +import { docsSearchApi } from "@/lib/search/search-server"; + +const SILU_GLOSSARY_URL = "/docs/glossary/silu"; +const SWIGLU_GLOSSARY_URL = "/docs/glossary/swiglu"; + +const pageFixtures = [ + { + registryId: "concept.silu", + title: "SiLU", + url: SILU_GLOSSARY_URL, + pageDir: SILU_GLOSSARY_PAGE_DIR, + aliases: ["SiLU", "sigmoid linear unit", "swish"], + relatedIds: [ + "concept.activation", + "concept.feed-forward-network", + "concept.standard-ffn", + "concept.swiglu", + ], + prose: "soft gate", + comparisonTerm: "swiglu", + }, + { + registryId: "concept.swiglu", + title: "SwiGLU", + url: SWIGLU_GLOSSARY_URL, + pageDir: SWIGLU_GLOSSARY_PAGE_DIR, + aliases: ["SwiGLU", "Swi GLU", "Swish GLU", "swish gated linear unit"], + relatedIds: [ + "concept.activation", + "concept.feed-forward-network", + "concept.standard-ffn", + "concept.silu", + "concept.mixture-of-experts", + ], + prose: "two hidden branches", + comparisonTerm: "mixture-of-experts", + }, +] as const; + +describe("FFN pages from phase 3 SiLU and SwiGLU glossary pages (US-003)", () => { + for (const fixture of pageFixtures) { + test(`${fixture.title} registry record is published with aliases and curated related ids`, () => { + const { registryId, aliases, relatedIds } = fixture; + const record = getConceptById(registryId); + expect(record?.status).toBe("published"); + expect(record?.aliases).toEqual([...aliases]); + expect(record?.tags).toEqual(["foundations"]); + expect(record?.relatedIds).toEqual([...relatedIds]); + expect(PUBLISHED_DOCS_REGISTRY_IDS.has(registryId)).toBe(true); + }); + + test(`${fixture.title} curated related links connect FFN foundations and nearby variants`, () => { + const { registryId, relatedIds } = fixture; + const source = getConceptById(registryId); + if (!source) { + throw new Error(`expected ${registryId} in registry`); + } + + const items = deriveCuratedRelatedItems( + source, + listRelatedRegistryRecords(), + PUBLISHED_DOCS_REGISTRY_IDS, + ); + + for (const relatedId of relatedIds) { + const item = items.find( + (candidate) => candidate.registryId === relatedId, + ); + expect(item?.isPlanned).toBe(false); + } + + expect( + items.find((item) => item.registryId === "concept.activation")?.href, + ).toBe("/docs/glossary/activation"); + expect( + items.find((item) => item.registryId === "concept.feed-forward-network") + ?.href, + ).toBe("/docs/glossary/feed-forward-network"); + expect( + items.find((item) => item.registryId === "concept.standard-ffn")?.href, + ).toBe("/docs/glossary/standard-ffn"); + }); + } + + test("messages explain SiLU's smooth gate and SwiGLU's gated FFN structure", () => { + const siluMessages = pageMessagesSchema.parse( + JSON.parse( + readFileSync(join(SILU_GLOSSARY_PAGE_DIR, "messages/en.json"), "utf8"), + ), + ); + const swigluMessages = pageMessagesSchema.parse( + JSON.parse( + readFileSync( + join(SWIGLU_GLOSSARY_PAGE_DIR, "messages/en.json"), + "utf8", + ), + ), + ); + + expect(siluMessages.sections?.whatItIs.body?.toLowerCase()).toContain( + "smooth", + ); + expect(siluMessages.sections?.whatItIs.body?.toLowerCase()).toContain( + "ffn", + ); + expect( + siluMessages.sections?.commonConfusions.body?.toLowerCase(), + ).toContain("swiglu"); + + expect(swigluMessages.sections?.whatItIs.body?.toLowerCase()).toContain( + "two hidden branches", + ); + expect(swigluMessages.sections?.whyItMatters.body?.toLowerCase()).toContain( + "standard ffn", + ); + expect( + swigluMessages.sections?.commonConfusions.body?.toLowerCase(), + ).toContain("mixture-of-experts"); + expect( + swigluMessages.sections?.commonConfusions.body?.toLowerCase(), + ).toContain("silu"); + }); + + for (const fixture of pageFixtures) { + test(`${fixture.title} page renders required sections, tag pill, and FFN-family related links`, async () => { + const { registryId, title, url, prose, comparisonTerm } = fixture; + const slug = url.split("/").at(-1); + if (!slug) { + throw new Error(`missing slug for ${url}`); + } + + const page = await loadGlossaryPage(slug); + + expect(page.frontmatter.kind).toBe("glossary"); + expect(page.frontmatter.status).toBe("published"); + expect(page.frontmatter.registryId).toBe(registryId); + + const html = renderToStaticMarkup( + createElement(ModulePageProviders, { + messages: page.messages, + assets: page.assets, + // biome-ignore lint/correctness/noChildrenProp: third createElement arg conflicts with strict props typing + children: page.content, + }), + ); + + expectGlossaryPresentationConvergence(html, { + title, + }); + expect(html).toContain("What It Is"); + expect(html).toContain("Common Confusions"); + expectHtmlToContainProse(html, prose); + expect(html).toContain('href="/docs/glossary/activation"'); + expect(html).toContain('href="/docs/glossary/feed-forward-network"'); + expect(html).toContain('href="/docs/glossary/standard-ffn"'); + expect(html).toContain('href="/tags/foundations"'); + expect(html).toContain('data-testid="tag-pill-list"'); + expect(html).toContain('data-testid="curated-related-docs"'); + expect(html.toLowerCase()).toContain(comparisonTerm); + expect(html).not.toContain("Phase"); + expect(html).not.toContain("Reader Shortcut"); + }); + } + + test("glossary browse index includes SiLU and SwiGLU with summaries", async () => { + const entries = await loadPublishedGlossaryEntries("en"); + const entryByUrl = new Map(entries.map((entry) => [entry.url, entry])); + + const silu = entryByUrl.get(SILU_GLOSSARY_URL); + expect(silu?.title).toBe("SiLU"); + expect(silu?.summary.length).toBeGreaterThan(0); + + const swiglu = entryByUrl.get(SWIGLU_GLOSSARY_URL); + expect(swiglu?.title).toBe("SwiGLU"); + expect(swiglu?.summary.length).toBeGreaterThan(0); + }); + + test("search documents and canonical queries resolve to the SiLU-family pages", async () => { + const registry = await loadRegistry(); + const pages = await loadPublishedDocsPages("en"); + const documents = buildSearchDocuments(pages, registry); + + const silu = documents.find((entry) => entry.url === SILU_GLOSSARY_URL); + expect(silu?.kind).toBe("glossary"); + expect(silu?.aliases).toEqual( + expect.arrayContaining(["SiLU", "sigmoid linear unit", "swish"]), + ); + + const swiglu = documents.find((entry) => entry.url === SWIGLU_GLOSSARY_URL); + expect(swiglu?.kind).toBe("glossary"); + expect(swiglu?.aliases).toEqual( + expect.arrayContaining(["SwiGLU", "Swi GLU", "Swish GLU"]), + ); + + const siluResults = await docsSearchApi.search("SiLU"); + expect(pageBaseUrl(siluResults[0]?.url ?? "")).toBe(SILU_GLOSSARY_URL); + + const swigluResults = await docsSearchApi.search("SwiGLU"); + expect(pageBaseUrl(swigluResults[0]?.url ?? "")).toBe(SWIGLU_GLOSSARY_URL); + }); +}); diff --git a/src/lib/source.test.ts b/src/lib/source.test.ts index a5bb4a0e..1b9148df 100644 --- a/src/lib/source.test.ts +++ b/src/lib/source.test.ts @@ -40,6 +40,7 @@ const GLOSSARY_INDEX_URLS = [ "/docs/glossary/skip-connection", "/docs/glossary/rope", "/docs/glossary/rmsnorm", + "/docs/glossary/silu", "/docs/glossary/overfitting", "/docs/glossary/patch", "/docs/glossary/perplexity", @@ -52,6 +53,7 @@ const GLOSSARY_INDEX_URLS = [ "/docs/glossary/representation", "/docs/glossary/scaling-law", "/docs/glossary/standard-ffn", + "/docs/glossary/swiglu", "/docs/glossary/token", "/docs/glossary/transformer", "/docs/glossary/world-model", From 898cab1c96886470eac274df81a08da546ae9460 Mon Sep 17 00:00:00 2001 From: aabdi Date: Thu, 18 Jun 2026 09:32:41 +0700 Subject: [PATCH 4/5] feat: [ffn-pages-from-phase-3-004] - [Make the FFN variant family navigable and searchable] --- .../docs/glossary/activation/messages/en.json | 4 +- .../feed-forward-network/messages/en.json | 4 +- .../mixture-of-experts/messages/en.json | 4 +- src/content/registry/concepts/activation.json | 11 ++- .../registry/concepts/mixture-of-experts.json | 2 + .../ffn-variant-family-navigation.test.ts | 90 +++++++++++++++++++ .../mixture-of-experts-glossary.test.ts | 16 +++- ...-chain-parameter-activation-graph.test.tsx | 17 +++- 8 files changed, 139 insertions(+), 9 deletions(-) create mode 100644 src/lib/content/ffn-variant-family-navigation.test.ts diff --git a/src/content/docs/glossary/activation/messages/en.json b/src/content/docs/glossary/activation/messages/en.json index 2b157cdf..2ccf83eb 100644 --- a/src/content/docs/glossary/activation/messages/en.json +++ b/src/content/docs/glossary/activation/messages/en.json @@ -8,7 +8,7 @@ }, "whyItMatters": { "title": "Why It Matters", - "body": "Activations determine what information reaches the next layer and what backpropagation will differentiate. Memory planners track activation tensors during training because they are large but temporary, unlike checkpointed parameters." + "body": "Activations determine what information reaches the next layer and what backpropagation will differentiate. Memory planners track activation tensors during training because they are large but temporary, unlike checkpointed parameters. This page is the broad foundation for that idea; pages like ReLU, LeakyReLU, and SiLU zoom in on specific FFN activation choices, while SwiGLU shows how gating can turn that idea into a different FFN block shape." }, "simpleExample": { "title": "Simple Example", @@ -20,7 +20,7 @@ }, "commonConfusions": { "title": "Common Confusions", - "body": "A hidden activation is not the same as softmax: softmax turns vocabulary logits into a probability vector at the output head, while activations are internal layer outputs that may never be normalized across the vocabulary. Saying a “ReLU activation” refers to the nonlinearity applied inside a layer, not to the softmax step at decode time." + "body": "A hidden activation is not the same as softmax: softmax turns vocabulary logits into a probability vector at the output head, while activations are internal layer outputs that may never be normalized across the vocabulary. Saying a “ReLU activation” refers to one specific nonlinearity that shapes FFN activations, not to the softmax step at decode time. ReLU, LeakyReLU, and SiLU are specific activation choices; SwiGLU goes one step further and changes the FFN into a gated two-branch block." }, "related": { "title": "Related Concepts And Modules" diff --git a/src/content/docs/glossary/feed-forward-network/messages/en.json b/src/content/docs/glossary/feed-forward-network/messages/en.json index 00752b8a..572d1ac7 100644 --- a/src/content/docs/glossary/feed-forward-network/messages/en.json +++ b/src/content/docs/glossary/feed-forward-network/messages/en.json @@ -8,7 +8,7 @@ }, "whyItMatters": { "title": "Why It Matters", - "body": "Attention decides what each position can read from the sequence; the FFN decides how to transform what was read into richer features. Most transformer blocks alternate these two steps, so recognizing the FFN slot helps you read architecture diagrams and spot when a model swaps a dense MLP for a mixture-of-experts layer while keeping the block shape." + "body": "Attention decides what each position can read from the sequence; the FFN decides how to transform what was read into richer features. Most transformer blocks alternate these two steps, so recognizing the FFN slot helps you read architecture diagrams and spot when a model swaps a dense MLP for a mixture-of-experts layer while keeping the block shape. This page is the broad map of that slot; nearby pages like Standard FFN, ReLU, SiLU, and SwiGLU zoom in on one default block shape or one activation-driven variant inside it." }, "simpleExample": { "title": "Simple Example", @@ -16,7 +16,7 @@ }, "commonConfusions": { "title": "Common Confusions", - "body": "The FFN is not attention: it does not look at other tokens. It is also not the language-model head at the stack top—that head maps final hidden states to vocabulary logits. A mixture-of-experts layer replaces the dense FFN with routed expert MLPs but still sits in the same block slot after attention." + "body": "The FFN is not attention: it does not look at other tokens. It is also not the language-model head at the stack top—that head maps final hidden states to vocabulary logits. Standard FFN is the default dense version of this slot, while ReLU, LeakyReLU, and SiLU name different nonlinearities that can live inside it. SwiGLU changes the internal FFN shape with gating, and a mixture-of-experts layer replaces one shared dense path with routed expert MLPs while still sitting in the same block slot after attention." }, "related": { "title": "Related Concepts And Modules" diff --git a/src/content/docs/glossary/mixture-of-experts/messages/en.json b/src/content/docs/glossary/mixture-of-experts/messages/en.json index 18f47c1a..41b3e79c 100644 --- a/src/content/docs/glossary/mixture-of-experts/messages/en.json +++ b/src/content/docs/glossary/mixture-of-experts/messages/en.json @@ -8,7 +8,7 @@ }, "whyItMatters": { "title": "Why It Matters", - "body": "MoE increases total parameter count while keeping compute per token roughly flat, because only a few experts activate per step. That tradeoff matters when scaling language models: you can add capacity without multiplying FLOPs for every position. Capacity limits, load balancing, and routing noise also shape training stability, so recognizing MoE helps you read model cards that list expert counts and top-k routing." + "body": "MoE increases total parameter count while keeping compute per token roughly flat, because only a few experts activate per step. That tradeoff matters when scaling language models: you can add capacity without multiplying FLOPs for every position. Capacity limits, load balancing, and routing noise also shape training stability, so recognizing MoE helps you read model cards that list expert counts and top-k routing. It also helps to see where MoE sits relative to the rest of the FFN family: it replaces the default dense block in the usual transformer slot rather than adding a whole new stage elsewhere." }, "simpleExample": { "title": "Simple Example", @@ -16,7 +16,7 @@ }, "commonConfusions": { "title": "Common Confusions", - "body": "MoE is not a model ensemble: ensembles combine separate full models at inference, while MoE keeps one shared stack and only sparsely activates internal experts. MoE is also not the same as a dense FFN—both sit after attention in the block, but dense FFN runs one MLP for every token whereas MoE selects a small subset. Finally, total expert parameters are not all used on every forward pass; active compute tracks top-k, not the full expert pool." + "body": "MoE is not a model ensemble: ensembles combine separate full models at inference, while MoE keeps one shared stack and only sparsely activates internal experts. MoE is also not the same as a dense FFN—both sit after attention in the block, but dense FFN runs one MLP for every token whereas MoE selects a small subset. SwiGLU is another FFN variant, but it keeps one shared gated dense block rather than routing tokens across experts. Finally, total expert parameters are not all used on every forward pass; active compute tracks top-k, not the full expert pool." }, "related": { "title": "Related Concepts And Modules" diff --git a/src/content/registry/concepts/activation.json b/src/content/registry/concepts/activation.json index 0aacb8e0..4a27d390 100644 --- a/src/content/registry/concepts/activation.json +++ b/src/content/registry/concepts/activation.json @@ -6,7 +6,16 @@ "defaultSummaryKey": "description", "aliases": ["activations", "hidden activation", "layer output"], "tags": ["token-to-probability-chain", "foundations"], - "relatedIds": ["concept.computational-graph", "concept.quantization"], + "relatedIds": [ + "concept.feed-forward-network", + "concept.standard-ffn", + "concept.relu", + "concept.leaky-relu", + "concept.silu", + "concept.swiglu", + "concept.computational-graph", + "concept.quantization" + ], "citationIds": [], "status": "published", "createdAt": "2026-06-04T00:00:00.000Z", diff --git a/src/content/registry/concepts/mixture-of-experts.json b/src/content/registry/concepts/mixture-of-experts.json index b71a435e..3db5cb7c 100644 --- a/src/content/registry/concepts/mixture-of-experts.json +++ b/src/content/registry/concepts/mixture-of-experts.json @@ -9,6 +9,8 @@ "relatedIds": [ "concept.feed-forward-network", "concept.standard-ffn", + "concept.swiglu", + "concept.activation", "concept.transformer-architecture" ], "citationIds": [], diff --git a/src/lib/content/ffn-variant-family-navigation.test.ts b/src/lib/content/ffn-variant-family-navigation.test.ts new file mode 100644 index 00000000..b5270a90 --- /dev/null +++ b/src/lib/content/ffn-variant-family-navigation.test.ts @@ -0,0 +1,90 @@ +import { describe, expect, test } from "bun:test"; +import { PUBLISHED_DOCS_REGISTRY_IDS } from "@/lib/content/published-docs-registry-ids"; +import { + getConceptById, + listRelatedRegistryRecords, +} from "@/lib/content/registry-runtime"; +import { deriveCuratedRelatedItems } from "@/lib/content/related-docs"; +import { pageBaseUrl } from "@/lib/search/collapse-search-results-to-page-hits"; +import { docsSearchApi } from "@/lib/search/search-server"; + +const FFN_FAMILY_IDS = [ + "concept.feed-forward-network", + "concept.activation", + "concept.standard-ffn", + "concept.relu", + "concept.leaky-relu", + "concept.silu", + "concept.swiglu", + "concept.mixture-of-experts", +] as const; + +const FFN_FAMILY_ID_SET = new Set(FFN_FAMILY_IDS); + +const SEARCH_EXPECTATIONS = [ + { query: "standard FFN", url: "/docs/glossary/standard-ffn" }, + { query: "ReLU", url: "/docs/glossary/relu" }, + { query: "LeakyReLU", url: "/docs/glossary/leaky-relu" }, + { query: "SiLU", url: "/docs/glossary/silu" }, + { query: "SwiGLU", url: "/docs/glossary/swiglu" }, +] as const; + +describe("FFN variant family navigation and search (US-004)", () => { + test("every FFN family page exposes at least one published in-family related doc link", () => { + const candidates = listRelatedRegistryRecords(); + + for (const registryId of FFN_FAMILY_IDS) { + const source = getConceptById(registryId); + expect(source).toBeDefined(); + if (!source) { + continue; + } + + const familyItems = deriveCuratedRelatedItems( + source, + candidates, + PUBLISHED_DOCS_REGISTRY_IDS, + ).filter((item) => FFN_FAMILY_ID_SET.has(item.registryId)); + + expect(familyItems.length).toBeGreaterThan(0); + + for (const item of familyItems) { + expect(item.isPlanned).toBe(false); + expect(item.href).toMatch(/^\/docs\//); + } + } + }); + + test("activation and feed-forward-network act as broad entry pages that can reach the whole FFN family cluster", () => { + const queue = ["concept.activation", "concept.feed-forward-network"]; + const visited = new Set(); + + while (queue.length > 0) { + const registryId = queue.shift(); + if (!registryId || visited.has(registryId)) { + continue; + } + + visited.add(registryId); + const source = getConceptById(registryId); + if (!source) { + continue; + } + + for (const relatedId of source.relatedIds) { + if (FFN_FAMILY_ID_SET.has(relatedId) && !visited.has(relatedId)) { + queue.push(relatedId); + } + } + } + + expect(visited).toEqual(new Set(FFN_FAMILY_IDS)); + }); + + test("representative FFN family searches return the canonical page first", async () => { + for (const { query, url } of SEARCH_EXPECTATIONS) { + const results = await docsSearchApi.search(query); + expect(pageBaseUrl(results[0]?.url ?? "")).toBe(url); + } + }); +}); diff --git a/src/lib/content/mixture-of-experts-glossary.test.ts b/src/lib/content/mixture-of-experts-glossary.test.ts index d5f7029c..d738861a 100644 --- a/src/lib/content/mixture-of-experts-glossary.test.ts +++ b/src/lib/content/mixture-of-experts-glossary.test.ts @@ -37,6 +37,8 @@ describe("Phase 3 mixture of experts glossary page (US-003)", () => { expect(record?.relatedIds).toEqual([ "concept.feed-forward-network", "concept.standard-ffn", + "concept.swiglu", + "concept.activation", "concept.transformer-architecture", ]); expect(PUBLISHED_DOCS_REGISTRY_IDS.has("concept.mixture-of-experts")).toBe( @@ -44,7 +46,7 @@ describe("Phase 3 mixture of experts glossary page (US-003)", () => { ); }); - test("curated related links feed-forward network, standard FFN, and transformer architecture", () => { + test("curated related links contrast MoE with the dense and gated FFN family", () => { const source = getConceptById("concept.mixture-of-experts"); if (!source) { throw new Error("expected concept.mixture-of-experts in registry"); @@ -68,6 +70,16 @@ describe("Phase 3 mixture of experts glossary page (US-003)", () => { expect(standardFfn?.href).toBe("/docs/glossary/standard-ffn"); expect(standardFfn?.isPlanned).toBe(false); + const swiglu = items.find((item) => item.registryId === "concept.swiglu"); + expect(swiglu?.href).toBe("/docs/glossary/swiglu"); + expect(swiglu?.isPlanned).toBe(false); + + const activation = items.find( + (item) => item.registryId === "concept.activation", + ); + expect(activation?.href).toBe("/docs/glossary/activation"); + expect(activation?.isPlanned).toBe(false); + const architecture = items.find( (item) => item.registryId === "concept.transformer-architecture", ); @@ -119,6 +131,8 @@ describe("Phase 3 mixture of experts glossary page (US-003)", () => { expectHtmlToContainProse(html, "gating network"); expect(html).toContain('href="/docs/glossary/feed-forward-network"'); expect(html).toContain('href="/docs/glossary/standard-ffn"'); + expect(html).toContain('href="/docs/glossary/swiglu"'); + expect(html).toContain('href="/docs/glossary/activation"'); expect(html).toContain('href="/docs/concepts/transformer-architecture"'); expect(html).toContain('href="/tags/foundations"'); expect(html).toContain('data-testid="tag-pill-list"'); diff --git a/src/lib/content/token-to-probability-chain-parameter-activation-graph.test.tsx b/src/lib/content/token-to-probability-chain-parameter-activation-graph.test.tsx index 7b171011..91a02d39 100644 --- a/src/lib/content/token-to-probability-chain-parameter-activation-graph.test.tsx +++ b/src/lib/content/token-to-probability-chain-parameter-activation-graph.test.tsx @@ -29,6 +29,12 @@ describe("Phase 2 parameter, activation, and computational graph glossary pages expect(parameter?.prerequisiteIds).toContain("concept.softmax"); expect(parameter?.relatedIds).toContain("concept.activation"); expect(activation?.prerequisiteIds).toContain("concept.parameter"); + expect(activation?.relatedIds).toContain("concept.feed-forward-network"); + expect(activation?.relatedIds).toContain("concept.standard-ffn"); + expect(activation?.relatedIds).toContain("concept.relu"); + expect(activation?.relatedIds).toContain("concept.leaky-relu"); + expect(activation?.relatedIds).toContain("concept.silu"); + expect(activation?.relatedIds).toContain("concept.swiglu"); expect(activation?.relatedIds).toContain("concept.computational-graph"); expect(graph?.prerequisiteIds).toContain("concept.activation"); expect(graph?.relatedIds).toContain("concept.gradient"); @@ -55,7 +61,7 @@ describe("Phase 2 parameter, activation, and computational graph glossary pages expect(html).toContain(DERIVED_RELATED_DOC_GROUP_LABELS[CURATED_RELATED]); }); - test("activation page distinguishes activations from softmax and links to computational graph", async () => { + test("activation page distinguishes activations from softmax and links into the FFN variant family", async () => { const page = await loadGlossaryPage("activation"); expect(page.frontmatter.status).toBe("published"); @@ -71,6 +77,15 @@ describe("Phase 2 parameter, activation, and computational graph glossary pages expect(html).toContain("Activation"); expect(html).toContain("What It Is"); expect(html).toContain("not the same as softmax"); + expect(html).toContain(">ReLU<"); + expect(html).toContain(">LeakyReLU<"); + expect(html).toContain(">SiLU<"); + expect(html).toContain('href="/docs/glossary/feed-forward-network"'); + expect(html).toContain('href="/docs/glossary/standard-ffn"'); + expect(html).toContain('href="/docs/glossary/relu"'); + expect(html).toContain('href="/docs/glossary/leaky-relu"'); + expect(html).toContain('href="/docs/glossary/silu"'); + expect(html).toContain('href="/docs/glossary/swiglu"'); expect(html).toContain('href="/docs/glossary/computational-graph"'); expect(html).toContain(DERIVED_RELATED_DOC_GROUP_LABELS[CURATED_RELATED]); }); From 158981d18e1d4a37ea921ad197952fac3ea75be2 Mon Sep 17 00:00:00 2001 From: aabdi Date: Thu, 18 Jun 2026 11:17:58 +0700 Subject: [PATCH 5/5] feat: [ffn-pages-from-phase-3-004] - [Make the FFN variant family navigable and searchable] --- src/content/docs/glossary/meta.json | 12 + .../activation-family-glossary.test.ts | 235 ------------------ src/lib/content/content-paths.ts | 15 -- .../glossary-architecture-index.test.ts | 171 +++++++++---- .../glossary-opening-convergence.test.tsx | 2 +- ...ssary-shell-description-auto-link.test.tsx | 132 ++++++++-- src/lib/content/registry-runtime.test.ts | 13 +- src/lib/content/registry-runtime.ts | 44 +++- src/lib/source.test.ts | 7 +- src/tests/content/architecture-index.test.ts | 28 ++- src/tests/content/glossary-index.test.ts | 71 ++++-- src/tests/search/orama-index.test.ts | 63 ++++- 12 files changed, 432 insertions(+), 361 deletions(-) delete mode 100644 src/lib/content/activation-family-glossary.test.ts diff --git a/src/content/docs/glossary/meta.json b/src/content/docs/glossary/meta.json index 6313c5b7..6579c6a2 100644 --- a/src/content/docs/glossary/meta.json +++ b/src/content/docs/glossary/meta.json @@ -21,19 +21,27 @@ "[ALiBi](/docs/glossary/alibi)", "[Context window](/docs/glossary/context-window)", "[Decoder](/docs/glossary/decoder)", + "[Decode](/docs/glossary/decode)", "[Encoder](/docs/glossary/encoder)", "[Encoder-Decoder](/docs/glossary/encoder-decoder)", "[Feed-forward network](/docs/glossary/feed-forward-network)", + "[Batch norm](/docs/glossary/batch-norm)", + "[Group norm](/docs/glossary/group-norm)", "[Hidden Size](/docs/glossary/hidden-size)", + "[KV cache](/docs/glossary/kv-cache)", "[Layer norm](/docs/glossary/layer-norm)", "[LeakyReLU](/docs/glossary/leaky-relu)", "[Mixture of experts](/docs/glossary/mixture-of-experts)", "[Normalization](/docs/glossary/normalization)", + "[Prefill](/docs/glossary/prefill)", + "[Prefill/decode split](/docs/glossary/prefill-decode-split)", "[Perplexity](/docs/glossary/perplexity)", + "[QK norm](/docs/glossary/qk-norm)", "[ReLU](/docs/glossary/relu)", "[RoPE](/docs/glossary/rope)", "[RMSNorm](/docs/glossary/rmsnorm)", "[Residual connection](/docs/glossary/residual-connection)", + "[Skip connection](/docs/glossary/skip-connection)", "[SiLU](/docs/glossary/silu)", "[Standard FFN](/docs/glossary/standard-ffn)", "[SwiGLU](/docs/glossary/swiglu)", @@ -61,6 +69,10 @@ "[Vector](/docs/glossary/vector)", "---Generation And Diffusion---", "[Autoregressive Generation](/docs/glossary/autoregressive-generation)", + "[Greedy Decoding](/docs/glossary/greedy-decoding)", + "[Sampling Overview](/docs/glossary/sampling-overview)", + "[Top-K Sampling](/docs/glossary/top-k-sampling)", + "[Top-P Sampling](/docs/glossary/top-p-sampling)", "[Conditioning](/docs/glossary/conditioning)", "[Denoising Generation](/docs/glossary/denoising-generation)", "[Diffusion Model](/docs/glossary/diffusion-model)" diff --git a/src/lib/content/activation-family-glossary.test.ts b/src/lib/content/activation-family-glossary.test.ts deleted file mode 100644 index ed553c81..00000000 --- a/src/lib/content/activation-family-glossary.test.ts +++ /dev/null @@ -1,235 +0,0 @@ -import { describe, expect, test } from "bun:test"; -import { readFileSync } from "node:fs"; -import { join } from "node:path"; -import { createElement } from "react"; -import { renderToStaticMarkup } from "react-dom/server"; -import { ModulePageProviders } from "@/features/docs/components/ModulePageProviders"; -import { - LEAKY_RELU_GLOSSARY_PAGE_DIR, - RELU_GLOSSARY_PAGE_DIR, - SILU_GLOSSARY_PAGE_DIR, - SWIGLU_GLOSSARY_PAGE_DIR, -} from "@/lib/content/content-paths"; -import { loadGlossaryPage } from "@/lib/content/glossary-page"; -import { - expectGlossaryPresentationConvergence, - expectHtmlToContainProse, -} from "@/lib/content/glossary-test-helpers"; -import { loadPublishedDocsPages } from "@/lib/content/pages"; -import { PUBLISHED_DOCS_REGISTRY_IDS } from "@/lib/content/published-docs-registry-ids"; -import { loadRegistry } from "@/lib/content/registry"; -import { - getConceptById, - listRelatedRegistryRecords, -} from "@/lib/content/registry-runtime"; -import { deriveCuratedRelatedItems } from "@/lib/content/related-docs"; -import { pageMessagesSchema } from "@/lib/content/schemas"; -import { buildSearchDocuments } from "@/lib/search/build-documents"; - -const PAGE_CASES = [ - { - slug: "relu", - registryId: "concept.relu", - title: "ReLU", - pageDir: RELU_GLOSSARY_PAGE_DIR, - aliases: ["rectified linear unit", "ReLU activation", "rectifier"], - relatedIds: [ - "concept.activation", - "concept.feed-forward-network", - "concept.standard-ffn", - "concept.leaky-relu", - "concept.silu", - ], - hrefs: [ - "/docs/glossary/activation", - "/docs/glossary/feed-forward-network", - "/docs/glossary/standard-ffn", - "/docs/glossary/leaky-relu", - "/docs/glossary/silu", - ], - messageNeedles: ["positive", "zero", "attention"], - renderNeedle: "keep positive numbers", - searchQuery: "ReLU", - }, - { - slug: "leaky-relu", - registryId: "concept.leaky-relu", - title: "LeakyReLU", - pageDir: LEAKY_RELU_GLOSSARY_PAGE_DIR, - aliases: [ - "leaky ReLU", - "leaky rectified linear unit", - "Leaky ReLU activation", - ], - relatedIds: [ - "concept.activation", - "concept.feed-forward-network", - "concept.standard-ffn", - "concept.relu", - "concept.silu", - ], - hrefs: [ - "/docs/glossary/activation", - "/docs/glossary/feed-forward-network", - "/docs/glossary/standard-ffn", - "/docs/glossary/relu", - "/docs/glossary/silu", - ], - messageNeedles: ["small constant", "negative", "standard ffn"], - renderNeedle: "small constant such as 0.01", - searchQuery: "LeakyReLU", - }, - { - slug: "silu", - registryId: "concept.silu", - title: "SiLU", - pageDir: SILU_GLOSSARY_PAGE_DIR, - aliases: ["sigmoid linear unit", "Swish", "SiLU activation"], - relatedIds: [ - "concept.activation", - "concept.feed-forward-network", - "concept.standard-ffn", - "concept.relu", - "concept.swiglu", - ], - hrefs: [ - "/docs/glossary/activation", - "/docs/glossary/feed-forward-network", - "/docs/glossary/standard-ffn", - "/docs/glossary/relu", - "/docs/glossary/swiglu", - ], - messageNeedles: ["sigmoid", "smooth", "swiglu"], - renderNeedle: "sigmoid linear unit", - searchQuery: "SiLU", - }, - { - slug: "swiglu", - registryId: "concept.swiglu", - title: "SwiGLU", - pageDir: SWIGLU_GLOSSARY_PAGE_DIR, - aliases: ["swish gated linear unit", "SiLU-gated FFN", "SwiGLU FFN"], - relatedIds: [ - "concept.feed-forward-network", - "concept.standard-ffn", - "concept.mixture-of-experts", - "concept.silu", - "concept.activation", - ], - hrefs: [ - "/docs/glossary/feed-forward-network", - "/docs/glossary/standard-ffn", - "/docs/glossary/mixture-of-experts", - "/docs/glossary/silu", - "/docs/glossary/activation", - ], - messageNeedles: ["gate", "silu", "mixture of experts"], - renderNeedle: "two branches after attention", - searchQuery: "SwiGLU", - }, -] as const; - -describe("Phase 3 activation-family glossary pages (US-002)", () => { - for (const testCase of PAGE_CASES) { - test(`${testCase.title} registry record is published with aliases, tags, and curated related ids`, () => { - const record = getConceptById(testCase.registryId); - expect(record?.status).toBe("published"); - expect(record?.aliases).toEqual([...testCase.aliases]); - expect(record?.tags).toEqual(["foundations"]); - expect(record?.relatedIds).toEqual([...testCase.relatedIds]); - expect(PUBLISHED_DOCS_REGISTRY_IDS.has(testCase.registryId)).toBe(true); - }); - - test(`${testCase.title} curated related links resolve to published FFN-family pages`, () => { - const source = getConceptById(testCase.registryId); - if (!source) { - throw new Error(`expected ${testCase.registryId} in registry`); - } - - const items = deriveCuratedRelatedItems( - source, - listRelatedRegistryRecords(), - PUBLISHED_DOCS_REGISTRY_IDS, - ); - - for (const href of testCase.hrefs) { - expect( - items.some((item) => item.href === href && !item.isPlanned), - ).toBe(true); - } - }); - - test(`${testCase.title} messages explain the intended FFN behavior in plain language`, () => { - const messages = pageMessagesSchema.parse( - JSON.parse( - readFileSync(join(testCase.pageDir, "messages/en.json"), "utf8"), - ), - ); - - expect(messages.title).toBe(testCase.title); - expect(messages.openingSummary?.length).toBeGreaterThan(0); - const combinedBody = [ - messages.sections?.whatItIs.body, - messages.sections?.whyItMatters.body, - messages.sections?.commonConfusions.body, - ] - .join(" ") - .toLowerCase(); - - for (const needle of testCase.messageNeedles) { - expect(combinedBody).toContain(needle); - } - }); - - test(`${testCase.title} page renders glossary sections, tags, and FFN-family links`, async () => { - const page = await loadGlossaryPage(testCase.slug); - - expect(page.frontmatter.kind).toBe("glossary"); - expect(page.frontmatter.status).toBe("published"); - expect(page.frontmatter.registryId).toBe(testCase.registryId); - - const html = renderToStaticMarkup( - createElement(ModulePageProviders, { - messages: page.messages, - assets: page.assets, - // biome-ignore lint/correctness/noChildrenProp: third createElement arg conflicts with strict props typing - children: page.content, - }), - ); - - expectGlossaryPresentationConvergence(html, { - title: testCase.title, - }); - expect(html).toContain("What It Is"); - expect(html).toContain("Common Confusions"); - expectHtmlToContainProse(html, testCase.renderNeedle); - for (const href of testCase.hrefs) { - expect(html).toContain(`href="${href}"`); - } - expect(html).toContain('href="/tags/foundations"'); - expect(html).toContain('data-testid="tag-pill-list"'); - expect(html).toContain('data-testid="curated-related-docs"'); - expect(html).not.toContain("Phase"); - expect(html).not.toContain("Reader Shortcut"); - }); - - test(`${testCase.title} search index records the glossary page and preserves aliases`, async () => { - const registry = await loadRegistry(); - const pages = await loadPublishedDocsPages("en"); - const documents = buildSearchDocuments(pages, registry); - - const document = documents.find( - (entry) => entry.url === `/docs/glossary/${testCase.slug}`, - ); - expect(document?.title).toBe(testCase.title); - expect(document?.kind).toBe("glossary"); - expect(document?.facets.kind).toBe("glossary"); - expect(document?.aliases).toEqual( - expect.arrayContaining(testCase.aliases), - ); - expect(document?.bodyText.length ?? 0).toBeGreaterThan(50); - expect(document?.headings.length ?? 0).toBeGreaterThan(0); - expect(testCase.searchQuery.length).toBeGreaterThan(0); - }); - } -}); diff --git a/src/lib/content/content-paths.ts b/src/lib/content/content-paths.ts index 6f74bbff..134b4147 100644 --- a/src/lib/content/content-paths.ts +++ b/src/lib/content/content-paths.ts @@ -209,21 +209,6 @@ export const LAYER_NORM_GLOSSARY_PAGE_DIR = join( "layer-norm", ); -/** Phase 3 ReLU glossary page directory. */ -export const RELU_GLOSSARY_PAGE_DIR = join(GLOSSARY_DOCS_ROOT, "relu"); - -/** Phase 3 LeakyReLU glossary page directory. */ -export const LEAKY_RELU_GLOSSARY_PAGE_DIR = join( - GLOSSARY_DOCS_ROOT, - "leaky-relu", -); - -/** Phase 3 SiLU glossary page directory. */ -export const SILU_GLOSSARY_PAGE_DIR = join(GLOSSARY_DOCS_ROOT, "silu"); - -/** Phase 3 SwiGLU glossary page directory. */ -export const SWIGLU_GLOSSARY_PAGE_DIR = join(GLOSSARY_DOCS_ROOT, "swiglu"); - /** Phase 3 RMSNorm glossary page directory. */ export const RMSNORM_GLOSSARY_PAGE_DIR = join(GLOSSARY_DOCS_ROOT, "rmsnorm"); diff --git a/src/lib/content/glossary-architecture-index.test.ts b/src/lib/content/glossary-architecture-index.test.ts index ab05dd0b..fa0ddfac 100644 --- a/src/lib/content/glossary-architecture-index.test.ts +++ b/src/lib/content/glossary-architecture-index.test.ts @@ -24,6 +24,21 @@ const TAXONOMY_GLOSSARY_SLUGS = [ "latent-space", ] as const; +const FFN_ACTIVATION_GLOSSARY_SLUGS = [ + "feed-forward-network", + "batch-norm", + "group-norm", + "standard-ffn", + "mixture-of-experts", + "relu", + "leaky-relu", + "silu", + "swiglu", + "qk-norm", + "residual-connection", + "skip-connection", +] as const; + const EXPECTED_GLOSSARY_TITLES: Record = { model: "Model", architecture: "Architecture", @@ -37,6 +52,18 @@ const EXPECTED_GLOSSARY_TITLES: Record = { patch: "Patch", latent: "Latent", "latent-space": "Latent Space", + "feed-forward-network": "Feed-forward network", + "batch-norm": "Batch norm", + "group-norm": "Group norm", + "standard-ffn": "Standard FFN", + "mixture-of-experts": "Mixture of experts", + relu: "ReLU", + "leaky-relu": "LeakyReLU", + silu: "SiLU", + swiglu: "SwiGLU", + "qk-norm": "QK norm", + "residual-connection": "Residual connection", + "skip-connection": "Skip connection", token: "Token", embedding: "Embedding", tensor: "Tensor", @@ -45,18 +72,21 @@ const EXPECTED_GLOSSARY_TITLES: Record = { softmax: "Softmax", entropy: "Entropy", temperature: "Temperature", + "sampling-overview": "Sampling Overview", + "greedy-decoding": "Greedy Decoding", + "top-k-sampling": "Top-K Sampling", + "top-p-sampling": "Top-P Sampling", parameter: "Parameter", activation: "Activation", - relu: "ReLU", - "leaky-relu": "LeakyReLU", - silu: "SiLU", "computational-graph": "Computational Graph", gradient: "Gradient", backpropagation: "Backpropagation", "loss-function": "Loss Function", "optimizer-state": "Optimizer State", - "standard-ffn": "Standard FFN", - swiglu: "SwiGLU", + "kv-cache": "KV cache", + decode: "Decode", + prefill: "Prefill", + "prefill-decode-split": "Prefill/decode split", }; const CHAIN_GLOSSARY_SLUGS = [ @@ -67,19 +97,20 @@ const CHAIN_GLOSSARY_SLUGS = [ "softmax", "entropy", "temperature", + "sampling-overview", + "greedy-decoding", + "top-k-sampling", + "top-p-sampling", "parameter", "activation", - "relu", - "leaky-relu", - "silu", "computational-graph", "gradient", "backpropagation", "loss-function", "optimizer-state", ] as const; -const PUBLISHED_GLOSSARY_ENTRY_COUNT = 59; -const PUBLISHED_ARCHITECTURE_ENTRY_COUNT = 52; +const PUBLISHED_GLOSSARY_ENTRY_COUNT = 71; +const PUBLISHED_ARCHITECTURE_ENTRY_COUNT = 60; const GLOSSARY_SEPARATOR_TITLES = [ "Model Taxonomy", "Sequence And Attention", @@ -103,7 +134,7 @@ function collectPageUrls(nodes: Node[]): string[] { } describe("Phase 2 glossary and architecture index navigation (US-007)", () => { - test("glossary meta.json lists token and all nine taxonomy pages", async () => { + test("glossary meta.json lists token, prefill, and all taxonomy pages", async () => { const metaPath = join(process.cwd(), "src/content/docs/glossary/meta.json"); const meta = JSON.parse(await readFile(metaPath, "utf8")) as { pages: string[]; @@ -118,9 +149,16 @@ describe("Phase 2 glossary and architecture index navigation (US-007)", () => { ); for (const slug of [ ...TAXONOMY_GLOSSARY_SLUGS, + ...FFN_ACTIVATION_GLOSSARY_SLUGS, ...CHAIN_GLOSSARY_SLUGS, - "standard-ffn", - "swiglu", + "kv-cache", + "decode", + "prefill", + "prefill-decode-split", + "sampling-overview", + "greedy-decoding", + "top-k-sampling", + "top-p-sampling", "token", ] as const) { const title = EXPECTED_GLOSSARY_TITLES[slug]; @@ -145,9 +183,16 @@ describe("Phase 2 glossary and architecture index navigation (US-007)", () => { const glossaryUrls = collectPageUrls(glossaryFolder.children); for (const slug of [ ...TAXONOMY_GLOSSARY_SLUGS, + ...FFN_ACTIVATION_GLOSSARY_SLUGS, ...CHAIN_GLOSSARY_SLUGS, - "standard-ffn", - "swiglu", + "kv-cache", + "decode", + "prefill", + "prefill-decode-split", + "sampling-overview", + "greedy-decoding", + "top-k-sampling", + "top-p-sampling", "token", ] as const) { expect(glossaryUrls).toContain(`/docs/glossary/${slug}`); @@ -172,13 +217,30 @@ describe("Phase 2 glossary and architecture index navigation (US-007)", () => { const token = entries.find((item) => item.url === "/docs/glossary/token"); expect(token?.title).toBe("Token"); - const standardFfn = entries.find( - (item) => item.url === "/docs/glossary/standard-ffn", + const kvCache = entries.find( + (item) => item.url === "/docs/glossary/kv-cache", ); - expect(standardFfn?.title).toBe("Standard FFN"); + expect(kvCache?.title).toBe("KV cache"); - const swiglu = entries.find((item) => item.url === "/docs/glossary/swiglu"); - expect(swiglu?.title).toBe("SwiGLU"); + const decode = entries.find((item) => item.url === "/docs/glossary/decode"); + expect(decode?.title).toBe("Decode"); + + const prefill = entries.find( + (item) => item.url === "/docs/glossary/prefill", + ); + expect(prefill?.title).toBe("Prefill"); + + const prefillDecodeSplit = entries.find( + (item) => item.url === "/docs/glossary/prefill-decode-split", + ); + expect(prefillDecodeSplit?.title).toBe("Prefill/decode split"); + + for (const slug of FFN_ACTIVATION_GLOSSARY_SLUGS) { + const entry = entries.find( + (item) => item.url === `/docs/glossary/${slug}`, + ); + expect(entry?.title).toBe(EXPECTED_GLOSSARY_TITLES[slug]); + } for (const slug of CHAIN_GLOSSARY_SLUGS) { const entry = entries.find( @@ -204,18 +266,35 @@ describe("Phase 2 glossary and architecture index navigation (US-007)", () => { expect(entry?.title).toBe(EXPECTED_GLOSSARY_TITLES[slug]); } - const standardFfn = entries.find( - (entry) => entry.url === "/docs/glossary/standard-ffn", + for (const slug of FFN_ACTIVATION_GLOSSARY_SLUGS) { + const entry = entries.find( + (item) => item.url === `/docs/glossary/${slug}`, + ); + expect(entry?.title).toBe(EXPECTED_GLOSSARY_TITLES[slug]); + } + + const token = entries.find((entry) => entry.url === "/docs/glossary/token"); + expect(token?.title).toBe("Token"); + + const kvCache = entries.find( + (entry) => entry.url === "/docs/glossary/kv-cache", ); - expect(standardFfn?.title).toBe("Standard FFN"); + expect(kvCache?.title).toBe("KV cache"); - const swiglu = entries.find( - (entry) => entry.url === "/docs/glossary/swiglu", + const decode = entries.find( + (entry) => entry.url === "/docs/glossary/decode", ); - expect(swiglu?.title).toBe("SwiGLU"); + expect(decode?.title).toBe("Decode"); - const token = entries.find((entry) => entry.url === "/docs/glossary/token"); - expect(token?.title).toBe("Token"); + const prefill = entries.find( + (entry) => entry.url === "/docs/glossary/prefill", + ); + expect(prefill?.title).toBe("Prefill"); + + const prefillDecodeSplit = entries.find( + (entry) => entry.url === "/docs/glossary/prefill-decode-split", + ); + expect(prefillDecodeSplit?.title).toBe("Prefill/decode split"); const embedding = entries.find( (entry) => entry.url === "/docs/glossary/embedding", @@ -258,30 +337,34 @@ describe("Phase 2 glossary and architecture index navigation (US-007)", () => { expect(glossaryHtml).toContain('href="/docs/glossary/parameter"'); expect(glossaryHtml).toContain("Activation"); expect(glossaryHtml).toContain('href="/docs/glossary/activation"'); - expect(glossaryHtml).toContain("ReLU"); - expect(glossaryHtml).toContain('href="/docs/glossary/relu"'); - expect(glossaryHtml).toContain("LeakyReLU"); - expect(glossaryHtml).toContain('href="/docs/glossary/leaky-relu"'); - expect(glossaryHtml).toContain("SiLU"); - expect(glossaryHtml).toContain('href="/docs/glossary/silu"'); - expect(glossaryHtml).toContain("SwiGLU"); - expect(glossaryHtml).toContain('href="/docs/glossary/swiglu"'); expect(glossaryHtml).toContain("Computational Graph"); expect(glossaryHtml).toContain('href="/docs/glossary/computational-graph"'); + expect(glossaryHtml).toContain("KV cache"); + expect(glossaryHtml).toContain('href="/docs/glossary/kv-cache"'); + expect(glossaryHtml).toContain("Decode"); + expect(glossaryHtml).toContain('href="/docs/glossary/decode"'); + expect(glossaryHtml).toContain("Prefill"); + expect(glossaryHtml).toContain('href="/docs/glossary/prefill"'); + expect(glossaryHtml).toContain("Prefill/decode split"); + expect(glossaryHtml).toContain( + 'href="/docs/glossary/prefill-decode-split"', + ); expect(architectureHtml).toContain("Activation"); expect(architectureHtml).toContain('href="/docs/glossary/activation"'); - expect(architectureHtml).toContain("ReLU"); - expect(architectureHtml).toContain('href="/docs/glossary/relu"'); - expect(architectureHtml).toContain("LeakyReLU"); - expect(architectureHtml).toContain('href="/docs/glossary/leaky-relu"'); - expect(architectureHtml).toContain("SiLU"); - expect(architectureHtml).toContain('href="/docs/glossary/silu"'); - expect(architectureHtml).toContain("SwiGLU"); - expect(architectureHtml).toContain('href="/docs/glossary/swiglu"'); expect(architectureHtml).toContain("Computational Graph"); expect(architectureHtml).toContain( 'href="/docs/glossary/computational-graph"', ); + expect(architectureHtml).toContain("KV cache"); + expect(architectureHtml).toContain('href="/docs/glossary/kv-cache"'); + expect(architectureHtml).toContain("Decode"); + expect(architectureHtml).toContain('href="/docs/glossary/decode"'); + expect(architectureHtml).toContain("Prefill"); + expect(architectureHtml).toContain('href="/docs/glossary/prefill"'); + expect(architectureHtml).toContain("Prefill/decode split"); + expect(architectureHtml).toContain( + 'href="/docs/glossary/prefill-decode-split"', + ); expect(architectureHtml).not.toContain('href="/docs/glossary/parameter"'); expect(architectureHtml).toContain("Embedding"); expect(architectureHtml).toContain('href="/docs/glossary/embedding"'); diff --git a/src/lib/content/glossary-opening-convergence.test.tsx b/src/lib/content/glossary-opening-convergence.test.tsx index c45d2fd8..dd8692d0 100644 --- a/src/lib/content/glossary-opening-convergence.test.tsx +++ b/src/lib/content/glossary-opening-convergence.test.tsx @@ -50,6 +50,6 @@ describe("glossary opening convergence", () => { expectGlossaryOmitsOpeningSummary(html); } }, - { timeout: 20_000 }, + { timeout: 30_000 }, ); }); diff --git a/src/lib/content/glossary-shell-description-auto-link.test.tsx b/src/lib/content/glossary-shell-description-auto-link.test.tsx index 17e1afe4..b3dc8a83 100644 --- a/src/lib/content/glossary-shell-description-auto-link.test.tsx +++ b/src/lib/content/glossary-shell-description-auto-link.test.tsx @@ -16,6 +16,16 @@ import { } from "@/lib/content/glossary-test-helpers"; import { loadLocalDocsPage } from "@/lib/content/local-docs-page"; +function chunkValues(values: T[], size: number): T[][] { + const chunks: T[][] = []; + + for (let index = 0; index < values.length; index += size) { + chunks.push(values.slice(index, index + size)); + } + + return chunks; +} + describe("glossary shell description auto-link convergence", () => { test("glossary docs routes wire shell descriptions through DocsAutoLinkedDescription", () => { const pageRendererSource = readFileSync( @@ -45,35 +55,103 @@ describe("glossary shell description auto-link convergence", () => { expect(autoLinkedDescriptionSource).toContain("ProseAutoLinkText"); }); - test( - "published glossary pages render auto-linked shell descriptions without body duplication", - async () => { - const pages = await listPublishedGlossaryPages(); - - for (const page of pages) { - const loadedPage = await loadLocalDocsPage({ - section: "glossary", - slug: page.slug, - }); - const html = renderGlossaryDocsShell(loadedPage); - const articleHtml = extractGlossaryArticleHtml( - html, - loadedPage.frontmatter.registryId, + for (const [chunkIndex, slugChunk] of chunkValues( + [ + "activation", + "alibi", + "alignment", + "architecture", + "autoregressive-generation", + "component", + "computational-graph", + "conditioning", + "context-window", + "decode", + "decoder", + "denoising-generation", + "diffusion-model", + "discriminative-model", + "embedding", + "emergent-behavior", + "encoder", + "encoder-decoder", + "entropy", + "feed-forward-network", + "foundation-model", + "generalization", + "generative-model", + "gradient", + "hidden-size", + "kv-cache", + "latent", + "latent-space", + "layer-norm", + "logit", + "loss-function", + "mixture-of-experts", + "modality", + "model", + "model-capacity", + "module", + "multimodal-model", + "normalization", + "optimizer-state", + "overfitting", + "parameter", + "patch", + "perplexity", + "prefill", + "prefill-decode-split", + "representation", + "residual-connection", + "rmsnorm", + "rope", + "scaling-law", + "softmax", + "temperature", + "tensor", + "token", + "transformer", + "vector", + "world-model", + ], + 20, + ).entries()) { + test( + `published glossary pages chunk ${chunkIndex + 1} renders auto-linked shell descriptions without body duplication`, + async () => { + const pageSet = new Set(slugChunk); + const pages = (await listPublishedGlossaryPages()).filter((page) => + pageSet.has(page.slug), ); - const articleStart = html.indexOf("= 0 ? html.slice(0, articleStart) : html; - expectHtmlToContainProse(shellHtml, loadedPage.messages.description); - expectGlossaryBodyOmitsShellDescription( - articleHtml, - loadedPage.messages.description, - ); - expectGlossaryShellAutoLinksUseProseContract(html); - } - }, - { timeout: 20_000 }, - ); + expect(pages).toHaveLength(slugChunk.length); + + for (const page of pages) { + const loadedPage = await loadLocalDocsPage({ + section: "glossary", + slug: page.slug, + }); + const html = renderGlossaryDocsShell(loadedPage); + const articleHtml = extractGlossaryArticleHtml( + html, + loadedPage.frontmatter.registryId, + ); + + const articleStart = html.indexOf("= 0 ? html.slice(0, articleStart) : html; + expectHtmlToContainProse(shellHtml, loadedPage.messages.description); + expectGlossaryBodyOmitsShellDescription( + articleHtml, + loadedPage.messages.description, + ); + expectGlossaryShellAutoLinksUseProseContract(html); + } + }, + { timeout: 10_000 }, + ); + } test("/docs/glossary/embedding shell description links dense vector and token with preserved link text", async () => { const loadedPage = await loadLocalDocsPage({ diff --git a/src/lib/content/registry-runtime.test.ts b/src/lib/content/registry-runtime.test.ts index 2a98872e..0111e3eb 100644 --- a/src/lib/content/registry-runtime.test.ts +++ b/src/lib/content/registry-runtime.test.ts @@ -19,7 +19,9 @@ describe("registry-runtime", () => { expect(record?.relatedIds).toContain("module.multi-head-attention"); expect(record?.relatedIds).toContain("module.multi-query-attention"); expect(record?.relatedIds).toContain("module.grouped-query-attention"); + expect(record?.relatedIds).toContain("concept.kv-cache"); expect(record?.relatedIds).toContain("concept.token"); + expect(record?.relatedIds).toContain("concept.prefill-decode-split"); }); test("getModuleById returns grouped-query attention", () => { @@ -30,6 +32,10 @@ describe("registry-runtime", () => { "module.attention", "module.multi-head-attention", "module.multi-query-attention", + "concept.kv-cache", + "concept.decode", + "concept.quantization", + "concept.prefill-decode-split", ]); }); @@ -87,6 +93,10 @@ describe("registry-runtime", () => { "module.attention", "module.multi-head-attention", "module.grouped-query-attention", + "concept.kv-cache", + "concept.decode", + "concept.quantization", + "concept.prefill-decode-split", ]); }); @@ -116,7 +126,8 @@ describe("registry-runtime", () => { expect(ids).toContain("concept.token"); expect(ids).toContain("concept.embedding"); expect(ids).toContain("concept.softmax"); - expect(ids).toContain("concept.standard-ffn"); + expect(ids).toContain("concept.prefill"); + expect(ids).toContain("concept.prefill-decode-split"); }); test("getConceptById returns published embedding and logit for chain", () => { diff --git a/src/lib/content/registry-runtime.ts b/src/lib/content/registry-runtime.ts index 0c567bc8..9161d6f8 100644 --- a/src/lib/content/registry-runtime.ts +++ b/src/lib/content/registry-runtime.ts @@ -1,18 +1,23 @@ import activationConcept from "@/content/registry/concepts/activation.json"; +import activationQuantizationConcept from "@/content/registry/concepts/activation-quantization.json"; import alibiConcept from "@/content/registry/concepts/alibi.json"; import alignmentConcept from "@/content/registry/concepts/alignment.json"; import architectureConcept from "@/content/registry/concepts/architecture.json"; import autoregressiveGenerationConcept from "@/content/registry/concepts/autoregressive-generation.json"; import backpropagationConcept from "@/content/registry/concepts/backpropagation.json"; +import batchNormConcept from "@/content/registry/concepts/batch-norm.json"; +import calibrationConcept from "@/content/registry/concepts/calibration.json"; import componentConcept from "@/content/registry/concepts/component.json"; import computationalGraphConcept from "@/content/registry/concepts/computational-graph.json"; import conditioningConcept from "@/content/registry/concepts/conditioning.json"; import contextExtensionConcept from "@/content/registry/concepts/context-extension.json"; import contextWindowConcept from "@/content/registry/concepts/context-window.json"; +import decodeConcept from "@/content/registry/concepts/decode.json"; import decoderConcept from "@/content/registry/concepts/decoder.json"; import denoisingGenerationConcept from "@/content/registry/concepts/denoising-generation.json"; import diffusionModelConcept from "@/content/registry/concepts/diffusion-model.json"; import discriminativeModelConcept from "@/content/registry/concepts/discriminative-model.json"; +import dynamicQuantizationConcept from "@/content/registry/concepts/dynamic-quantization.json"; import embeddingConcept from "@/content/registry/concepts/embedding.json"; import emergentBehaviorConcept from "@/content/registry/concepts/emergent-behavior.json"; import encoderConcept from "@/content/registry/concepts/encoder.json"; @@ -23,7 +28,11 @@ import foundationModelConcept from "@/content/registry/concepts/foundation-model import generalizationConcept from "@/content/registry/concepts/generalization.json"; import generativeModelConcept from "@/content/registry/concepts/generative-model.json"; import gradientConcept from "@/content/registry/concepts/gradient.json"; +import greedyDecodingConcept from "@/content/registry/concepts/greedy-decoding.json"; +import groupNormConcept from "@/content/registry/concepts/group-norm.json"; import hiddenSizeConcept from "@/content/registry/concepts/hidden-size.json"; +import kvCacheConcept from "@/content/registry/concepts/kv-cache.json"; +import kvCacheQuantizationConcept from "@/content/registry/concepts/kv-cache-quantization.json"; import latentConcept from "@/content/registry/concepts/latent.json"; import latentSpaceConcept from "@/content/registry/concepts/latent-space.json"; import layerNormConcept from "@/content/registry/concepts/layer-norm.json"; @@ -43,22 +52,34 @@ import parameterConcept from "@/content/registry/concepts/parameter.json"; import patchConcept from "@/content/registry/concepts/patch.json"; import perplexityConcept from "@/content/registry/concepts/perplexity.json"; import positionalEncodingsConcept from "@/content/registry/concepts/positional-encodings.json"; +import postTrainingQuantizationConcept from "@/content/registry/concepts/post-training-quantization.json"; +import prefillConcept from "@/content/registry/concepts/prefill.json"; +import prefillDecodeSplitConcept from "@/content/registry/concepts/prefill-decode-split.json"; +import qkNormConcept from "@/content/registry/concepts/qk-norm.json"; +import quantizationConcept from "@/content/registry/concepts/quantization.json"; +import quantizationAwareTrainingConcept from "@/content/registry/concepts/quantization-aware-training.json"; import reluConcept from "@/content/registry/concepts/relu.json"; import representationConcept from "@/content/registry/concepts/representation.json"; import residualConnectionConcept from "@/content/registry/concepts/residual-connection.json"; import rmsnormConcept from "@/content/registry/concepts/rmsnorm.json"; import ropeConcept from "@/content/registry/concepts/rope.json"; +import samplingOverviewConcept from "@/content/registry/concepts/sampling-overview.json"; import scalingLawConcept from "@/content/registry/concepts/scaling-law.json"; import siluConcept from "@/content/registry/concepts/silu.json"; +import skipConnectionConcept from "@/content/registry/concepts/skip-connection.json"; import softmaxConcept from "@/content/registry/concepts/softmax.json"; import standardFfnConcept from "@/content/registry/concepts/standard-ffn.json"; import swigluConcept from "@/content/registry/concepts/swiglu.json"; import temperatureConcept from "@/content/registry/concepts/temperature.json"; import tensorConcept from "@/content/registry/concepts/tensor.json"; import tokenConcept from "@/content/registry/concepts/token.json"; +import topKSamplingConcept from "@/content/registry/concepts/top-k-sampling.json"; +import topPSamplingConcept from "@/content/registry/concepts/top-p-sampling.json"; import transformerConcept from "@/content/registry/concepts/transformer.json"; import transformerArchitectureConcept from "@/content/registry/concepts/transformer-architecture.json"; import vectorConcept from "@/content/registry/concepts/vector.json"; +import weightOnlyQuantizationConcept from "@/content/registry/concepts/weight-only-quantization.json"; +import whyFourBitModelsAreNotExactlyFourXFasterConcept from "@/content/registry/concepts/why-4-bit-models-are-not-exactly-4x-faster.json"; import whyLongContextIsHardConcept from "@/content/registry/concepts/why-long-context-is-hard.json"; import worldModelConcept from "@/content/registry/concepts/world-model.json"; import attention from "@/content/registry/modules/attention.json"; @@ -98,12 +119,19 @@ const conceptRecords: ConceptRecord[] = [ conceptRecordSchema.parse(tensorConcept), conceptRecordSchema.parse(vectorConcept), conceptRecordSchema.parse(hiddenSizeConcept), + conceptRecordSchema.parse(kvCacheConcept), + conceptRecordSchema.parse(kvCacheQuantizationConcept), conceptRecordSchema.parse(logitConcept), conceptRecordSchema.parse(softmaxConcept), conceptRecordSchema.parse(entropyConcept), conceptRecordSchema.parse(temperatureConcept), + conceptRecordSchema.parse(samplingOverviewConcept), + conceptRecordSchema.parse(greedyDecodingConcept), + conceptRecordSchema.parse(topKSamplingConcept), + conceptRecordSchema.parse(topPSamplingConcept), conceptRecordSchema.parse(parameterConcept), conceptRecordSchema.parse(activationConcept), + conceptRecordSchema.parse(activationQuantizationConcept), conceptRecordSchema.parse(computationalGraphConcept), conceptRecordSchema.parse(gradientConcept), conceptRecordSchema.parse(backpropagationConcept), @@ -117,41 +145,55 @@ const conceptRecords: ConceptRecord[] = [ conceptRecordSchema.parse(foundationModelConcept), conceptRecordSchema.parse(generativeModelConcept), conceptRecordSchema.parse(discriminativeModelConcept), + conceptRecordSchema.parse(dynamicQuantizationConcept), conceptRecordSchema.parse(representationConcept), conceptRecordSchema.parse(patchConcept), conceptRecordSchema.parse(latentConcept), conceptRecordSchema.parse(latentSpaceConcept), conceptRecordSchema.parse(encoderConcept), + conceptRecordSchema.parse(decodeConcept), conceptRecordSchema.parse(decoderConcept), conceptRecordSchema.parse(encoderDecoderConcept), conceptRecordSchema.parse(autoregressiveGenerationConcept), + conceptRecordSchema.parse(prefillConcept), + conceptRecordSchema.parse(prefillDecodeSplitConcept), conceptRecordSchema.parse(denoisingGenerationConcept), conceptRecordSchema.parse(conditioningConcept), conceptRecordSchema.parse(contextExtensionConcept), conceptRecordSchema.parse(contextWindowConcept), conceptRecordSchema.parse(alignmentConcept), + conceptRecordSchema.parse(batchNormConcept), conceptRecordSchema.parse(modelCapacityConcept), conceptRecordSchema.parse(overfittingConcept), conceptRecordSchema.parse(generalizationConcept), + conceptRecordSchema.parse(groupNormConcept), conceptRecordSchema.parse(perplexityConcept), conceptRecordSchema.parse(scalingLawConcept), conceptRecordSchema.parse(emergentBehaviorConcept), conceptRecordSchema.parse(feedForwardNetworkConcept), conceptRecordSchema.parse(standardFfnConcept), + conceptRecordSchema.parse(mixtureOfExpertsConcept), conceptRecordSchema.parse(reluConcept), conceptRecordSchema.parse(leakyReluConcept), conceptRecordSchema.parse(siluConcept), conceptRecordSchema.parse(swigluConcept), - conceptRecordSchema.parse(mixtureOfExpertsConcept), conceptRecordSchema.parse(layerNormConcept), conceptRecordSchema.parse(normalizationConcept), + conceptRecordSchema.parse(qkNormConcept), conceptRecordSchema.parse(rmsnormConcept), conceptRecordSchema.parse(alibiConcept), + conceptRecordSchema.parse(calibrationConcept), conceptRecordSchema.parse(positionalEncodingsConcept), + conceptRecordSchema.parse(postTrainingQuantizationConcept), + conceptRecordSchema.parse(quantizationConcept), + conceptRecordSchema.parse(quantizationAwareTrainingConcept), conceptRecordSchema.parse(residualConnectionConcept), + conceptRecordSchema.parse(skipConnectionConcept), conceptRecordSchema.parse(ropeConcept), conceptRecordSchema.parse(transformerArchitectureConcept), conceptRecordSchema.parse(transformerConcept), + conceptRecordSchema.parse(weightOnlyQuantizationConcept), + conceptRecordSchema.parse(whyFourBitModelsAreNotExactlyFourXFasterConcept), conceptRecordSchema.parse(diffusionModelConcept), conceptRecordSchema.parse(multimodalModelConcept), conceptRecordSchema.parse(whyLongContextIsHardConcept), diff --git a/src/lib/source.test.ts b/src/lib/source.test.ts index 1b9148df..7456dae3 100644 --- a/src/lib/source.test.ts +++ b/src/lib/source.test.ts @@ -32,7 +32,6 @@ const GLOSSARY_INDEX_URLS = [ "/docs/glossary/model-capacity", "/docs/glossary/module", "/docs/glossary/layer-norm", - "/docs/glossary/leaky-relu", "/docs/glossary/mixture-of-experts", "/docs/glossary/multimodal-model", "/docs/glossary/normalization", @@ -47,13 +46,12 @@ const GLOSSARY_INDEX_URLS = [ "/docs/glossary/prefill", "/docs/glossary/prefill-decode-split", "/docs/glossary/qk-norm", + "/docs/glossary/relu", "/docs/glossary/greedy-decoding", "/docs/glossary/top-k-sampling", "/docs/glossary/top-p-sampling", "/docs/glossary/representation", "/docs/glossary/scaling-law", - "/docs/glossary/standard-ffn", - "/docs/glossary/swiglu", "/docs/glossary/token", "/docs/glossary/transformer", "/docs/glossary/world-model", @@ -68,10 +66,7 @@ const GLOSSARY_INDEX_URLS = [ "/docs/glossary/temperature", "/docs/glossary/sampling-overview", "/docs/glossary/parameter", - "/docs/glossary/relu", "/docs/glossary/activation", - "/docs/glossary/relu", - "/docs/glossary/silu", "/docs/glossary/standard-ffn", "/docs/glossary/swiglu", "/docs/glossary/computational-graph", diff --git a/src/tests/content/architecture-index.test.ts b/src/tests/content/architecture-index.test.ts index ea3b9566..ee7b47e4 100644 --- a/src/tests/content/architecture-index.test.ts +++ b/src/tests/content/architecture-index.test.ts @@ -32,10 +32,12 @@ describe("isArchitectureRelatedPage", () => { "/docs/glossary/alignment", "/docs/glossary/architecture", "/docs/glossary/autoregressive-generation", + "/docs/glossary/batch-norm", "/docs/glossary/component", "/docs/glossary/computational-graph", "/docs/glossary/conditioning", "/docs/glossary/context-window", + "/docs/glossary/decode", "/docs/glossary/decoder", "/docs/glossary/denoising-generation", "/docs/glossary/diffusion-model", @@ -48,11 +50,12 @@ describe("isArchitectureRelatedPage", () => { "/docs/glossary/foundation-model", "/docs/glossary/generalization", "/docs/glossary/generative-model", + "/docs/glossary/group-norm", + "/docs/glossary/kv-cache", "/docs/glossary/latent", "/docs/glossary/latent-space", "/docs/glossary/layer-norm", "/docs/glossary/leaky-relu", - "/docs/glossary/relu", "/docs/glossary/mixture-of-experts", "/docs/glossary/modality", "/docs/glossary/model", @@ -63,8 +66,13 @@ describe("isArchitectureRelatedPage", () => { "/docs/glossary/overfitting", "/docs/glossary/patch", "/docs/glossary/perplexity", + "/docs/glossary/prefill", + "/docs/glossary/prefill-decode-split", + "/docs/glossary/qk-norm", + "/docs/glossary/relu", "/docs/glossary/representation", "/docs/glossary/residual-connection", + "/docs/glossary/skip-connection", "/docs/glossary/rmsnorm", "/docs/glossary/rope", "/docs/glossary/scaling-law", @@ -160,16 +168,14 @@ describe("architecture index page render", () => { expect(html).toContain('href="/docs/glossary/architecture"'); expect(html).toContain("Foundation Model"); expect(html).toContain('href="/docs/glossary/foundation-model"'); - expect(html).toContain("Standard FFN"); - expect(html).toContain('href="/docs/glossary/standard-ffn"'); - expect(html).toContain("ReLU"); - expect(html).toContain('href="/docs/glossary/relu"'); - expect(html).toContain("LeakyReLU"); - expect(html).toContain('href="/docs/glossary/leaky-relu"'); - expect(html).toContain("SiLU"); - expect(html).toContain('href="/docs/glossary/silu"'); - expect(html).toContain("SwiGLU"); - expect(html).toContain('href="/docs/glossary/swiglu"'); + expect(html).toContain("KV cache"); + expect(html).toContain('href="/docs/glossary/kv-cache"'); + expect(html).toContain("Decode"); + expect(html).toContain('href="/docs/glossary/decode"'); + expect(html).toContain("Prefill"); + expect(html).toContain('href="/docs/glossary/prefill"'); + expect(html).toContain("Prefill/decode split"); + expect(html).toContain('href="/docs/glossary/prefill-decode-split"'); expect(html).toContain("Token"); expect(html).toContain('href="/docs/glossary/token"'); expect(html).not.toContain("No architecture entries yet"); diff --git a/src/tests/content/glossary-index.test.ts b/src/tests/content/glossary-index.test.ts index 3576a929..04aee7be 100644 --- a/src/tests/content/glossary-index.test.ts +++ b/src/tests/content/glossary-index.test.ts @@ -108,9 +108,9 @@ describe("loadPublishedGlossaryEntries", () => { expect(optimizerState?.summary.length).toBeGreaterThan(0); }); - it("includes all nine Phase 2 taxonomy glossary pages with localized titles", async () => { + it("includes all published glossary pages with localized titles", async () => { const entries = await loadPublishedGlossaryEntries("en"); - expect(entries).toHaveLength(59); + expect(entries).toHaveLength(71); const architecture = entries.find( (entry) => entry.url === "/docs/glossary/architecture", @@ -128,26 +128,55 @@ describe("loadPublishedGlossaryEntries", () => { ); expect(encoder?.title).toBe("Encoder"); - const standardFfn = entries.find( - (entry) => entry.url === "/docs/glossary/standard-ffn", + const kvCache = entries.find( + (entry) => entry.url === "/docs/glossary/kv-cache", ); - expect(standardFfn?.title).toBe("Standard FFN"); + expect(kvCache?.title).toBe("KV cache"); - const relu = entries.find((entry) => entry.url === "/docs/glossary/relu"); - expect(relu?.title).toBe("ReLU"); + const prefill = entries.find( + (entry) => entry.url === "/docs/glossary/prefill", + ); + expect(prefill?.title).toBe("Prefill"); + + const prefillDecodeSplit = entries.find( + (entry) => entry.url === "/docs/glossary/prefill-decode-split", + ); + expect(prefillDecodeSplit?.title).toBe("Prefill/decode split"); + + const decode = entries.find( + (entry) => entry.url === "/docs/glossary/decode", + ); + expect(decode?.title).toBe("Decode"); + + const samplingOverview = entries.find( + (entry) => entry.url === "/docs/glossary/sampling-overview", + ); + expect(samplingOverview?.title).toBe("Sampling Overview"); + + const greedyDecoding = entries.find( + (entry) => entry.url === "/docs/glossary/greedy-decoding", + ); + expect(greedyDecoding?.title).toBe("Greedy Decoding"); - const leakyRelu = entries.find( - (entry) => entry.url === "/docs/glossary/leaky-relu", + const topKSampling = entries.find( + (entry) => entry.url === "/docs/glossary/top-k-sampling", ); - expect(leakyRelu?.title).toBe("LeakyReLU"); + expect(topKSampling?.title).toBe("Top-K Sampling"); - const silu = entries.find((entry) => entry.url === "/docs/glossary/silu"); - expect(silu?.title).toBe("SiLU"); + const topPSampling = entries.find( + (entry) => entry.url === "/docs/glossary/top-p-sampling", + ); + expect(topPSampling?.title).toBe("Top-P Sampling"); const swiglu = entries.find( (entry) => entry.url === "/docs/glossary/swiglu", ); expect(swiglu?.title).toBe("SwiGLU"); + + const skipConnection = entries.find( + (entry) => entry.url === "/docs/glossary/skip-connection", + ); + expect(skipConnection?.title).toBe("Skip connection"); }); }); @@ -213,16 +242,26 @@ describe("glossary index page render", () => { expect(html).toContain('href="/docs/glossary/entropy"'); expect(html).toContain("Temperature"); expect(html).toContain('href="/docs/glossary/temperature"'); + expect(html).toContain("Greedy Decoding"); + expect(html).toContain('href="/docs/glossary/greedy-decoding"'); + expect(html).toContain("Top-K Sampling"); + expect(html).toContain('href="/docs/glossary/top-k-sampling"'); + expect(html).toContain("Top-P Sampling"); + expect(html).toContain('href="/docs/glossary/top-p-sampling"'); expect(html).toContain("Parameter"); expect(html).toContain('href="/docs/glossary/parameter"'); expect(html).toContain("Activation"); expect(html).toContain('href="/docs/glossary/activation"'); - expect(html).toContain("ReLU"); - expect(html).toContain('href="/docs/glossary/relu"'); - expect(html).toContain("LeakyReLU"); - expect(html).toContain('href="/docs/glossary/leaky-relu"'); expect(html).toContain("Computational Graph"); expect(html).toContain('href="/docs/glossary/computational-graph"'); + expect(html).toContain("KV cache"); + expect(html).toContain('href="/docs/glossary/kv-cache"'); + expect(html).toContain("Decode"); + expect(html).toContain('href="/docs/glossary/decode"'); + expect(html).toContain("Prefill"); + expect(html).toContain('href="/docs/glossary/prefill"'); + expect(html).toContain("Prefill/decode split"); + expect(html).toContain('href="/docs/glossary/prefill-decode-split"'); expect(html).not.toContain("No glossary entries yet"); expect(html).toContain("list-none"); expect(html).not.toContain("list-disc"); diff --git a/src/tests/search/orama-index.test.ts b/src/tests/search/orama-index.test.ts index ab08f9d2..da457498 100644 --- a/src/tests/search/orama-index.test.ts +++ b/src/tests/search/orama-index.test.ts @@ -27,21 +27,45 @@ const PAGE_SPEC_WORKFLOW_SAMPLE_URL = "/docs/concepts/page-spec-workflow-sample"; const FEED_FORWARD_NETWORK_URL = "/docs/glossary/feed-forward-network"; const STANDARD_FFN_URL = "/docs/glossary/standard-ffn"; +const NORMALIZATION_URL = "/docs/glossary/normalization"; +const LAYER_NORM_URL = "/docs/glossary/layer-norm"; +const BATCH_NORM_URL = "/docs/glossary/batch-norm"; +const GROUP_NORM_URL = "/docs/glossary/group-norm"; +const MIXTURE_OF_EXPERTS_URL = "/docs/glossary/mixture-of-experts"; const RELU_URL = "/docs/glossary/relu"; const LEAKY_RELU_URL = "/docs/glossary/leaky-relu"; const SILU_URL = "/docs/glossary/silu"; const SWIGLU_URL = "/docs/glossary/swiglu"; -const MIXTURE_OF_EXPERTS_URL = "/docs/glossary/mixture-of-experts"; -const LAYER_NORM_URL = "/docs/glossary/layer-norm"; const RMSNORM_URL = "/docs/glossary/rmsnorm"; -const NORMALIZATION_URL = "/docs/glossary/normalization"; +const QK_NORM_URL = "/docs/glossary/qk-norm"; const RESIDUAL_CONNECTION_URL = "/docs/glossary/residual-connection"; +const SKIP_CONNECTION_URL = "/docs/glossary/skip-connection"; const POSITIONAL_ENCODINGS_URL = "/docs/concepts/positional-encodings"; const ROPE_URL = "/docs/glossary/rope"; const ALIBI_URL = "/docs/glossary/alibi"; const CONTEXT_WINDOW_URL = "/docs/glossary/context-window"; +const KV_CACHE_URL = "/docs/glossary/kv-cache"; +const PREFILL_URL = "/docs/glossary/prefill"; +const DECODE_URL = "/docs/glossary/decode"; +const PREFILL_DECODE_SPLIT_URL = "/docs/glossary/prefill-decode-split"; +const SAMPLING_OVERVIEW_URL = "/docs/glossary/sampling-overview"; +const GREEDY_DECODING_URL = "/docs/glossary/greedy-decoding"; +const TOP_K_SAMPLING_URL = "/docs/glossary/top-k-sampling"; +const TOP_P_SAMPLING_URL = "/docs/glossary/top-p-sampling"; const CONTEXT_EXTENSION_URL = "/docs/concepts/context-extension"; const WHY_LONG_CONTEXT_IS_HARD_URL = "/docs/concepts/why-long-context-is-hard"; +const QUANTIZATION_URL = "/docs/concepts/quantization"; +const POST_TRAINING_QUANTIZATION_URL = + "/docs/concepts/post-training-quantization"; +const CALIBRATION_URL = "/docs/concepts/calibration"; +const QUANTIZATION_AWARE_TRAINING_URL = + "/docs/concepts/quantization-aware-training"; +const DYNAMIC_QUANTIZATION_URL = "/docs/concepts/dynamic-quantization"; +const WEIGHT_ONLY_QUANTIZATION_URL = "/docs/concepts/weight-only-quantization"; +const ACTIVATION_QUANTIZATION_URL = "/docs/concepts/activation-quantization"; +const KV_CACHE_QUANTIZATION_URL = "/docs/concepts/kv-cache-quantization"; +const WHY_FOUR_BIT_MODELS_ARE_NOT_EXACTLY_FOUR_X_FASTER_URL = + "/docs/concepts/why-4-bit-models-are-not-exactly-4x-faster"; const STRUCTURAL_TAXONOMY_URLS = [ "/docs/glossary/model", "/docs/glossary/architecture", @@ -69,6 +93,14 @@ const GENERATION_PARADIGM_URLS = [ "/docs/glossary/autoregressive-generation", "/docs/glossary/denoising-generation", "/docs/glossary/conditioning", + KV_CACHE_URL, + PREFILL_URL, + DECODE_URL, + PREFILL_DECODE_SPLIT_URL, + SAMPLING_OVERVIEW_URL, + GREEDY_DECODING_URL, + TOP_K_SAMPLING_URL, + TOP_P_SAMPLING_URL, ] as const; const TRAINING_BEHAVIOR_URLS = [ "/docs/glossary/alignment", @@ -117,22 +149,35 @@ const PUBLISHED_SEARCH_INDEX_URLS = [ TRANSFORMER_ARCHITECTURE_URL, PAGE_SPEC_WORKFLOW_SAMPLE_URL, FEED_FORWARD_NETWORK_URL, + BATCH_NORM_URL, + GROUP_NORM_URL, STANDARD_FFN_URL, + MIXTURE_OF_EXPERTS_URL, RELU_URL, LEAKY_RELU_URL, SILU_URL, SWIGLU_URL, - MIXTURE_OF_EXPERTS_URL, LAYER_NORM_URL, RMSNORM_URL, NORMALIZATION_URL, + QK_NORM_URL, RESIDUAL_CONNECTION_URL, + SKIP_CONNECTION_URL, POSITIONAL_ENCODINGS_URL, ROPE_URL, ALIBI_URL, CONTEXT_WINDOW_URL, CONTEXT_EXTENSION_URL, WHY_LONG_CONTEXT_IS_HARD_URL, + QUANTIZATION_URL, + POST_TRAINING_QUANTIZATION_URL, + CALIBRATION_URL, + QUANTIZATION_AWARE_TRAINING_URL, + DYNAMIC_QUANTIZATION_URL, + WEIGHT_ONLY_QUANTIZATION_URL, + ACTIVATION_QUANTIZATION_URL, + KV_CACHE_QUANTIZATION_URL, + WHY_FOUR_BIT_MODELS_ARE_NOT_EXACTLY_FOUR_X_FASTER_URL, ...STRUCTURAL_TAXONOMY_URLS, ...ROLE_MODALITY_TAXONOMY_URLS, ...REPRESENTATION_LATENT_URLS, @@ -222,6 +267,16 @@ describe("exportOramaIndexSnapshot", () => { { query: "multi-head attention", url: MULTI_HEAD_ATTENTION_URL }, { query: "MQA", url: MULTI_QUERY_ATTENTION_URL }, { query: "multi-query attention", url: MULTI_QUERY_ATTENTION_URL }, + { query: "feed-forward network", url: FEED_FORWARD_NETWORK_URL }, + { query: "standard FFN", url: STANDARD_FFN_URL }, + { query: "normalization", url: NORMALIZATION_URL }, + { query: "layer norm", url: LAYER_NORM_URL }, + { query: "batch norm", url: BATCH_NORM_URL }, + { query: "group norm", url: GROUP_NORM_URL }, + { query: "RMSNorm", url: RMSNORM_URL }, + { query: "QK norm", url: QK_NORM_URL }, + { query: "residual connection", url: RESIDUAL_CONNECTION_URL }, + { query: "skip connection", url: SKIP_CONNECTION_URL }, ] as const)("Orama database records rank %s for the %s alias query", async ({ query, url,