diff --git a/.claude/launch.json b/.claude/launch.json index 0cc1c06..0f14c4b 100644 --- a/.claude/launch.json +++ b/.claude/launch.json @@ -1,17 +1,17 @@ { - "version": "0.0.1", - "configurations": [ - { - "name": "dev", - "runtimeExecutable": "npm", - "runtimeArgs": ["run", "dev", "--", "--port", "5181", "--strictPort"], - "port": 5181 - }, - { - "name": "preview", - "runtimeExecutable": "npm", - "runtimeArgs": ["run", "preview"], - "port": 4173 - } - ] + "version": "0.0.1", + "configurations": [ + { + "name": "dev", + "runtimeExecutable": "npm", + "runtimeArgs": ["run", "dev", "--", "--port", "5181", "--strictPort"], + "port": 5181 + }, + { + "name": "preview", + "runtimeExecutable": "npm", + "runtimeArgs": ["run", "preview"], + "port": 4173 + } + ] } diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..bedb172 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,37 @@ +name: CI + +on: + pull_request: + push: + branches-ignore: [main] # main is covered by deploy.yml + workflow_dispatch: + +permissions: + contents: read + +jobs: + quality: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: npm + + - run: npm ci + + # Formatting + lint (prettier --check . && eslint .) + - run: npm run lint + + # Type + Svelte diagnostics + - run: npm run check + + # Content integrity: every cross-referenced id must resolve + - run: npm run validate + + # Unit tests (vitest) + e2e (playwright builds + previews internally) + - run: npm run test:unit + - run: npx playwright install --with-deps chromium + - run: npm run test:e2e diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index d07b670..00f67e7 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -26,6 +26,11 @@ jobs: cache: npm - run: npm ci + + # Quality gates β€” never deploy a red baseline. + - run: npm run lint + - run: npm run check + - run: npm run build env: BASE_PATH: '/${{ github.event.repository.name }}' diff --git a/.prettierignore b/.prettierignore index 7d74fe2..02abbad 100644 --- a/.prettierignore +++ b/.prettierignore @@ -7,3 +7,13 @@ bun.lockb # Miscellaneous /static/ + +# Prose / content working docs β€” authored as freeform Markdown, not code. +# Prettier's markdown reformatting is non-idempotent on this long-form content +# and adds no value here, so keep them out of the format/check gate. +/research/ +/podcast-blueprints/ +/deep-research-prompts.txt +/outreach-emails.md +/build/ +/.svelte-kit/ diff --git a/CLAUDE.md b/CLAUDE.md index 124100b..d6799fe 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -12,36 +12,36 @@ In dev mode (`npm run dev`), a `window.__dev` object is exposed for agent and te **Available methods:** -| Method | Description | -|---|---| -| `__dev.go(id, view?)` | Navigate to a protocol/category by ID. `view` is `'learn'` (default) or `'simulate'`. | -| `__dev.step(n?)` | Click Step Forward `n` times (default 1). | -| `__dev.play()` | Click the Play button to start the simulation. | -| `__dev.scrollTo(text)` | Scroll to a heading containing `text` (e.g., `'Encapsulation'`). | -| `__dev.ls()` | List all node IDs and types. | -| `__dev.appState` | Direct access to the AppState instance (viewport, layoutMode, selectedNode, theme, etc.). | -| `__dev.nodes` | Static array of GraphNode objects (for ID/metadata lookup, not live positions). | -| `__dev.journey(id)` | Start a journey by ID. | -| `__dev.journeyNext()` | Advance to the next journey step. | -| `__dev.journeyPrev()` | Go back to the previous journey step. | -| `__dev.journeyExit()` | Exit the current journey. | +| Method | Description | +| ---------------------- | ----------------------------------------------------------------------------------------- | +| `__dev.go(id, view?)` | Navigate to a protocol/category by ID. `view` is `'learn'` (default) or `'simulate'`. | +| `__dev.step(n?)` | Click Step Forward `n` times (default 1). | +| `__dev.play()` | Click the Play button to start the simulation. | +| `__dev.scrollTo(text)` | Scroll to a heading containing `text` (e.g., `'Encapsulation'`). | +| `__dev.ls()` | List all node IDs and types. | +| `__dev.appState` | Direct access to the AppState instance (viewport, layoutMode, selectedNode, theme, etc.). | +| `__dev.nodes` | Static array of GraphNode objects (for ID/metadata lookup, not live positions). | +| `__dev.journey(id)` | Start a journey by ID. | +| `__dev.journeyNext()` | Advance to the next journey step. | +| `__dev.journeyPrev()` | Go back to the previous journey step. | +| `__dev.journeyExit()` | Exit the current journey. | **Changing layout mode:** ```js -window.__dev.appState.layoutMode = 'radial'; // 'force', 'radial', or 'timeline' +window.__dev.appState.layoutMode = 'radial'; // 'force', 'radial', or 'timeline' ``` **Typical agent workflow for verifying a simulation:** ```js // 1. Wait for page load, then navigate -new Promise(r => setTimeout(r, 2000)).then(() => { - window.__dev.go('tls', 'simulate'); // open TLS in simulate tab +new Promise((r) => setTimeout(r, 2000)).then(() => { + window.__dev.go('tls', 'simulate'); // open TLS in simulate tab }); // 2. Step through and inspect -window.__dev.step(3); // advance 3 steps +window.__dev.step(3); // advance 3 steps // 3. Scroll to see encapsulation cards window.__dev.scrollTo('Encapsulation'); diff --git a/IMPROVEMENT_PLAN.md b/IMPROVEMENT_PLAN.md new file mode 100644 index 0000000..ab09e77 --- /dev/null +++ b/IMPROVEMENT_PLAN.md @@ -0,0 +1,406 @@ +# Protocol Lab β€” Improvement Plan + +A phased, test-driven plan to address the findings from the codebase audit. The +guiding principle: **establish a safety net before changing anything, and make +every change independently verifiable.** Phases are ordered so that each one is +validated against a known-green baseline established by the phase before it. + +Legend: πŸ”΄ high Β· 🟠 medium Β· 🟒 low. Each task lists **Change**, **How it's +tested**, and **Commit boundary**. + +--- + +## Phase 0 β€” Baselines & safety net (prerequisite for everything) + +You cannot detect regressions against a red baseline. Before any refactor, we +need (a) a green `check`/`lint`, (b) a test runner, and (c) recorded reference +metrics. Phases 1–2 deliver this. + +### Reference metrics to capture first (no code change) + +- **Bundle baseline:** record `du -sh build/_app/immutable` and the per-chunk + sizes (`du -k build/_app/immutable/chunks/*.js | sort -rn | head`). Current: + total ~4.2 MB, largest chunk `CGRapOf_.js` = **1.2 MB** (contains protocol + prose + d3 + mermaid + hljs all fused). +- **Visual baseline:** Playwright screenshots of the graph (force/radial/timeline), + one protocol detail panel, one simulation mid-playback, mobile viewport. These + become golden references for later refactors. +- Save both into `docs/baselines/` so later phases can diff against them. + +--- + +## Phase 1 β€” Green the type/lint/format baseline πŸ”΄ + +**Why first:** a 589-file prettier reformat creates an enormous diff. Doing it +_before_ any logic change keeps real changes reviewable. Each step here is +mechanical and independently verifiable. + +### 1a. Fix the 3 TypeScript errors (logic, not formatting) + +- `SequencePlayer.svelte:149` β€” `definition` possibly undefined β†’ add a guard or + non-null assertion after confirming the invariant. +- `SequencePlayer.svelte:208` β€” `getBBox` not on `SVGElement` β†’ narrow to + `SVGGraphicsElement` (which declares `getBBox`). +- `DetailPanel.svelte:734` β€” a `SubcategoryStory` is passed where `CategoryStory` + is required. **Investigate the real intent** β€” this is a genuine type mismatch, + not a cast. Either the prop type should be a union, or the wrong value is being + passed. Do not paper over with `as`. +- **How it's tested:** `npm run check` β†’ 0 errors. Manually exercise the + SequencePlayer (a protocol simulation diagram) and the DetailPanel branch that + hits line 734 (a subcategory story view) in the browser to confirm no runtime + break. +- **Commit:** `fix(types): resolve 3 svelte-check errors` + +### 1b. Fix non-formatting ESLint errors (the ~67 that aren't escapes) + +- `@typescript-eslint/no-unused-vars` (~28): remove dead vars/imports + (`windowHeight`, `FOUNDATION_TEASERS`, `navigateToBookChapter`, + `foundationSections`, `totalParts`, …). **Verify each is truly dead** β€” grep + for usage before deleting; some may indicate a half-wired feature. +- `svelte/no-navigation-without-resolve` (~13): wrap `goto()`/href targets with + `resolve()` from `$app/paths` per the lint rule. +- `svelte/no-at-html-tags`: audit each `{@html}` site. The content is + self-authored (not user input), so these are low-risk, but confirm the source + is always static data and add an `eslint-disable-next-line` with a justifying + comment rather than leaving a bare error. +- `svelte/prefer-svelte-reactivity` (Map) and `non_reactive_update` + (`containerEl` in StoryDiagramModal): these are real reactivity smells β€” fix + by using `$state`/`SvelteMap` as the rule suggests. +- **How it's tested:** `npm run check` stays at 0; targeted browser check of each + touched component; `npx eslint .` error count drops to only the escape errors. +- **Commit:** `fix(lint): clear unused-vars, navigation, and reactivity errors` + +### 1c. The 537 `no-useless-escape` errors β€” surgical, NOT regex + +- ⚠️ **Do not** run a global `s/\\'/'/g`. The errors are a mix: `\'` inside + template literals is unnecessary, but some flagged `` \` `` are inside + single/double-quoted strings while _other_ backticks inside template literals + are genuinely required. A blind regex will corrupt template literals. +- **Approach:** write a one-off codemod (`scripts/fix-useless-escapes.ts`) that + consumes ESLint's JSON output (`eslint --format json`), which gives exact + `{file, line, column}` for each flagged character, and removes **only** the + backslash at those precise positions (process each file's edits + right-to-left so columns don't shift). +- **How it's tested:** This is the highest-risk mechanical change because it + edits content strings. + 1. Before: `git stash`-clean tree, run `npm run build`, save the built data + chunk bytes. + 2. Run the codemod. + 3. `npx eslint .` β†’ escape errors gone. + 4. `npm run build` and **diff the rendered text**: write a tiny script that + imports `allProtocols`/book parts and asserts no string contains a stray + backslash that changed meaning. Better: render-snapshot a few pages + (Playwright `textContent`) before and after and diff β€” the visible text must + be identical except for the intended apostrophes. + 5. Spot-check the `` \` `` sites (e.g. famous-outages.ts:174) by eye. +- **Commit:** `fix(content): remove unnecessary string escapes (codemod)` + +### 1d. Prettier the repo + +- `npm run format` (writes 589 files). +- **How it's tested:** `npm run build` output bytes for JS chunks should be + **byte-identical** to the pre-format build (formatting must not change emitted + code). Confirm `git diff --stat` shows only whitespace/quote churn. +- **Commit:** `style: apply prettier across repo` (isolated, reviewable as + "formatting only") + +### 1e. Wire the gates into CI + +- Add to `.github/workflows/deploy.yml` (and ideally a separate `ci.yml` that + runs on PRs): `npm run check`, `npm run lint`, `npm run test`. +- Add a lightweight pre-commit guard (lint-staged + a `prepare` hook, or a simple + `husky` pre-commit) running `prettier --check` + `eslint` on staged files only, + so the baseline can't regress. +- **How it's tested:** push a branch with a deliberate lint error and confirm CI + fails; revert. +- **Commit:** `ci: enforce check/lint/test on PRs + pre-commit` + +--- + +## Phase 2 β€” Test infrastructure (the safety net) πŸ”΄ + +No unit runner exists today and there is exactly one trivial e2e test. Every +later phase depends on this. Build it before touching engine/data/components. + +### 2a. Add Vitest for pure logic + +- Install `vitest` + `@vitest/ui`; add `"test:unit": "vitest run"` and fold into + `"test"`. Configure via `vite.config.ts` (SvelteKit + Vitest share it). +- **Target the pure, high-value functions** (no DOM needed): + - `src/lib/engine/layouts.ts` β€” radial/timeline/force target positions: + assert deterministic coordinates for a fixed node set, no overlaps, correct + ring assignment. + - `src/lib/engine/simulation.ts` β€” `warmUpSimulation`, `syncPositions` + (regression test for the index-vs-id matching issue in Phase 7). + - `src/lib/utils/` β€” `math.ts`, `colors.ts` (`themedDomColor`), + `text-parser.ts`, `sequence-parser.ts`, `navigation.ts`. These parse the + `[[id|label]]` / `{{concept}}` markup that the whole content layer relies on β€” + they are the highest-leverage unit tests in the repo. + - The cross-reference validator from Phase 3 (test it against a known-good and + a deliberately-broken fixture). +- **How it's tested:** `npm run test:unit` green; coverage report shows the + parser/layout/util modules covered. +- **Commit:** `test: add vitest + unit tests for engine/util/parser logic` + +### 2b. Expand Playwright e2e for critical user paths + +- Use the `window.__dev` helper (documented in CLAUDE.md) to drive deterministic + navigation. Add specs: + 1. **Graph loads** β†’ canvas present, node count matches data, no console errors. + 2. **Node select** β†’ `__dev.go('tcp')` opens detail panel with correct title; + close restores graph. + 3. **Layout switch** β†’ force/radial/timeline each settle without error; compare + against visual baselines (Playwright `toHaveScreenshot`). + 4. **Simulation** β†’ `__dev.go('tls','simulate'); __dev.step(3)` advances the + step timeline; play/pause works. + 5. **Search** β†’ type a query, arrow-key to a result, Enter navigates. + 6. **Journey** β†’ `__dev.journey(id)` β†’ next/prev/exit. + 7. **Mobile** β†’ 375px viewport: accordion + detail sheet render; no horizontal + scroll. + 8. **Routes prerender** β†’ smoke-load `/`, `/p/tcp`, `/rfcs`, `/pioneers`, + `/outages`, `/glossary`, a `/book/[part]` and `/journey/[id]`; assert 200 + + `

` + unique ``. +- Mark screenshot tests with a small pixel tolerance to avoid flakiness. +- **How it's tested:** `npm run test:e2e` green locally and in CI. +- **Commit:** `test: e2e coverage for graph, detail, sim, search, journey, mobile` + +### 2c. Delete demo scaffolding + +- Remove `src/routes/demo/**` (the `/demo` and `/demo/playwright` fixtures) once + the real e2e suite replaces the placeholder spec. +- **How it's tested:** build + e2e still green; grep confirms nothing links to + `/demo`. +- **Commit:** `chore: remove demo scaffolding routes` + +--- + +## Phase 3 β€” Build-time content validation πŸ”΄ (cheap, high insurance) + +The data is consistent today, but nothing prevents a typo'd ID across 75 +protocol files + journeys + comparisons + RFCs + book slots. + +### 3a. Cross-reference validator + +- `scripts/validate-cross-references.ts`: load every registry and assert all + referential IDs resolve: + - `protocol.connections[]`, `relatedProtocols` β†’ protocol IDs + - `journey.steps[].protocolId` β†’ protocol IDs + - `comparison/pairs.ts` ids β†’ protocol IDs + - `rfcs[].protocols[]`, `outages`/`pioneers` protocol refs β†’ protocol IDs + - `protocol.categoryId` β†’ category IDs; subcategory `protocolIds` β†’ protocol IDs + - book `ChapterSlot` targets β†’ existing protocol/sim/story/chapter + - `[[id|label]]`, `{{concept}}`, `[[rfc:n]]` inline refs across prose (reuse the + parser from 2a) β†’ resolve to real entries +- Exit non-zero with a readable list on failure. +- Add `"validate": "tsx scripts/validate-cross-references.ts"` and chain into + `"build": "npm run validate && vite build"` + the CI job. +- **How it's tested:** unit test (2a) feeds it a broken fixture β†’ expects failure; + run against current repo β†’ expects pass. Intentionally break one ID on a + branch β†’ CI red. +- **Commit:** `feat(scripts): build-time cross-reference validator + wire to build` + +### 3b. (Optional, after 3a is green) Branded ID types + +- In `types.ts`, introduce `ProtocolId`/`CategoryId` brands to document intent + and catch literal typos at review time. Low urgency; do only if it doesn't + cause churn. Skip if it fights the existing data-authoring ergonomics β€” the + runtime validator (3a) already covers correctness. +- **How it's tested:** `npm run check` stays green. + +--- + +## Phase 4 β€” Bundle & performance πŸ”΄ + +Now that tests + bundle baselines exist, optimize with proof. Re-measure chunk +sizes after each step and assert the target shrank without breaking e2e. + +### 4a. Stop importing the full registry into the root layout + +- `+layout.svelte:6` imports `allProtocols` only to show a count. Replace with a + tiny derived constant (e.g. export `PROTOCOL_COUNT` from a 1-line module, or + compute at build via the validator). This is the single biggest lever β€” it + pulls the entire protocol registry into the entry chunk. +- **How it's tested:** rebuild; assert the entry/layout chunk no longer contains + protocol prose (`grep -c "Transmission Control Protocol"` on the layout chunk β†’ + 0); e2e count display still correct. +- **Commit:** `perf(bundle): drop full-registry import from root layout` + +### 4b. Dynamic-import heavy page-specific data + +- Move into route-loader `import()`s so they split out of the entry bundle: + `journeys.ts` (116 KB), `diagram-definitions.ts` (140 KB), `rfcs.ts` (120 KB), + `book/parts/*` (580 KB), `concepts.ts` where feasible. +- Each route's `+page.ts` loads only what it renders. Keep prerender working + (dynamic import is fine under adapter-static). +- **How it's tested:** per-route e2e still green; measure that the protocol + detail route chunk no longer bundles journeys/book; total transferred JS for a + cold `/p/tcp` load drops (Playwright network capture). +- **Commit:** `perf(bundle): lazy-load journeys/rfcs/book/diagrams per route` + +### 4c. Dynamic-import highlight.js + +- `CodeExample.svelte` statically imports hljs core + 8 language packs (~150 KB). + Switch to `await import()` on mount (mirroring the pattern MermaidDiagram + already uses). Register only the languages actually present in the data. +- **How it's tested:** e2e on a page with a code example confirms highlighting + still renders; entry chunk shrinks by ~150 KB. +- **Commit:** `perf(bundle): dynamic-import highlight.js + only used languages` + +### 4d. manualChunks for the fused vendor chunk + +- The 1.2 MB chunk fuses d3 + mermaid + hljs + content. After 4a–4c, add Vite + `build.rollupOptions.output.manualChunks` to separate vendor (`d3-force`, + `d3-quadtree`) from content so the graph engine and prose cache independently. +- **How it's tested:** rebuild; assert no single chunk > ~500 KB; e2e green; + compare against Phase 0 baseline and record the win in `docs/baselines/`. +- **Commit:** `perf(bundle): split vendor/content chunks` + +--- + +## Phase 5 β€” Component de-duplication 🟠 + +Pure refactors β€” the Phase 2 visual/e2e suite is the regression guard. Refactor +one group at a time, screenshot-diff after each. + +### 5a. `GenericLink` for the 6 inline link components + +- `detail/inline/{Chapter,Frontier,Glossary,Outage,Pioneer,Protocol}Link.svelte` + share one shape (fetch entity by id β†’ derive color/tooltip β†’ render `<a>` or + fallback `<span>`). Extract `GenericLink.svelte` taking `fetch`/`getHref`/ + `getTooltip` callbacks; reduce each to a thin wrapper. ~330 lines reclaimable. +- **How it's tested:** these links appear throughout prose β€” run the e2e that + opens several detail pages and asserts links resolve + hover tooltips work; + screenshot-diff a content-dense page before/after (must be pixel-identical). +- **Commit:** `refactor(inline): unify 6 link components into GenericLink` + +### 5b. `ModalShell` for the 3 modals + +- `DiagramModal`, `StoryDiagramModal`, `StoryImageModal` share backdrop / header / + close / escape-key / backdrop-click. Extract `ModalShell.svelte` with content + slot; fold the focus-trap work from Phase 6 into it (one place to get a11y + right). +- **How it's tested:** e2e opens each modal type, asserts escape + backdrop-click + close, content renders; screenshot-diff. +- **Commit:** `refactor(modals): extract ModalShell` + +### 5c. Centralize Mermaid init + +- Three components duplicate the mermaid `initialize({...})` config. Move to + `utils/mermaid-helpers.ts` (`initMermaid()` returning the configured instance). +- **How it's tested:** e2e renders a mermaid diagram in each of the three call + sites; visual-diff. +- **Commit:** `refactor(mermaid): single init helper` + +--- + +## Phase 6 β€” Accessibility 🟠 + +### 6a. Focus trap + restore in modals + +- Implement in the new `ModalShell` (5b): on open, move focus into the dialog and + trap Tab; on close, restore focus to the trigger. Add visible focus styling to + `AccessibleGraph` tree items. +- **How it's tested:** e2e keyboard-only flow β€” open modal, Tab cycles within, + Escape closes and focus returns to trigger. Manual screen-reader smoke (VoiceOver). +- **Commit:** `a11y: focus trap/restore in modals + visible tree focus` + +### 6b. Respect `prefers-reduced-motion` in DetailPanel + +- The slide-in animations (`slideInRight`/`slideInUp`) ignore reduced-motion. + Add `@media (prefers-reduced-motion: reduce) { animation: none }`. (The graph + bloom already checks `prefersReducedMotion.current` β€” match that behavior.) +- **How it's tested:** e2e with `prefersReducedMotion` emulation + (`page.emulateMedia({ reducedMotion: 'reduce' })`) asserts the panel appears + without animation; default still animates. +- **Commit:** `a11y: honor reduced-motion in detail panel` + +--- + +## Phase 7 β€” Engine / render-loop efficiency 🟠 + +Guarded by the Phase 2a unit tests on `layouts.ts`/`simulation.ts` and the +visual e2e. None of these are correctness bugs today, so land them only with +before/after evidence (FPS via `requestAnimationFrame` timing, or render-call +counts behind a dev flag). + +### 7a. `syncPositions` match by id, not index + +- `simulation.ts` aligns sim/graph nodes by array index. Switch to id-keyed + matching to prevent silent desync. **Add the regression unit test first** + (2a), then change the code so the test proves the fix. +- **Commit:** `fix(engine): match sim positions by id` + +### 7b. Memoize per-frame map rebuilds + +- `canvas-renderer.ts` rebuilds `NODE_MAP`/connected-id sets every frame. Cache + keyed on `(nodes.length, selectedNode?.id, journey?.id)`; rebuild only on change. +- **Commit:** `perf(render): memoize node/connection maps` + +### 7c. Evict settled hover/dim animations; pool gradients + +- Delete animation-map entries when a node settles (`hoverT===0 && target===0`). + Reuse a small gradient pool instead of `createLinearGradient` per shooting-star + per frame. +- **Commit:** `perf(render): evict settled anims, pool gradients` + +### 7d. Frame-rate-independent viewport lerp + +- `app-state.svelte.ts:404` uses a fixed `t=0.09` assuming 60 fps (settles 2Γ— + fast on 120 Hz). Pass `dt` and use `1 - 0.9^(dt/16.67)`. +- **How it's tested:** unit-test the easing function for equal settle-time across + simulated dt values; visual e2e unchanged. +- **Commit:** `fix(viewport): delta-time-normalized lerp` + +> AppState decomposition (splitting the 30+-property god object into +> chrome/interaction/modal/navigation slices) is noted but **deferred** β€” high +> blast radius, low immediate payoff. Revisit only if it keeps growing. + +--- + +## Phase 8 β€” Hygiene & SEO 🟒 + +### 8a. Sitemap + JSON-LD + +- Generate `sitemap.xml` at build (endpoint or prerender script) covering `/`, + all `/p/[id]`, `/rfcs`, `/pioneers`, `/outages`, `/book/*`, `/journey/*`. Add + `EducationalResource` JSON-LD in `+layout.svelte`. +- **How it's tested:** build; assert `build/sitemap.xml` lists every prerendered + route (cross-check against the route manifest); validate XML. +- **Commit:** `feat(seo): sitemap.xml + JSON-LD` + +### 8b. Compress og-image + +- `static/og-image.png` is 1.8 MB. Re-encode to <200 KB (it's a social card, + 1200Γ—630). +- **How it's tested:** visual check it still looks right; size assertion. +- **Commit:** `chore: compress og-image` + +### 8c. Repo cleanup + docs + +- Remove `outreach-emails.md` from git (looks like a local artifact); add + `research/` to `.gitignore` if it's scratch. Add `scripts/README.md` + documenting the content-pipeline tools (wrap-bare-_, densify-_, audit-\*, + validate-cross-references) and the content-authoring workflow. +- **How it's tested:** `git status` clean; links in README resolve. +- **Commit:** `docs: document scripts + clean repo artifacts` + +--- + +## Execution order & rollback + +1. Phase 0 (measure) β†’ 1 (green baseline) β†’ 2 (tests) β†’ 3 (validator). **These + four are the foundation; do them strictly in order.** +2. Phases 4–8 can then proceed in roughly any order; recommended 4 β†’ 7 (perf + together) β†’ 5 β†’ 6 (component + a11y together) β†’ 8 (hygiene last). +3. Every task is a single focused commit on a feature branch with its own + verification. If a phase's verification fails, revert that commit β€” no phase + depends on a later one. + +## Definition of done (per task) + +- `npm run check` β†’ 0 errors +- `npm run lint` β†’ 0 errors +- `npm run test` (unit + e2e) β†’ green +- For perf tasks: measured before/after recorded in `docs/baselines/` +- For refactors: screenshot-diff identical +- CI green on the PR diff --git a/docs/baselines/bundle-baseline.md b/docs/baselines/bundle-baseline.md new file mode 100644 index 0000000..4efb612 --- /dev/null +++ b/docs/baselines/bundle-baseline.md @@ -0,0 +1,58 @@ +# Baseline metrics + +- Commit: `afa4450` (branch `improvement-pass-1`, captured 2026-06-19) +- Build time: ~10.8s, `npm run build` green + +## Client bundle (`build/_app/immutable`) + +- **Total raw:** 6.5 MB +- **Total client JS gzipped (sum of all chunks):** **1973 KB (~1.93 MB)** + +### Largest client JS chunks (hashes change per build; identity by content) + +| Raw | Gzip | Contents | +| ------: | -----: | ---------------------------------------------------------------- | +| 1516 KB | 466 KB | protocol-prose + mermaid + hljs + driver.js (fused shared chunk) | +| 1016 KB | 352 KB | protocol-prose + hljs | +| 584 KB | 211 KB | protocol-prose | +| 476 KB | 131 KB | mermaid + driver.js | +| 444 KB | 105 KB | mermaid | + +### Key problems confirmed + +- `mermaid`, `hljs`, `driver.js`, and protocol prose are fused into the largest shared chunk β†’ loaded eagerly on every page. +- `+layout.svelte` imports `allProtocols` (full registry) just for a count. +- `static/og-image.png` = **1.8 MB** (social card; should be <200 KB). + +## Targets after Phase 4 + +- Largest single chunk < 500 KB raw. +- mermaid / hljs / driver.js split out and loaded on demand. +- Total client JS gzipped reduced meaningfully on cold first paint. + +## Phase 4 result (measured on the prerendered `/`) + +Method: parse `build/index.html` for its initial chunk set, sum raw+gzip, check +for vendor markers. The Vite build is non-deterministic (chunk hashes vary per +build), so all measurement must happen within a single build. + +- **Initial JS on `/`: ~3488 KB raw, ~1171 KB gzip (23 chunks).** +- `highlight.js`: **now lazy** β€” CodeExample loads core + 8 grammars via dynamic + `import()` on mount, so ~138 KB gz no longer ships on first paint (only when a + code example renders). Verified: grammar code absent from the initial chunk + set; highlighting still applies in-browser. +- `mermaid` and `driver.js`: confirmed lazy (dynamic `import()`); no static + importer pulls them into the initial graph. (A "sequenceDiagram" string in an + initial chunk is diagram-definition _content_, not the library.) + +## Remaining opportunity (deferred β€” high blast radius) + +Most of the 1171 KB gz initial load is hand-authored **prose** statically +imported via `buildGraphNodes()` (full `Protocol` objects), `concepts.ts` +(~416 KB raw), and `diagram-definitions.ts` (~140 KB raw). The graph only needs +protocol _metadata_ (id/name/category/connections), not the long-form fields. +Splitting `Protocol` into always-loaded metadata + lazily-loaded per-protocol +content would cut first paint substantially β€” but the content layer resolves +`[[id]]`/`{{concept}}` refs synchronously (text-parser, detail panels), so it's +a real refactor needing care, not a mechanical change. Left for a focused, +well-tested pass rather than this autonomous run. diff --git a/e2e/app.e2e.ts b/e2e/app.e2e.ts new file mode 100644 index 0000000..f09058b --- /dev/null +++ b/e2e/app.e2e.ts @@ -0,0 +1,143 @@ +import { expect, test, type Page } from '@playwright/test'; + +/** + * End-to-end smoke + critical-path coverage. These run against the production + * build (`npm run build && npm run preview`), so the dev-only `window.__dev` + * helper is unavailable β€” every test drives the app through real URLs and + * clicks, the same way a user (or a crawler) would. + */ + +/** Collect console errors so a test can assert the page stayed clean. */ +function trackConsoleErrors(page: Page): string[] { + const errors: string[] = []; + page.on('console', (msg) => { + if (msg.type() === 'error') errors.push(msg.text()); + }); + page.on('pageerror', (err) => errors.push(String(err))); + return errors; +} + +test.describe('home / graph', () => { + test('loads the graph canvas with the right title and no console errors', async ({ page }) => { + const errors = trackConsoleErrors(page); + await page.goto('/'); + await expect(page).toHaveTitle(/Protocol Lab/); + const canvas = page.locator('canvas').first(); + await expect(canvas).toBeVisible(); + const box = await canvas.boundingBox(); + expect(box?.width ?? 0).toBeGreaterThan(100); + expect(box?.height ?? 0).toBeGreaterThan(100); + expect(errors, errors.join('\n')).toEqual([]); + }); +}); + +test.describe('protocol detail', () => { + test('navigating to /p/tcp opens the TCP panel with overview prose', async ({ page }) => { + await page.goto('/p/tcp'); + await expect(page).toHaveTitle(/TCP/); + await expect(page.getByRole('heading', { name: 'TCP', exact: true })).toBeVisible(); + // Overview mentions TCP somewhere in the prose body. + await expect( + page.getByText(/Transmission Control Protocol|backbone of the internet/i).first() + ).toBeVisible(); + }); + + test('the Simulate tab reveals the step-driven simulator', async ({ page }) => { + await page.goto('/p/tcp'); + await page + .getByRole('button', { name: /Simulate/i }) + .first() + .click(); + await expect(page.locator('[data-tour="simulator-view"]')).toBeVisible(); + // A playback control should be present (Play / Step). + await expect(page.getByRole('button', { name: /Play|Step/i }).first()).toBeVisible(); + }); + + test('code examples highlight after the lazy highlight.js loads', async ({ page }) => { + // http1 ships a code example; highlight.js is dynamically imported on mount. + await page.goto('/p/http1'); + const code = page.locator('[data-tour="code-example"] code.hljs').first(); + await expect(code).toBeVisible(); + // Once hljs resolves it wraps tokens in <span class="hljs-…">. + await expect(code.locator('span[class^="hljs-"]').first()).toBeVisible(); + }); + + test('404s on an unknown protocol id', async ({ page }) => { + const res = await page.goto('/p/definitely-not-a-protocol'); + // adapter-static serves the SvelteKit error page; status may be 200 for the + // fallback shell, so assert on the rendered error text instead. + await expect(page.getByText(/not found|404|Unknown protocol/i).first()).toBeVisible(); + expect(res).toBeTruthy(); + }); +}); + +test.describe('category & subcategory', () => { + test('/c/transport renders the Transport category', async ({ page }) => { + await page.goto('/c/transport'); + await expect(page.getByText(/Transport/i).first()).toBeVisible(); + }); + + test('/s/link-layer renders the subcategory guide', async ({ page }) => { + await page.goto('/s/link-layer'); + await expect(page.locator('h2').first()).toBeVisible(); + }); +}); + +test.describe('search', () => { + test('typing a query surfaces matching results', async ({ page }) => { + await page.goto('/'); + // Open search (button labelled for screen readers) then type. + const searchTrigger = page.getByRole('button', { name: /search/i }).first(); + if (await searchTrigger.isVisible().catch(() => false)) { + await searchTrigger.click(); + } + const input = page.getByRole('textbox').first(); + await input.fill('TCP'); + await expect(page.getByRole('option').first()).toBeVisible(); + }); +}); + +test.describe('registry & book pages', () => { + const pages: [string, RegExp][] = [ + ['/rfcs', /RFC/i], + ['/pioneers', /Pioneers/i], + ['/outages', /Outage/i], + ['/glossary', /Glossary/i], + ['/frontier', /Frontier/i], + ['/book/foundations', /.+/], + ['/journey/url-bar', /.+/] + ]; + + for (const [path, titleRe] of pages) { + test(`${path} prerenders and shows content`, async ({ page }) => { + const errors = trackConsoleErrors(page); + await page.goto(path); + await expect(page).toHaveTitle(titleRe); + // Registry "pages" render in the side panel; some lead with h3 sub-heads + // (glossary) rather than an h1/h2, so accept any structural heading. + await expect(page.locator('h1, h2, h3').first()).toBeVisible(); + expect(errors, errors.join('\n')).toEqual([]); + }); + } +}); + +test.describe('accessibility', () => { + test('reduced-motion users still get the detail panel content', async ({ page }) => { + await page.emulateMedia({ reducedMotion: 'reduce' }); + await page.goto('/p/tcp'); + // The slide-in animation is collapsed to ~instant; content must still render. + await expect(page.getByRole('heading', { name: 'TCP', exact: true })).toBeVisible(); + }); +}); + +test.describe('mobile', () => { + test.use({ viewport: { width: 375, height: 812 } }); + + test('protocol detail renders as a bottom sheet on a phone viewport', async ({ page }) => { + await page.goto('/p/tcp'); + await expect(page.getByRole('heading', { name: 'TCP', exact: true })).toBeVisible(); + // No horizontal overflow on a narrow viewport. + const scrollWidth = await page.evaluate(() => document.documentElement.scrollWidth); + expect(scrollWidth).toBeLessThanOrEqual(375 + 1); + }); +}); diff --git a/eslint.config.js b/eslint.config.js index bf092d2..f447599 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -22,7 +22,28 @@ export default defineConfig( rules: { // typescript-eslint strongly recommend that you do not use the no-undef lint rule on TypeScript projects. // see: https://typescript-eslint.io/troubleshooting/faqs/eslint/#i-get-errors-from-the-no-undef-rule-about-global-variables-not-being-defined-even-though-there-are-no-typescript-errors - 'no-undef': 'off' + 'no-undef': 'off', + + // Allow intentionally-unused identifiers prefixed with `_` (placeholder + // destructure targets, ignored callback args). + '@typescript-eslint/no-unused-vars': [ + 'error', + { argsIgnorePattern: '^_', varsIgnorePattern: '^_', caughtErrorsIgnorePattern: '^_' } + ], + + // This project deliberately centralizes base-path handling: navigation.ts + // prefixes every goto() with `${base}`, and inline links build hrefs as + // `{base}/...`. That is a correct, deployed pattern for the GitHub Pages + // sub-path. resolve() would be an equivalent restyle of ~20 call sites with + // no behavioral gain, so we opt out of this stylistic rule. + 'svelte/no-navigation-without-resolve': 'off', + + // Every Map/Set in this codebase is an ephemeral local built inside a + // `$derived.by()` / helper function, or a non-reactive cache used by the + // canvas render loop β€” never reactive component state. SvelteMap/SvelteSet + // would add proxy overhead for no benefit, so this rule is all false + // positives here. + 'svelte/prefer-svelte-reactivity': 'off' } }, { diff --git a/package-lock.json b/package-lock.json index 8c75934..1dc68a7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,6 +28,7 @@ "@types/d3-force": "^3.0.10", "@types/d3-quadtree": "^3.0.6", "@types/node": "^24", + "@vitest/coverage-v8": "^4.1.9", "eslint": "^9.39.2", "eslint-config-prettier": "^10.1.8", "eslint-plugin-svelte": "^3.14.0", @@ -38,9 +39,11 @@ "svelte": "^5.51.0", "svelte-check": "^4.4.2", "tailwindcss": "^4.1.18", + "tsx": "^4.22.4", "typescript": "^5.9.3", "typescript-eslint": "^8.54.0", - "vite": "^7.3.1" + "vite": "^7.3.1", + "vitest": "^4.1.9" } }, "node_modules/@antfu/install-pkg": { @@ -56,6 +59,66 @@ "url": "https://github.com/sponsors/antfu" } }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/@braintree/sanitize-url": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-7.1.2.tgz", @@ -1284,7 +1347,6 @@ "integrity": "sha512-WDJApQ1ipZLbaC4YjqJjwYR9y7QQgTqVwEObgNZ8Mu/eVQJqn4Qzw9a+n7mr5xnBYiAYz9UdJOOl+aqVbfGXcA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@standard-schema/spec": "^1.0.0", "@sveltejs/acorn-typescript": "^1.0.5", @@ -1327,7 +1389,6 @@ "integrity": "sha512-ou/d51QSdTyN26D7h6dSpusAKaZkAiGM55/AKYi+9AGZw7q85hElbjK3kEyzXHhLSnRISHOYzVge6x0jRZ7DXA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@sveltejs/vite-plugin-svelte-inspector": "^5.0.0", "deepmerge": "^4.3.1", @@ -1646,6 +1707,17 @@ "vite": "^5.2.0 || ^6 || ^7" } }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, "node_modules/@types/cookie": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", @@ -1906,6 +1978,13 @@ "@types/d3-selection": "*" } }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -1931,7 +2010,6 @@ "integrity": "sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~7.16.0" } @@ -1987,7 +2065,6 @@ "integrity": "sha512-XZzOmihLIr8AD1b9hL9ccNMzEMWt/dE2u7NyTY9jJG6YNiNthaD5XtUHVF2uCXZ15ng+z2hT3MVuxnUYhq6k1g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.57.0", "@typescript-eslint/types": "8.57.0", @@ -2235,12 +2312,155 @@ "d3-transition": "^3.0.1" } }, + "node_modules/@vitest/coverage-v8": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.9.tgz", + "integrity": "sha512-G9/lgqibheLVBDRuya45EbsEXTYcWoSG+TLg7i2axuzx0Eq62eXn+aWXyaVdV5vKvFSWd6ywcX8hA7la9Pvu8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^1.0.2", + "@vitest/utils": "4.1.9", + "ast-v8-to-istanbul": "^1.0.0", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.2.0", + "magicast": "^0.5.2", + "obug": "^2.1.1", + "std-env": "^4.0.0-rc.1", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/browser": "4.1.9", + "vitest": "4.1.9" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + } + } + }, + "node_modules/@vitest/expect": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.9.tgz", + "integrity": "sha512-vl/rYsUKcBr3SnQn166+XR5ZQcgMx3DQhFWdfli/cWpLnLUmbxZvyrJZotLFUryib+LtArYMSTJ5RbQ57ZqrlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.1.9", + "@vitest/utils": "4.1.9", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.9.tgz", + "integrity": "sha512-EVkXzBjrPGM+cK8/ANWgBrkUCfJfb38/EfTSO8h7pWvKkyPkpWxvR7BkD2MyItMF62C97zAEoqdpUixwR/e+Rw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.1.9", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.9.tgz", + "integrity": "sha512-s0iufns3iIFitdgm+YR7g1whCAaGtXz459VS9/PqyKDEEFgYIhsHOQmXgIgDuYCt7DeQmiZT0Qe2OA2p4ZPu5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.9.tgz", + "integrity": "sha512-KXLMDtc7oe70+3mJfGrPUWPesswH+3sTxAMAMl8DG7I8IUQT4XW718dY5ID3vPUcmlu27CcKfY4P3h3I29SLJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.1.9", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.9.tgz", + "integrity": "sha512-Jc7RKGNBo8Z28WYIm0Niej4xdSPByRf6mU58VpHQkd6Zh05rlnA+twjbK5HyeIGHxrzsc3mJgS43uM0CZKzaIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.9", + "@vitest/utils": "4.1.9", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.9.tgz", + "integrity": "sha512-fHpsS6mIi+PiEW+vcRVOMkX1oSaPKne3VOclSFICPcGOmfKgXPU5iAah+wcNcj2xPrCCmfq99IDGf+EojhhvhA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.9.tgz", + "integrity": "sha512-A51o8ymO5PpqlWNnBP9ZHPXDIpuMtTLlGSjN7la4US+LJzoUMyhwjA5QXlm39JexgwHKW4Xjs8Z2d3dLCXOeuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.9", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, "node_modules/acorn": { "version": "8.16.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2307,6 +2527,28 @@ "node": ">= 0.4" } }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/ast-v8-to-istanbul": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.4.tgz", + "integrity": "sha512-0bC0/4bTSrnwdhU3IsZDwEdojvuPrSg59OYZfKsLRtJZ0u8VBx9DebfqqG8bRdCC0I7vjgxmPi41P0lpkhJHtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.31", + "estree-walker": "^3.0.3", + "js-tokens": "^10.0.0" + } + }, "node_modules/axobject-query": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", @@ -2344,6 +2586,16 @@ "node": ">=6" } }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -2366,7 +2618,6 @@ "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.1.2.tgz", "integrity": "sha512-opLQzEVriiH1uUQ4Kctsd49bRoFDXGGSC4GUqj7pGyxM3RehRhvTlZJc1FL/Flew2p5uwxa1tUDWKzI4wNM8pg==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@chevrotain/cst-dts-gen": "11.1.2", "@chevrotain/gast": "11.1.2", @@ -2455,6 +2706,13 @@ "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", "license": "MIT" }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, "node_modules/cookie": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", @@ -2507,7 +2765,6 @@ "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.33.1.tgz", "integrity": "sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10" } @@ -2908,7 +3165,6 @@ "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", "license": "ISC", - "peer": true, "engines": { "node": ">=12" } @@ -3098,6 +3354,13 @@ "node": ">=10.13.0" } }, + "node_modules/es-module-lexer": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz", + "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==", + "dev": true, + "license": "MIT" + }, "node_modules/esbuild": { "version": "0.27.3", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", @@ -3159,7 +3422,6 @@ "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -3389,6 +3651,16 @@ "node": ">=4.0" } }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -3399,6 +3671,16 @@ "node": ">=0.10.0" } }, + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -3562,6 +3844,13 @@ "node": ">=12.0.0" } }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -3659,6 +3948,45 @@ "dev": true, "license": "ISC" }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/jiti": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", @@ -3669,6 +3997,13 @@ "jiti": "lib/jiti-cli.mjs" } }, + "node_modules/js-tokens": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz", + "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==", + "dev": true, + "license": "MIT" + }, "node_modules/js-yaml": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", @@ -4121,6 +4456,34 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, + "node_modules/magicast": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.3.tgz", + "integrity": "sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.3", + "@babel/types": "^7.29.0", + "source-map-js": "^1.2.1" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/marked": { "version": "16.4.2", "resolved": "https://registry.npmjs.org/marked/-/marked-16.4.2.tgz", @@ -4365,7 +4728,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -4452,7 +4814,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -4586,7 +4947,6 @@ "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -4603,7 +4963,6 @@ "integrity": "sha512-65+fr5+cgIKWKiqM1Doum4uX6bY8iFCdztvvp2RcF+AJoieaw9kJOFMNcJo/bkmKYsxFaM9OsVZK/gWauG/5mg==", "dev": true, "license": "MIT", - "peer": true, "peerDependencies": { "prettier": "^3.0.0", "svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0" @@ -4853,6 +5212,13 @@ "node": ">=8" } }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, "node_modules/sirv": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", @@ -4878,6 +5244,20 @@ "node": ">=0.10.0" } }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz", + "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==", + "dev": true, + "license": "MIT" + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -4915,7 +5295,6 @@ "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.53.10.tgz", "integrity": "sha512-UcNfWzbrjvYXYSk+U2hME25kpb87oq6/WVLeBF4khyQrb3Ob/URVlN23khal+RbdCUTMfg4qWjI9KZjCNFtYMQ==", "license": "MIT", - "peer": true, "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", @@ -5012,8 +5391,7 @@ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.1.tgz", "integrity": "sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/tapable": { "version": "2.3.0", @@ -5029,6 +5407,13 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, "node_modules/tinyexec": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", @@ -5055,6 +5440,16 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/tinyrainbow": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", + "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/totalist": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", @@ -5087,43 +5482,560 @@ "node": ">=6.10" } }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "node_modules/tsx": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.22.4.tgz", + "integrity": "sha512-X8EX+XV4QR5xCsrgxaED954zTDfY8KqlDtskKEL0cHhyS/P8b4IFOvGDQpsC9Q1XnLq915wEfwwY/zzskCtmhg==", "dev": true, "license": "MIT", "dependencies": { - "prelude-ls": "^1.2.1" + "esbuild": "~0.28.0" }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "peer": true, "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" + "tsx": "dist/cli.mjs" }, "engines": { - "node": ">=14.17" + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" } }, - "node_modules/typescript-eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.57.0.tgz", - "integrity": "sha512-W8GcigEMEeB07xEZol8oJ26rigm3+bfPHxHvwbYUlu1fUDsGuQ7Hiskx5xGW/xM4USc9Ephe3jtv7ZYPQntHeA==", + "node_modules/tsx/node_modules/@esbuild/aix-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", + "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", + "cpu": [ + "ppc64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@typescript-eslint/eslint-plugin": "8.57.0", - "@typescript-eslint/parser": "8.57.0", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", + "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", + "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", + "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", + "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", + "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", + "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", + "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", + "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", + "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", + "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-loong64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", + "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", + "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", + "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", + "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-s390x": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", + "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", + "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", + "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", + "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", + "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", + "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", + "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/sunos-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", + "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", + "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", + "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", + "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/esbuild": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", + "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.1", + "@esbuild/android-arm": "0.28.1", + "@esbuild/android-arm64": "0.28.1", + "@esbuild/android-x64": "0.28.1", + "@esbuild/darwin-arm64": "0.28.1", + "@esbuild/darwin-x64": "0.28.1", + "@esbuild/freebsd-arm64": "0.28.1", + "@esbuild/freebsd-x64": "0.28.1", + "@esbuild/linux-arm": "0.28.1", + "@esbuild/linux-arm64": "0.28.1", + "@esbuild/linux-ia32": "0.28.1", + "@esbuild/linux-loong64": "0.28.1", + "@esbuild/linux-mips64el": "0.28.1", + "@esbuild/linux-ppc64": "0.28.1", + "@esbuild/linux-riscv64": "0.28.1", + "@esbuild/linux-s390x": "0.28.1", + "@esbuild/linux-x64": "0.28.1", + "@esbuild/netbsd-arm64": "0.28.1", + "@esbuild/netbsd-x64": "0.28.1", + "@esbuild/openbsd-arm64": "0.28.1", + "@esbuild/openbsd-x64": "0.28.1", + "@esbuild/openharmony-arm64": "0.28.1", + "@esbuild/sunos-x64": "0.28.1", + "@esbuild/win32-arm64": "0.28.1", + "@esbuild/win32-ia32": "0.28.1", + "@esbuild/win32-x64": "0.28.1" + } + }, + "node_modules/tsx/node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.57.0.tgz", + "integrity": "sha512-W8GcigEMEeB07xEZol8oJ26rigm3+bfPHxHvwbYUlu1fUDsGuQ7Hiskx5xGW/xM4USc9Ephe3jtv7ZYPQntHeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.57.0", + "@typescript-eslint/parser": "8.57.0", "@typescript-eslint/typescript-estree": "8.57.0", "@typescript-eslint/utils": "8.57.0" }, @@ -5188,7 +6100,6 @@ "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", @@ -5293,6 +6204,96 @@ } } }, + "node_modules/vitest": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.9.tgz", + "integrity": "sha512-nE3/LEyc0z87uHYLZebqCUOaJr2hdtuPp7BQ4BosVFnfltxgAvMG08NyrSGlPpOUWvR27c5flSmYFTNr78L9GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.1.9", + "@vitest/mocker": "4.1.9", + "@vitest/pretty-format": "4.1.9", + "@vitest/runner": "4.1.9", + "@vitest/snapshot": "4.1.9", + "@vitest/spy": "4.1.9", + "@vitest/utils": "4.1.9", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^4.0.0-rc.1", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.1.9", + "@vitest/browser-preview": "4.1.9", + "@vitest/browser-webdriverio": "4.1.9", + "@vitest/coverage-istanbul": "4.1.9", + "@vitest/coverage-v8": "4.1.9", + "@vitest/ui": "4.1.9", + "happy-dom": "*", + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "vite": { + "optional": false + } + } + }, "node_modules/vscode-jsonrpc": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", @@ -5358,6 +6359,23 @@ "node": ">= 8" } }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", diff --git a/package.json b/package.json index 70a07e2..2864572 100644 --- a/package.json +++ b/package.json @@ -5,15 +5,18 @@ "type": "module", "scripts": { "dev": "vite dev", - "build": "vite build", + "validate": "tsx scripts/validate-cross-references.ts", + "build": "npm run validate && vite build", "preview": "vite preview", "prepare": "svelte-kit sync || echo ''", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "lint": "prettier --check . && eslint .", "format": "prettier --write .", + "test:unit": "vitest run", + "test:unit:watch": "vitest", "test:e2e": "playwright test", - "test": "npm run test:e2e" + "test": "npm run test:unit && npm run test:e2e" }, "devDependencies": { "@eslint/compat": "^2.0.2", @@ -27,6 +30,7 @@ "@types/d3-force": "^3.0.10", "@types/d3-quadtree": "^3.0.6", "@types/node": "^24", + "@vitest/coverage-v8": "^4.1.9", "eslint": "^9.39.2", "eslint-config-prettier": "^10.1.8", "eslint-plugin-svelte": "^3.14.0", @@ -37,9 +41,11 @@ "svelte": "^5.51.0", "svelte-check": "^4.4.2", "tailwindcss": "^4.1.18", + "tsx": "^4.22.4", "typescript": "^5.9.3", "typescript-eslint": "^8.54.0", - "vite": "^7.3.1" + "vite": "^7.3.1", + "vitest": "^4.1.9" }, "dependencies": { "@jis3r/icons": "^2.7.0", diff --git a/scripts/audit-acronyms.ts b/scripts/audit-acronyms.ts index 014749b..83f6f09 100644 --- a/scripts/audit-acronyms.ts +++ b/scripts/audit-acronyms.ts @@ -141,11 +141,21 @@ const BLOCKLIST = new Set([ 'OK', 'CIA', 'FBI', - 'NSA', // organisations covered elsewhere if needed + 'NSA' // organisations covered elsewhere if needed ]); // HTTP verbs β€” handled in their own way, not concepts. -const HTTP_VERBS = new Set(['GET', 'PUT', 'POST', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS', 'CONNECT', 'TRACE']); +const HTTP_VERBS = new Set([ + 'GET', + 'PUT', + 'POST', + 'DELETE', + 'PATCH', + 'HEAD', + 'OPTIONS', + 'CONNECT', + 'TRACE' +]); function walk(dir: string, out: string[] = []): string[] { for (const n of readdirSync(dir)) { @@ -226,7 +236,8 @@ function stripMarkup(src: string): string { } function lineColOf(src: string, idx: number): { line: number; col: number } { - let line = 1, col = 1; + let line = 1, + col = 1; for (let i = 0; i < idx; i++) { if (src.charCodeAt(i) === 10) { line++; @@ -278,7 +289,8 @@ for (const c of concepts) { // uppercase letters, optionally with embedded digits / slashes / dots / // hyphens, that AREN'T sentence-initial common words. Lookarounds // prevent matching inside larger camelCase or word tokens. -const ACRONYM_RE = /(?<![A-Za-z0-9_])([A-Z][A-Z0-9](?:[A-Z0-9./-]*[A-Z0-9])?)(?:s|s')?(?![A-Za-z0-9_])/g; +const ACRONYM_RE = + /(?<![A-Za-z0-9_])([A-Z][A-Z0-9](?:[A-Z0-9./-]*[A-Z0-9])?)(?:s|s')?(?![A-Za-z0-9_])/g; // Plural-friendly variant: also catch "RTTs", "ACKs", etc. // The capturing group is the acronym, the suffix is optional. @@ -445,5 +457,7 @@ console.log(' protocol (needs link):', knownProtocol.length); console.log(' http-verb:', httpVerbs.length); console.log('\nTop unknowns:'); for (const u of unknownAcronyms.slice(0, 40)) { - console.log(` ${u.stem.padEnd(10)} ${u.totalCount.toString().padStart(4)} ${u.sampleContext.slice(0, 80)}`); + console.log( + ` ${u.stem.padEnd(10)} ${u.totalCount.toString().padStart(4)} ${u.sampleContext.slice(0, 80)}` + ); } diff --git a/scripts/audit-terms.ts b/scripts/audit-terms.ts index 76d212a..c71b28f 100644 --- a/scripts/audit-terms.ts +++ b/scripts/audit-terms.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ /** * audit-terms.ts β€” Densification audit. * @@ -133,10 +132,7 @@ function lineColOf(src: string, idx: number): { line: number; col: number } { function snippet(src: string, idx: number, len: number): string { const start = Math.max(0, idx - 30); const end = Math.min(src.length, idx + len + 30); - return src - .slice(start, end) - .replace(/\s+/g, ' ') - .trim(); + return src.slice(start, end).replace(/\s+/g, ' ').trim(); } function findFirstUnwrapped( @@ -196,7 +192,12 @@ function scanFile(absPath: string): FileReport { .filter(([num]) => !rfcSet.has(num)) .map(([num, { idx }]) => { const lc = lineColOf(src, idx); - return { number: num, line: lc.line, col: lc.col, context: snippet(src, idx, 4 + num.length) }; + return { + number: num, + line: lc.line, + col: lc.col, + context: snippet(src, idx, 4 + num.length) + }; }) .sort((a, b) => Number(a.number) - Number(b.number)); @@ -223,9 +224,7 @@ function scanFile(absPath: string): FileReport { const hit = findFirstUnwrapped(stripped, src, re); if (!hit) continue; const lc = lineColOf(src, hit.idx); - const priority: 'high' | 'low' = LOW_PRIORITY_TERMS.has(c.term.toLowerCase()) - ? 'low' - : 'high'; + const priority: 'high' | 'low' = LOW_PRIORITY_TERMS.has(c.term.toLowerCase()) ? 'low' : 'high'; unwrappedConcepts.push({ term: c.term, displayLabel: hit.matched, @@ -258,7 +257,8 @@ const allMissingPioneers = new Map<string, number>(); const allMissingConcepts = new Map<string, number>(); for (const r of reports) { - for (const h of r.missingRfcs) allMissingRfcs.set(h.number, (allMissingRfcs.get(h.number) ?? 0) + 1); + for (const h of r.missingRfcs) + allMissingRfcs.set(h.number, (allMissingRfcs.get(h.number) ?? 0) + 1); for (const h of r.unwrappedPioneers) allMissingPioneers.set(h.term, (allMissingPioneers.get(h.term) ?? 0) + 1); for (const h of r.unwrappedConcepts) @@ -317,8 +317,7 @@ md += `Editorial rule: wrap on first appearance per section, not every time. \`l const sortedConcepts = [...allMissingConcepts.entries()].sort((a, b) => b[1] - a[1]); md += `| Term | Files |\n|---|---:|\n`; -for (const [term, count] of sortedConcepts.slice(0, 60)) - md += `| ${term} | ${count} |\n`; +for (const [term, count] of sortedConcepts.slice(0, 60)) md += `| ${term} | ${count} |\n`; if (sortedConcepts.length > 60) md += `| _…${sortedConcepts.length - 60} more_ | |\n`; md += '\n'; @@ -343,4 +342,5 @@ console.log(` Missing RFCs: ${allMissingRfcs.size}`); console.log(` Unwrapped pioneers: ${allMissingPioneers.size} / ${pioneers.length}`); console.log(` Unwrapped concepts: ${allMissingConcepts.size} / ${concepts.length}`); console.log(' Top missing RFCs (by file count):'); -for (const [num, count] of sortedMissingRfcs.slice(0, 10)) console.log(` RFC ${num} (${count} files)`); +for (const [num, count] of sortedMissingRfcs.slice(0, 10)) + console.log(` RFC ${num} (${count} files)`); diff --git a/scripts/densify-concepts.ts b/scripts/densify-concepts.ts index 683ab61..10f7a09 100644 --- a/scripts/densify-concepts.ts +++ b/scripts/densify-concepts.ts @@ -287,8 +287,7 @@ function densifyString(src: string, stats: Map<string, WrapStat>): string { let lastIdx = 0; let m: RegExpExecArray | null; while ((m = tokenRe.exec(work)) !== null) { - if (m.index > lastIdx) - out.push(applyAlias(work.slice(lastIdx, m.index), alias, stat)); + if (m.index > lastIdx) out.push(applyAlias(work.slice(lastIdx, m.index), alias, stat)); out.push(m[0]); lastIdx = m.index + m[0].length; } @@ -314,11 +313,7 @@ function enclosingPropertyName(node: ts.Node): string | undefined { n = n.parent; continue; } - if ( - ts.isParenthesizedExpression(n) || - ts.isAsExpression(n) || - ts.isSatisfiesExpression(n) - ) { + if (ts.isParenthesizedExpression(n) || ts.isAsExpression(n) || ts.isSatisfiesExpression(n)) { n = n.parent; continue; } @@ -429,7 +424,9 @@ function main() { const { apply, files } = parseArgs(process.argv); const targets = files.length > 0 ? files : defaultTargets(); - console.log(`Concept aliases: ${ALIASES.length} (from ${concepts.length} concepts, ${BLOCKLIST.size} blocked)`); + console.log( + `Concept aliases: ${ALIASES.length} (from ${concepts.length} concepts, ${BLOCKLIST.size} blocked)` + ); let grandTotal = 0; const grandStats = new Map<string, number>(); @@ -450,7 +447,9 @@ function main() { .sort((a, b) => b.count - a.count) .slice(0, 8); for (const s of top) { - console.log(` ${s.id.padEnd(20)} ${String(s.count).padStart(4)} e.g. ${s.samples[0] ?? ''}`); + console.log( + ` ${s.id.padEnd(20)} ${String(s.count).padStart(4)} e.g. ${s.samples[0] ?? ''}` + ); } if (apply) { writeFileSync(f, result.updated, 'utf8'); @@ -459,7 +458,9 @@ function main() { } console.log('\n──────────────────────────────────────────'); - console.log(`Total wraps: ${grandTotal} across ${fileSummaries.filter((f) => f.total > 0).length} files`); + console.log( + `Total wraps: ${grandTotal} across ${fileSummaries.filter((f) => f.total > 0).length} files` + ); const sorted = [...grandStats.entries()].filter(([, n]) => n > 0).sort((a, b) => b[1] - a[1]); for (const [id, n] of sorted.slice(0, 20)) { console.log(` ${id.padEnd(20)} ${String(n).padStart(4)}`); diff --git a/scripts/densify-protocols.ts b/scripts/densify-protocols.ts index 505966a..ad30c32 100644 --- a/scripts/densify-protocols.ts +++ b/scripts/densify-protocols.ts @@ -153,12 +153,7 @@ interface WrapStat { * us from matching inside larger words (e.g. "TCP" in "MTCP" or "IP" * in "IPv6"). */ -function applyAlias( - text: string, - id: string, - alias: string, - stat: WrapStat -): string { +function applyAlias(text: string, id: string, alias: string, stat: WrapStat): string { // `\b` only fires next to ASCII word chars. The alias may *start* or // *end* with a non-word char (e.g. "Wi-Fi"), in which case the inner // `\b` is meaningless on that side; emulate the boundary with a @@ -182,10 +177,7 @@ function applyAlias( /** Tokenise a string into protected (`[[…]]`, `((…))`, `{{…}}`) and * plain regions, run a single alias on the plain ones, and rejoin. */ -function densifyString( - src: string, - stats: Map<string, WrapStat> -): string { +function densifyString(src: string, stats: Map<string, WrapStat>): string { let work = src; for (const entry of ALIASES) { const stat = stats.get(entry.id) ?? { id: entry.id, count: 0, samples: [] }; @@ -201,8 +193,7 @@ function densifyString( out.push(m[0]); lastIdx = m.index + m[0].length; } - if (lastIdx < work.length) - out.push(applyAlias(work.slice(lastIdx), entry.id, alias, stat)); + if (lastIdx < work.length) out.push(applyAlias(work.slice(lastIdx), entry.id, alias, stat)); work = out.join(''); } } @@ -339,11 +330,7 @@ function enclosingPropertyName(node: ts.Node): string | undefined { } // String inside a parenthesised / template / conditional expression β€” // keep climbing. - if ( - ts.isParenthesizedExpression(n) || - ts.isAsExpression(n) || - ts.isSatisfiesExpression(n) - ) { + if (ts.isParenthesizedExpression(n) || ts.isAsExpression(n) || ts.isSatisfiesExpression(n)) { n = n.parent; continue; } @@ -365,10 +352,7 @@ function processFile(filePath: string): FileResult { const edits: { start: number; end: number; replacement: string }[] = []; function visit(node: ts.Node) { - if ( - ts.isStringLiteral(node) || - ts.isNoSubstitutionTemplateLiteral(node) - ) { + if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) { const propName = enclosingPropertyName(node); const innerStart = node.getStart() + 1; const innerEnd = node.getEnd() - 1; @@ -413,9 +397,7 @@ function parseArgs(argv: string[]): { apply: boolean; files: string[] } { const list = a.slice('--files='.length).split(',').filter(Boolean); args.files = list.map((p) => (p.startsWith('/') ? p : join(REPO, p))); } else if (a === '--help' || a === '-h') { - console.log( - `Usage: npx tsx scripts/densify-protocols.ts [--apply] [--files=path,path]` - ); + console.log(`Usage: npx tsx scripts/densify-protocols.ts [--apply] [--files=path,path]`); process.exit(0); } } @@ -445,7 +427,9 @@ function main() { .sort((a, b) => b.count - a.count) .slice(0, 8); for (const s of top) { - console.log(` ${s.id.padEnd(10)} ${String(s.count).padStart(4)} e.g. ${s.samples[0] ?? ''}`); + console.log( + ` ${s.id.padEnd(10)} ${String(s.count).padStart(4)} e.g. ${s.samples[0] ?? ''}` + ); } if (apply) { writeFileSync(f, result.updated, 'utf8'); @@ -454,7 +438,9 @@ function main() { } console.log('\n──────────────────────────────────────────'); - console.log(`Total wraps: ${grandTotal} across ${fileSummaries.filter((f) => f.total > 0).length} files`); + console.log( + `Total wraps: ${grandTotal} across ${fileSummaries.filter((f) => f.total > 0).length} files` + ); const sorted = [...grandStats.entries()].filter(([, n]) => n > 0).sort((a, b) => b[1] - a[1]); for (const [id, n] of sorted) { console.log(` ${id.padEnd(10)} ${String(n).padStart(4)}`); diff --git a/scripts/densify-references.ts b/scripts/densify-references.ts index 52e8a75..aa3a013 100644 --- a/scripts/densify-references.ts +++ b/scripts/densify-references.ts @@ -75,7 +75,6 @@ function buildAliases(): RefAlias[] { }); } - // Longest first so multi-token pioneer names win over single tokens // they share (none today, but safe for future entries). out.sort((a, b) => b.pattern.length - a.pattern.length); @@ -192,8 +191,7 @@ function densifyString(src: string, stats: Map<string, WrapStat>): string { let lastIdx = 0; let m: RegExpExecArray | null; while ((m = tokenRe.exec(work)) !== null) { - if (m.index > lastIdx) - out.push(applyAlias(work.slice(lastIdx, m.index), alias, stat)); + if (m.index > lastIdx) out.push(applyAlias(work.slice(lastIdx, m.index), alias, stat)); out.push(m[0]); lastIdx = m.index + m[0].length; } @@ -215,11 +213,7 @@ function enclosingPropertyName(node: ts.Node): string | undefined { n = n.parent; continue; } - if ( - ts.isParenthesizedExpression(n) || - ts.isAsExpression(n) || - ts.isSatisfiesExpression(n) - ) { + if (ts.isParenthesizedExpression(n) || ts.isAsExpression(n) || ts.isSatisfiesExpression(n)) { n = n.parent; continue; } @@ -344,7 +338,9 @@ function main() { .sort((a, b) => b.count - a.count) .slice(0, 8); for (const s of top) { - console.log(` ${s.id.padEnd(28)} ${String(s.count).padStart(4)} e.g. ${s.samples[0] ?? ''}`); + console.log( + ` ${s.id.padEnd(28)} ${String(s.count).padStart(4)} e.g. ${s.samples[0] ?? ''}` + ); } if (apply) { writeFileSync(f, result.updated, 'utf8'); @@ -353,7 +349,9 @@ function main() { } console.log('\n──────────────────────────────────────────'); - console.log(`Total wraps: ${grandTotal} across ${fileSummaries.filter((f) => f.total > 0).length} files`); + console.log( + `Total wraps: ${grandTotal} across ${fileSummaries.filter((f) => f.total > 0).length} files` + ); const sorted = [...grandStats.entries()].filter(([, n]) => n > 0).sort((a, b) => b[1] - a[1]); for (const [id, n] of sorted.slice(0, 25)) { console.log(` ${id.padEnd(28)} ${String(n).padStart(4)}`); diff --git a/scripts/fix-useless-escapes.ts b/scripts/fix-useless-escapes.ts new file mode 100644 index 0000000..208dedd --- /dev/null +++ b/scripts/fix-useless-escapes.ts @@ -0,0 +1,86 @@ +/** + * fix-useless-escapes.ts β€” surgical removal of ESLint `no-useless-escape` + * violations. + * + * Why not a regex? A naive `s/\\'/'/g` would also strip backslashes that are + * REQUIRED β€” e.g. a backtick inside a template literal. ESLint has already done + * the context analysis: it flags only the backslashes that JavaScript ignores. + * This script consumes ESLint's JSON report and deletes exactly those + * backslash characters, by (line, column), processing each file's edits + * right-to-left so earlier column numbers stay valid. + * + * Safety: removing an *unnecessary* escape never changes a string's runtime + * value (`'\''` and `"'"` denote the same character), so the compiled bundle + * is byte-identical afterwards β€” that is the verification gate. + * + * Usage: + * npx eslint . --format json -o /tmp/eslint.json + * npx tsx scripts/fix-useless-escapes.ts /tmp/eslint.json + */ +import { readFileSync, writeFileSync } from 'node:fs'; + +interface EslintMessage { + ruleId: string | null; + line: number; + column: number; +} +interface EslintFileResult { + filePath: string; + messages: EslintMessage[]; +} + +const reportPath = process.argv[2]; +if (!reportPath) { + console.error('Usage: tsx scripts/fix-useless-escapes.ts <eslint-report.json>'); + process.exit(1); +} + +const report: EslintFileResult[] = JSON.parse(readFileSync(reportPath, 'utf8')); + +let filesChanged = 0; +let removed = 0; +let skipped = 0; + +for (const file of report) { + const targets = file.messages.filter((m) => m.ruleId === 'no-useless-escape'); + if (targets.length === 0) continue; + + const src = readFileSync(file.filePath, 'utf8'); + const lines = src.split('\n'); + + // Group by line, then apply each line's edits right-to-left. + const byLine = new Map<number, number[]>(); + for (const m of targets) { + const arr = byLine.get(m.line) ?? []; + arr.push(m.column); + byLine.set(m.line, arr); + } + + for (const [lineNo, columns] of byLine) { + const idx = lineNo - 1; + let line = lines[idx]; + // Descending column order so deletions don't shift later positions. + for (const col of columns.sort((a, b) => b - a)) { + const at = col - 1; // 1-based β†’ 0-based + if (line[at] === '\\') { + line = line.slice(0, at) + line.slice(at + 1); + removed++; + } else { + // Position didn't point at a backslash β€” refuse to guess. + console.warn( + ` ! ${file.filePath}:${lineNo}:${col} expected '\\' but found ${JSON.stringify(line[at])}; skipped` + ); + skipped++; + } + } + lines[idx] = line; + } + + writeFileSync(file.filePath, lines.join('\n')); + filesChanged++; +} + +console.log( + `Removed ${removed} unnecessary escapes across ${filesChanged} files (${skipped} skipped).` +); +if (skipped > 0) process.exit(2); diff --git a/scripts/output/acronym-audit.json b/scripts/output/acronym-audit.json index 31478b0..52dedf8 100644 --- a/scripts/output/acronym-audit.json +++ b/scripts/output/acronym-audit.json @@ -1,4699 +1,3544 @@ { - "unknown": [ - { - "stem": "FF", - "count": 12, - "files": [ - "src/lib/data/journeys.ts", - "src/lib/data/protocols/arp.ts" - ], - "sample": "to the {{broadcast|broadcast}} address (FF:FF:FF:FF:FF:FF) asking \"Who has 192.168" - }, - { - "stem": "BMW", - "count": 9, - "files": [ - "src/lib/data/book/parts/wireless.ts", - "src/lib/data/diagram-definitions.ts", - "src/lib/data/protocols/nfc.ts", - "src/lib/data/protocols/uwb.ts" - ], - "sample": "t bootstraps {{matter|Matter}}, unlocks BMWs, and broadcasts public hearing-loops ac" - }, - { - "stem": "R23", - "count": 9, - "files": [ - "src/lib/data/book/parts/wireless.ts", - "src/lib/data/journeys.ts", - "src/lib/data/protocols/zigbee.ts" - ], - "sample": "zigbee|IEEE 802.15.4 mesh]], Zigbee PRO R23 ({{dynamic-link-key|Dynamic Link Key}}," - }, - { - "stem": "AIP", - "count": 6, - "files": [ - "src/lib/data/journeys.ts", - "src/lib/data/protocols/nfc.ts" - ], - "sample": "After GET PROCESSING OPTIONS (returning AIP+{{afl|AFL}}) and {{read-record|READ REC" - }, - { - "stem": "GB", - "count": 6, - "files": [ - "src/lib/data/protocols/ipsec.ts", - "src/lib/data/protocols/nat-traversal.ts", - "src/lib/data/protocols/tcp.ts", - "src/lib/data/protocols/zigbee.ts" - ], - "sample": "-byte lifetime (default ~8 hours / ~100 GB). Before either limit is hit, peers run" - }, - { - "stem": "Q1", - "count": 5, - "files": [ - "src/lib/data/book/parts/transport.ts", - "src/lib/data/book/parts/web-api.ts", - "src/lib/data/protocols/uwb.ts", - "src/lib/data/protocols/zigbee.ts" - ], - "sample": "he in-kernel push', text: 'As of Q1 2026, [[quic|QUIC]] carries roughly **2" - }, - { - "stem": "OV", - "count": 5, - "files": [ - "src/lib/data/book/parts/wireless.ts", - "src/lib/data/protocols/nfc.ts" - ], - "sample": "to seconds of cloning time. **The Dutch OV-chipkaart kept shipping affected cards" - }, - { - "stem": "M3", - "count": 5, - "files": [ - "src/lib/data/book/parts/wireless.ts", - "src/lib/data/protocols/zigbee.ts" - ], - "sample": "atter}} devices* (Hue Bridge, Aqara Hub M3) translate {{matter|Matter}} operations" - }, - { - "stem": "II", - "count": 4, - "files": [ - "src/lib/data/book/parts/layer-2-3.ts", - "src/lib/data/category-stories/network-foundations.ts", - "src/lib/data/concept-foundations.ts", - "src/lib/data/protocols/zigbee.ts" - ], - "sample": "'The **[[ethernet|Ethernet]] Type II frame format** β€” six bytes of destinati" - }, - { - "stem": "F1", - "count": 4, - "files": [ - "src/lib/data/book/parts/utilities-security.ts", - "src/lib/data/protocols/cellular.ts", - "src/lib/data/protocols/ipsec.ts", - "src/lib/data/protocols/ntp.ts" - ], - "sample": "caption: '**{{nist|NIST}}-F1**, the caesium fountain atomic clock th" - }, - { - "stem": "SPEKE", - "count": 4, - "files": [ - "src/lib/data/journeys.ts", - "src/lib/data/protocols/zigbee.ts" - ], - "sample": "amic-link-key|Dynamic Link Key}}** with SPEKE-over-{{curve25519|Curve25519}} removes" - }, - { - "stem": "MAI", - "count": 4, - "files": [ - "src/lib/data/outages.ts" - ], - "sample": "the upstream took it.\", mistake: \"MAI Network Services ({{autonomous-system|A" - }, - { - "stem": "PCCW", - "count": 4, - "files": [ - "src/lib/data/outages.ts" - ], - "sample": "ocally. But Pakistan Telecom's upstream PCCW ({{autonomous-system|AS}} 3491) had no" - }, - { - "stem": "IKEA", - "count": 4, - "files": [ - "src/lib/data/protocols/mdns-dns-sd.ts", - "src/lib/data/protocols/zigbee.ts" - ], - "sample": "azon, Samsung, Aqara, Eve, Philips Hue, IKEA, Schlage, Yale, and dozens more.' }" - }, - { - "stem": "MUST", - "count": 3, - "files": [ - "src/lib/data/book/parts/layer-2-3.ts", - "src/lib/data/protocols/kerberos.ts" - ], - "sample": "t of [[ip|IP]].\"** Every [[ip|IP]] host MUST answer Echo Requests by spec. Dropping" - }, - { - "stem": "RS-232", - "count": 3, - "files": [ - "src/lib/data/book/parts/wireless.ts", - "src/lib/data/category-stories/wireless.ts" - ], - "sample": "pposed to be the wire that replaced the RS-232 cable to a mobile-phone headset. Thirty" - }, - { - "stem": "S1", - "count": 3, - "files": [ - "src/lib/data/book/parts/wireless.ts", - "src/lib/data/protocols/cellular.ts", - "src/lib/data/protocols/ipsec.ts" - ], - "sample": "ss network}} and the core (N2/N3 in 5G, S1 in {{lte|LTE}}) is wrapped in [[ipsec|I" - }, - { - "stem": "CONNECTED", - "count": 3, - "files": [ - "src/lib/data/book/parts/wireless.ts", - "src/lib/data/protocols/cellular.ts", - "src/lib/data/protocols/stomp.ts" - ], - "sample": "connection state machine β€” \\`RRC_IDLE β†’ CONNECTED β†’ INACTIVE\\` for 5G β€” and **{{nas|NAS}}" - }, - { - "stem": "ET", - "count": 3, - "files": [ - "src/lib/data/book/parts/wireless.ts", - "src/lib/data/protocols/uwb.ts" - ], - "sample": "text: 'On **22 February 2024 at 03:30 ET**, AT&T Mobility customers across the U" - }, - { - "stem": "AST", - "count": 3, - "files": [ - "src/lib/data/category-stories/wireless.ts", - "src/lib/data/protocols/cellular.ts" - ], - "sample": "}}\\'s Globalstar partnership and AT&T's AST SpaceMobile follow similar patterns. Re" - }, - { - "stem": "UDP/5353", - "count": 3, - "files": [ - "src/lib/data/diagram-definitions.ts", - "src/lib/data/protocols/mdns-dns-sd.ts" - ], - "sample": "-local {{multicast|multicast}} group on UDP/5353, with a probe/announce/respond/goodbye" - }, - { - "stem": "RX", - "count": 3, - "files": [ - "src/lib/data/journeys.ts" - ], - "sample": "n. The car (multiple anchors typically) RX-timestamps at t2, delays by `T_reply1`" - }, - { - "stem": "PARTNER.COM", - "count": 3, - "files": [ - "src/lib/data/protocols/kerberos.ts" - ], - "sample": "XAMPLE.COM wants to access a service in PARTNER.COM, her {{kerberos-kdc|KDC}} issues a **re" - }, - { - "stem": "PR", - "count": 3, - "files": [ - "src/lib/data/protocols/mdns-dns-sd.ts", - "src/lib/data/protocols/ospf.ts", - "src/lib/data/protocols/uwb.ts" - ], - "sample": "ded-clients DoS in 0.9-rc2 was fixed in PR #808.', source: { url: 'https://" - }, - { - "stem": "NIO", - "count": 3, - "files": [ - "src/lib/data/protocols/nfc.ts", - "src/lib/data/protocols/uwb.ts" - ], - "sample": "lone, including the first Chinese OEMs (NIO, XPENG, Geely group brands). Devices mu" - }, - { - "stem": "XPENG", - "count": 3, - "files": [ - "src/lib/data/protocols/nfc.ts", - "src/lib/data/protocols/uwb.ts" - ], - "sample": "including the first Chinese OEMs (NIO, XPENG, Geely group brands). Devices must supp" - }, - { - "stem": "T2", - "count": 3, - "files": [ - "src/lib/data/protocols/ntp.ts", - "src/lib/data/protocols/uwb.ts" - ], - "sample": "Server records when the packet arrives (T2) and when it sends the reply (T3). Both" - }, - { - "stem": "SIZE", - "count": 2, - "files": [ - "src/lib/data/book/parts/async-iot.ts", - "src/lib/data/journeys.ts" - ], - "sample": "he sentinel and uses an authoritative \\`SIZE\\` field. [[amqp|AMQP]] itself adds no a" - }, - { - "stem": "GA", - "count": 2, - "files": [ - "src/lib/data/book/parts/async-iot.ts" - ], - "sample": "protocol', text: '**RabbitMQ 4.0 GA (18 September 2024)** made [[amqp|AMQP]" - }, - { - "stem": "KIP-1150", - "count": 2, - "files": [ - "src/lib/data/book/parts/async-iot.ts" - ], - "sample": "ess Topics β€” KIP-1150', text: '**KIP-1150 \"Diskless Topics\"** was accepted by the" - }, - { - "stem": "S3", - "count": 2, - "files": [ - "src/lib/data/book/parts/async-iot.ts" - ], - "sample": "less / Bufstream architecture that uses S3 as primary storage. Brokers become {{st" - }, - { - "stem": "MD", - "count": 2, - "files": [ - "src/lib/data/book/parts/frontier.ts" - ], - "sample": "lorado Springs, Philadelphia, Rockville MD, San Francisco), with {{apple|Apple}}," - }, - { - "stem": "VSX", - "count": 2, - "files": [ - "src/lib/data/book/parts/realtime-av.ts", - "src/lib/data/category-stories/realtime-av.ts" - ], - "sample": "', caption: 'A **Polycom VSX 7000** video-conferencing system β€” the" - }, - { - "stem": "IIS", - "count": 2, - "files": [ - "src/lib/data/book/parts/realtime-av.ts", - "src/lib/data/protocols/http3.ts" - ], - "sample": "which was created in 1995 by Fraunhofer IIS for **WinPlay3** and popularised by **N" - }, - { - "stem": "TV", - "count": 2, - "files": [ - "src/lib/data/book/parts/realtime-av.ts", - "src/lib/data/protocols/mdns-dns-sd.ts" - ], - "sample": "y Netflix stream, every {{apple|Apple}} TV {{broadcast|broadcast}} β€” still starts" - }, - { - "stem": "EXT-X-PRELOAD-HINT", - "count": 2, - "files": [ - "src/lib/data/book/parts/realtime-av.ts", - "src/lib/data/protocols/hls.ts" - ], - "sample": "ttp2|HTTP/2]] push requirement with **\\`EXT-X-PRELOAD-HINT\\`** β€” a simpler, {{cdn|CDN}}-friendly h" - }, - { - "stem": "UCLA", - "count": 2, - "files": [ - "src/lib/data/book/parts/story-of-the-internet.ts", - "src/lib/data/category-stories/transport.ts" - ], - "sample": "-node network that became the internet. UCLA, SRI, UCSB, and Utah; one {{imp|IMP}} p" - }, - { - "stem": "SRI", - "count": 2, - "files": [ - "src/lib/data/book/parts/story-of-the-internet.ts", - "src/lib/data/category-stories/transport.ts" - ], - "sample": "network that became the internet. UCLA, SRI, UCSB, and Utah; one {{imp|IMP}} per si" - }, - { - "stem": "ISI", - "count": 2, - "files": [ - "src/lib/data/book/parts/story-of-the-internet.ts", - "src/lib/data/concept-foundations.ts" - ], - "sample": "'[[pioneer:jon-postel|Jon Postel]] at ISI. He edited [[rfc:791|RFC 791]] ([[ip|IP" - }, - { - "stem": "L7", - "count": 2, - "files": [ - "src/lib/data/book/parts/story-of-the-internet.ts", - "src/lib/data/book/parts/web-api.ts" - ], - "sample": "n the registry. The first genuinely new L7 protocol since [[websockets|WebSockets]" - }, - { - "stem": "WS", - "count": 2, - "files": [ - "src/lib/data/book/parts/utilities-security.ts", - "src/lib/data/comparison/pairs.ts" - ], - "sample": "dern protocol history. His core line: *\"WS-\\* bad\"* β€” shorthand among {{ietf|IETF}" - }, - { - "stem": "INACTIVE", - "count": 2, - "files": [ - "src/lib/data/book/parts/wireless.ts", - "src/lib/data/protocols/cellular.ts" - ], - "sample": "tate machine β€” \\`RRC_IDLE β†’ CONNECTED β†’ INACTIVE\\` for 5G β€” and **{{nas|NAS}}** carries" - }, - { - "stem": "AMPS", - "count": 2, - "files": [ - "src/lib/data/book/parts/wireless.ts", - "src/lib/data/protocols/cellular.ts" - ], - "sample": "[cellular|cellular]]** β€” from 1G analog AMPS / TACS / NMT in the early 1980s through" - }, - { - "stem": "NFC-A", - "count": 2, - "files": [ - "src/lib/data/book/parts/wireless.ts", - "src/lib/data/protocols/nfc.ts" - ], - "sample": "e flavours on the air', text: '**NFC-A** ({{iso|ISO}} 14443-A): {{pcd|PCD}}β†’{{" - }, - { - "stem": "OOK", - "count": 2, - "files": [ - "src/lib/data/book/parts/wireless.ts", - "src/lib/data/protocols/nfc.ts" - ], - "sample": "ed-Miller; {{picc|PICC}}β†’{{pcd|PCD}} is OOK Manchester on the 847.5 kHz subcarrier." - }, - { - "stem": "NFC-B", - "count": 2, - "files": [ - "src/lib/data/book/parts/wireless.ts", - "src/lib/data/protocols/nfc.ts" - ], - "sample": "Base rate 106 kbit/s, scaling to 848. **NFC-B** ({{iso|ISO}} 14443-B): {{pcd|PCD}}β†’{{" - }, - { - "stem": "NRZ-L", - "count": 2, - "files": [ - "src/lib/data/book/parts/wireless.ts", - "src/lib/data/protocols/nfc.ts" - ], - "sample": "cc|PICC}} is 10% {{ask-modulation|ASK}} NRZ-L; {{picc|PICC}}β†’{{pcd|PCD}} is {{bpsk|BP" - }, - { - "stem": "JIS", - "count": 2, - "files": [ - "src/lib/data/book/parts/wireless.ts", - "src/lib/data/protocols/nfc.ts" - ], - "sample": "assports. **{{nfc-f|NFC-F}}** (FeliCa / JIS X 6319-4): 212/424 kbit/s Manchester-co" - }, - { - "stem": "PASMO", - "count": 2, - "files": [ - "src/lib/data/book/parts/wireless.ts", - "src/lib/data/protocols/nfc.ts" - ], - "sample": "nt in Japan {{transit|transit}} (Suica, PASMO) and Hong Kong (Octopus). **{{nfc-v|NFC" - }, - { - "stem": "ETH", - "count": 2, - "files": [ - "src/lib/data/book/parts/wireless.ts", - "src/lib/data/protocols/uwb.ts" - ], - "sample": "u, Giovanni Camurati, and colleagues at ETH ZΓΌrich published **Ghost Peak** β€” an at" - }, - { - "stem": "D03", - "count": 2, - "files": [ - "src/lib/data/book/parts/wireless.ts", - "src/lib/data/protocols/uwb.ts" - ], - "sample": "eee-802-15-4|IEEE}} 802.15.4ab** (Draft D03 September 2025, ratification expected e" - }, - { - "stem": "ABI", - "count": 2, - "files": [ - "src/lib/data/book/parts/wireless.ts", - "src/lib/data/protocols/uwb.ts" - ], - "sample": "eness of [[uwb|UWB]] into one purchase. ABI projects [[uwb|UWB]] phone penetration" - }, - { - "stem": "PRO", - "count": 2, - "files": [ - "src/lib/data/book/parts/wireless.ts", - "src/lib/data/journeys.ts" - ], - "sample": "'[[zigbee|IEEE 802.15.4 mesh]], Zigbee PRO R23 ({{dynamic-link-key|Dynamic Link Ke" - }, - { - "stem": "RTSP", - "count": 2, - "files": [ - "src/lib/data/book/parts/wireless.ts", - "src/lib/data/protocols/zigbee.ts" - ], - "sample": "mber 2025)**, with camera streaming via RTSP, removing the last category that previo" - }, - { - "stem": "OASIS", - "count": 2, - "files": [ - "src/lib/data/category-stories/async-iot.ts", - "src/lib/data/diagram-definitions.ts" - ], - "sample": "ce the protocol and shepherd it through OASIS standardization.', imagePath:" - }, - { - "stem": "CEO", - "count": 2, - "files": [ - "src/lib/data/category-stories/async-iot.ts", - "src/lib/data/protocols/amqp.ts" - ], - "sample": "oyed [[amqp|AMQP]] broker. Later became CEO of Weaveworks, bringing messaging patte" - }, - { - "stem": "TIBCO", - "count": 2, - "files": [ - "src/lib/data/category-stories/async-iot.ts", - "src/lib/data/protocols/mdns-dns-sd.ts" - ], - "sample": "rneyed from Wall Street trading floors (TIBCO) to IoT sensors ([[mqtt|MQTT]]) to clou" - }, - { - "stem": "DIX", - "count": 2, - "files": [ - "src/lib/data/category-stories/network-foundations.ts" - ], - "sample": "c|Xerox PARC}} in 1973, co-authored the DIX [[ethernet|Ethernet]] standard (1980)," - }, - { - "stem": "DEC", - "count": 2, - "files": [ - "src/lib/data/category-stories/utilities.ts", - "src/lib/data/protocols/icmp.ts" - ], - "sample": "t infrastructure', caption: \"The DEC PDP-11 β€” machines like these ran early" - }, - { - "stem": "BIND", - "count": 2, - "files": [ - "src/lib/data/category-stories/utilities.ts", - "src/lib/data/protocols/dns.ts" - ], - "sample": "urity', contribution: 'Wrote BIND, the most widely deployed [[dns|DNS]] s" - }, - { - "stem": "HTML5", - "count": 2, - "files": [ - "src/lib/data/category-stories/web-api.ts", - "src/lib/data/protocols/sse.ts" - ], - "sample": "sse|Server-Sent Events]] as part of the HTML5 specification, enabling simple server-t" - }, - { - "stem": "CMOS", - "count": 2, - "files": [ - "src/lib/data/category-stories/wireless.ts", - "src/lib/data/protocols/uwb.ts" - ], - "sample": "sh engineer who owned the analog RF and CMOS implementation work that paired with Ja" - }, - { - "stem": "IC", - "count": 2, - "files": [ - "src/lib/data/category-stories/wireless.ts", - "src/lib/data/protocols/nfc.ts" - ], - "sample": "Jaap Haartsen\\'s digital baseband. The IC-level decisions that made [[bluetooth|B" - }, - { - "stem": "FR2", - "count": 2, - "files": [ - "src/lib/data/category-stories/wireless.ts", - "src/lib/data/protocols/cellular.ts" - ], - "sample": "flexible numerology, {{mmwave|mmWave}} (FR2) support, network slicing. First commer" - }, - { - "stem": "RTT", - "count": 2, - "files": [ - "src/lib/data/category-stories/wireless.ts", - "src/lib/data/protocols/quic.ts" - ], - "sample": "Adopted 3 September 2024. Phase-based + RTT distance measurement on a new {{le-audi" - }, - { - "stem": "H1/H2", - "count": 2, - "files": [ - "src/lib/data/category-stories/wireless.ts", - "src/lib/data/protocols/bluetooth.ts" - ], - "sample": "m|Broadcom}}, Qualcomm, {{apple|Apple}} H1/H2) uses **time-division arbitration** at" - }, - { - "stem": "SMTPS", - "count": 2, - "files": [ - "src/lib/data/comparison/pairs.ts" - ], - "sample": "ication protocols transparently (HTTPS, SMTPS); [[ssh|SSH]] provides an encrypted cha" - }, - { - "stem": "RTMPS", - "count": 2, - "files": [ - "src/lib/data/comparison/pairs.ts", - "src/lib/data/diagram-definitions.ts" - ], - "sample": "aps [[rtmp|RTMP]] connections to create RTMPS, encrypting live stream ingest traffic" - }, - { - "stem": "MB", - "count": 2, - "files": [ - "src/lib/data/concept-foundations.ts", - "src/lib/data/protocols/ospf.ts" - ], - "sample": "r packet is **1460 bytes**. Sending a 1 MB file means roughly 685 packets. {{path-" - }, - { - "stem": "NSFNET", - "count": 2, - "files": [ - "src/lib/data/concept-foundations.ts", - "src/lib/data/outages.ts" - ], - "sample": "1986 the same architecture was carrying NSFNET traffic across the country β€” and the bu" - }, - { - "stem": "UC", - "count": 2, - "files": [ - "src/lib/data/concept-foundations.ts", - "src/lib/data/outages.ts" - ], - "sample": "ffers between Lawrence Berkeley Lab and UC Berkeley, three hops apart, were where" - }, - { - "stem": "RACK-TLP", - "count": 2, - "files": [ - "src/lib/data/concept-foundations.ts", - "src/lib/data/outages.ts" - ], - "sample": "ubic|CUBIC}}, {{bbr|BBR}}, {{l4s|L4S}}, RACK-TLP β€” are each refinements of the same cons" - }, - { - "stem": "HPC", - "count": 2, - "files": [ - "src/lib/data/concept-foundations.ts", - "src/lib/data/frontier.ts" - ], - "sample": "rnet|Ethernet]]+[[ip|IP]] for {{ai|AI}}/HPC scale-out: {{connectionless|connectionl" - }, - { - "stem": "CBC", - "count": 2, - "files": [ - "src/lib/data/concept-foundations.ts", - "src/lib/data/protocols/tls.ts" - ], - "sample": "}} key {{exchange|exchange}}, and every CBC-mode cipher β€” keeping only {{chacha20-p" - }, - { - "stem": "BEAST", - "count": 2, - "files": [ - "src/lib/data/concept-foundations.ts", - "src/lib/data/protocols/tls.ts" - ], - "sample": "been weaponised in a published attack (BEAST, CRIME, BREACH, Lucky 13, FREAK, Logjam" - }, - { - "stem": "CRIME", - "count": 2, - "files": [ - "src/lib/data/concept-foundations.ts", - "src/lib/data/protocols/tls.ts" - ], - "sample": "eaponised in a published attack (BEAST, CRIME, BREACH, Lucky 13, FREAK, Logjam, ROBOT" - }, - { - "stem": "BREACH", - "count": 2, - "files": [ - "src/lib/data/concept-foundations.ts", - "src/lib/data/protocols/tls.ts" - ], - "sample": "ed in a published attack (BEAST, CRIME, BREACH, Lucky 13, FREAK, Logjam, ROBOT, …). [[" - }, - { - "stem": "FREAK", - "count": 2, - "files": [ - "src/lib/data/concept-foundations.ts", - "src/lib/data/protocols/tls.ts" - ], - "sample": "attack (BEAST, CRIME, BREACH, Lucky 13, FREAK, Logjam, ROBOT, …). [[tls|TLS]] 1.3 als" - }, - { - "stem": "ROBOT", - "count": 2, - "files": [ - "src/lib/data/concept-foundations.ts", - "src/lib/data/protocols/tls.ts" - ], - "sample": "CRIME, BREACH, Lucky 13, FREAK, Logjam, ROBOT, …). [[tls|TLS]] 1.3 also reduced the {" - }, - { - "stem": "OBS", - "count": 2, - "files": [ - "src/lib/data/diagram-definitions.ts", - "src/lib/data/journeys.ts" - ], - "sample": "eam ingest}}** protocol β€” your encoder (OBS, Wirecast) pushes a long-lived [[tcp|TC" - }, - { - "stem": "STD", - "count": 2, - "files": [ - "src/lib/data/diagram-definitions.ts", - "src/lib/data/protocols/ospf.ts" - ], - "sample": "tra|Dijkstra]] ([[rfc:2328|RFC 2328]] / STD 54).', steps: { 0: '{{ospf-hello|H" - }, - { - "stem": "CTR", - "count": 2, - "files": [ - "src/lib/data/diagram-definitions.ts", - "src/lib/data/protocols/cellular.ts" - ], - "sample": "t}}; **{{sts|STS}}** is the {{aes|AES}}-CTR-generated pulse pattern that makes the" - }, - { - "stem": "WHERE", - "count": 2, - "files": [ - "src/lib/data/journeys.ts" - ], - "sample": "transition: 'The browser now knows WHERE the server lives β€” but packets on the i" - }, - { - "stem": "FSCI", - "count": 2, - "files": [ - "src/lib/data/journeys.ts", - "src/lib/data/protocols/nfc.ts" - ], - "sample": "TS}}** declaring its frame-size budget (FSCI=5 = 64 bytes max). Both ends now know h" - }, - { - "stem": "FCI", - "count": 2, - "files": [ - "src/lib/data/journeys.ts", - "src/lib/data/protocols/nfc.ts" - ], - "sample": "} `2PAY.SYS.DDF01`). The eSE returns an FCI Template listing every payment {{aid|AI" - }, - { - "stem": "PROCESSING", - "count": 2, - "files": [ - "src/lib/data/journeys.ts", - "src/lib/data/protocols/nfc.ts" - ], - "sample": "gram', description: \"After GET PROCESSING OPTIONS (returning AIP+{{afl|AFL}}) and" - }, - { - "stem": "CDOL1", - "count": 2, - "files": [ - "src/lib/data/journeys.ts", - "src/lib/data/protocols/nfc.ts" - ], - "sample": "nerate-ac|GENERATE AC}} with the filled CDOL1 data. The eSE composes the inputs (amou" - }, - { - "stem": "QR", - "count": 2, - "files": [ - "src/lib/data/journeys.ts", - "src/lib/data/protocols/nfc.ts" - ], - "sample": "e}} (printed on the Hue bulb's box as a QR code), that link key is unique and an e" - }, - { - "stem": "CVSS", - "count": 2, - "files": [ - "src/lib/data/outages.ts", - "src/lib/data/protocols/uwb.ts" - ], - "sample": "on the public internet were vulnerable. CVSS 7.5 (high). Operators scrambled to patc" - }, - { - "stem": "CID", - "count": 2, - "files": [ - "src/lib/data/protocols/bluetooth.ts" - ], - "sample": "att-mtu|ATT}}) lives on {{l2cap|L2CAP}} CID 0x0004 and provides read/write/notify/i" - }, - { - "stem": "LTK", - "count": 2, - "files": [ - "src/lib/data/protocols/bluetooth.ts" - ], - "sample": "Curve P-256 to derive a Long-Term Key (LTK); the link is then {{encryption|encrypt" - }, - { - "stem": "CIS", - "count": 2, - "files": [ - "src/lib/data/protocols/bluetooth.ts" - ], - "sample": "nels** β€” Connected Isochronous Streams (CIS) for {{unicast|unicast}} earbuds/hearin" - }, - { - "stem": "LL", - "count": 2, - "files": [ - "src/lib/data/protocols/bluetooth.ts" - ], - "sample": "scription: 'Two devices in a normal LL connection schedule **{{channel-soundin" - }, - { - "stem": "NCC", - "count": 2, - "files": [ - "src/lib/data/protocols/bluetooth.ts", - "src/lib/data/protocols/uwb.ts" - ], - "sample": "s the protocol-level answer to the 2022 NCC Group {{ble|BLE}} relay attack that ope" - }, - { - "stem": "GFSK", - "count": 2, - "files": [ - "src/lib/data/protocols/bluetooth.ts" - ], - "sample": "s over the air**. Different modulation (GFSK + DPSK for Classic, GFSK only for {{ble" - }, - { - "stem": "PB", - "count": 2, - "files": [ - "src/lib/data/protocols/cellular.ts" - ], - "sample": "}} by Q3 2025; the network averages 6.5 PB/day. The first proof that a hyperscale" - }, - { - "stem": "NR", - "count": 2, - "files": [ - "src/lib/data/protocols/cellular.ts" - ], - "sample": "ecified in Release 17 (2022), the first NR-{{ntn|NTN}} deployments shipped in late" - }, - { - "stem": "USA", - "count": 2, - "files": [ - "src/lib/data/protocols/cellular.ts" - ], - "sample": "numbering plan: 234/235 = UK, 310–316 = USA, 460 = China, 405 = India, 440–441 = Ja" - }, - { - "stem": "X2", - "count": 2, - "files": [ - "src/lib/data/protocols/cellular.ts", - "src/lib/data/protocols/ipsec.ts" - ], - "sample": "*mandate** [[ipsec|IPsec]] on every S1, X2, N2, N3, Xn, F1, and E1 interface. Forg" - }, - { - "stem": "N2", - "count": 2, - "files": [ - "src/lib/data/protocols/cellular.ts", - "src/lib/data/protocols/ipsec.ts" - ], - "sample": "date** [[ipsec|IPsec]] on every S1, X2, N2, N3, Xn, F1, and E1 interface. Forgetti" - }, - { - "stem": "N3", - "count": 2, - "files": [ - "src/lib/data/protocols/cellular.ts", - "src/lib/data/protocols/ipsec.ts" - ], - "sample": "** [[ipsec|IPsec]] on every S1, X2, N2, N3, Xn, F1, and E1 interface. Forgetting t" - }, - { - "stem": "E1", - "count": 2, - "files": [ - "src/lib/data/protocols/cellular.ts", - "src/lib/data/protocols/ipsec.ts" - ], - "sample": "]] on every S1, X2, N2, N3, Xn, F1, and E1 interface. Forgetting this in a private" - }, - { - "stem": "SOA", - "count": 2, - "files": [ - "src/lib/data/protocols/dns.ts" - ], - "sample": "pex must also have {{ns-record|NS}} and SOA records. Some [[dns|DNS]] providers off" - }, - { - "stem": "NXDOMAIN", - "count": 2, - "files": [ - "src/lib/data/protocols/dns.ts" - ], - "sample": "g can hurt', text: 'Resolvers cache NXDOMAIN responses based on the SOA minimum fiel" - }, - { - "stem": "UDP/4500", - "count": 2, - "files": [ - "src/lib/data/protocols/ipsec.ts" - ], - "sample": "{{security-association|SA}} switches to UDP/4500 {{encapsulation|encapsulation}}. Two me" - }, - { - "stem": "MOBIKE", - "count": 2, - "files": [ - "src/lib/data/protocols/ipsec.ts" - ], - "sample": "me routers don\\'t corrupt the packet. **MOBIKE** ([[rfc:4555|RFC 4555]]) lets a roadwa" - }, - { - "stem": "SKU", - "count": 2, - "files": [ - "src/lib/data/protocols/ipsec.ts", - "src/lib/data/protocols/mdns-dns-sd.ts" - ], - "sample": "(10 Gbps aggregate on the AZ-redundant SKU), {{gcp|GCP}} Cloud {{vpn|VPN}}, OCI Si" - }, - { - "stem": "AS-REQ", - "count": 2, - "files": [ - "src/lib/data/protocols/kerberos.ts" - ], - "sample": "description: 'Client sends an **AS-REQ** to the {{kerberos-kdc|KDC}}\\'s Authen" - }, - { - "stem": "TGS-REP", - "count": 2, - "files": [ - "src/lib/data/protocols/kerberos.ts" - ], - "sample": "ion key for Alice↔web1, and returns a **TGS-REP** with a **service ticket** encrypted u" - }, - { - "stem": "GSS", - "count": 2, - "files": [ - "src/lib/data/protocols/kerberos.ts" - ], - "sample": "y speak Kerberos directly. They speak **GSS-{{api|API}}** (Generic Security Service" - }, - { - "stem": "SPNEGO", - "count": 2, - "files": [ - "src/lib/data/protocols/kerberos.ts" - ], - "sample": "ntext\\` / \\`gss_accept_sec_context\\`. **SPNEGO** ([[rfc:4178|RFC 4178]]) is the protoc" - }, - { - "stem": "PKINIT", - "count": 2, - "files": [ - "src/lib/data/protocols/kerberos.ts" - ], - "sample": "gust 2025 release. Headline features: **PKINIT {{ecdh|ECDH}}/EC certs** (smart-card au" - }, - { - "stem": "DES", - "count": 2, - "files": [ - "src/lib/data/protocols/kerberos.ts" - ], - "sample": "IT}}-internal for years because it used DES β€” and DES exports required State Depart" - }, - { - "stem": "FF02", - "count": 2, - "files": [ - "src/lib/data/protocols/mdns-dns-sd.ts", - "src/lib/data/protocols/ospf.ts" - ], - "sample": "s* on \\`224.0.0.251\\` ([[ipv6|IPv6]]: \\`FF02::FB\\`). Two flag bits get repurposed: t" - }, - { - "stem": "SD", - "count": 2, - "files": [ - "src/lib/data/protocols/mdns-dns-sd.ts", - "src/lib/data/protocols/ospf.ts" - ], - "sample": "cription: \"A {{dns-resolution|DNS}}-SD client looking for printers sends a {{p" - }, - { - "stem": "SRP", - "count": 2, - "files": [ - "src/lib/data/protocols/mdns-dns-sd.ts" - ], - "sample": "col) published', description: '**SRP** ({{rfc-doc|RFC}} 9665, Lemon + [[pion" - }, - { - "stem": "LLMNR", - "count": 2, - "files": [ - "src/lib/data/protocols/mdns-dns-sd.ts" - ], - "sample": "th [[mdns-dns-sd|mDNS]] **enabled** and LLMNR **disabled** in the security baseline." - }, - { - "stem": "IGMP", - "count": 2, - "files": [ - "src/lib/data/protocols/mdns-dns-sd.ts" - ], - "sample": "e (often 6 Mbps); managed switches with IGMP snooping enabled drop frames whose list" - }, - { - "stem": "WLC", - "count": 2, - "files": [ - "src/lib/data/protocols/mdns-dns-sd.ts", - "src/lib/data/protocols/nfc.ts" - ], - "sample": "-dns-sd|mDNS]] gateway ({{cisco|Cisco}} WLC `mdns-sd` profile, Aruba AirGroup, Aero" - }, - { - "stem": "DERP", - "count": 2, - "files": [ - "src/lib/data/protocols/nat-traversal.ts", - "src/lib/data/protocols/wireguard.ts" - ], - "sample": "path between peers; their proprietary **DERP** relays absorb the rest as a {{turn|TU" - }, - { - "stem": "CTO", - "count": 2, - "files": [ - "src/lib/data/protocols/nat-traversal.ts", - "src/lib/data/protocols/rtp.ts" - ], - "sample": "turn|TURN}}, and {{ice|ICE}}. Currently CTO + Head of {{ai|AI}} at Five9.' } ]," - }, - { - "stem": "T2T", - "count": 2, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "ate frame size (FSCI) and timing (FWI). T2T cards skip {{rats|RATS}} and go straigh" - }, - { - "stem": "TC", - "count": 2, - "files": [ - "src/lib/data/protocols/nfc.ts", - "src/lib/data/protocols/zigbee.ts" - ], - "sample": "} β€” either an {{arqc|ARQC}} (online) or TC (offline). The cryptogram is signed in" - }, - { - "stem": "TNF", - "count": 2, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "ifier|ID}} Length present), and a 3-bit TNF (Type Name Format: 0=Empty, 1=Well-Know" - }, - { - "stem": "IEC", - "count": 2, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "{ndef|NDEF}} was formally adopted as an IEC standard in **March 2026** alongside NF" - }, - { - "stem": "HID", - "count": 2, - "files": [ - "src/lib/data/protocols/nfc.ts", - "src/lib/data/protocols/uwb.ts" - ], - "sample": "}}, Allegion, Aqara, {{google|Google}}, HID, Kastle, Kwikset, Last Lock, Nordic, Nu" - }, - { - "stem": "EV3", - "count": 2, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "Plus in **2011**, DESFire EV2 in 2016, EV3 in the early 2020s. The Classic Crypto1" - }, - { - "stem": "GM", - "count": 2, - "files": [ - "src/lib/data/protocols/nfc.ts", - "src/lib/data/protocols/uwb.ts" - ], - "sample": "is, Audi (new in 2025), Volvo, Porsche, GM, Ford, plus a wave of Chinese OEMs (NIO" - }, - { - "stem": "DDA/CDA", - "count": 2, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "eturns an AIP byte that signals whether DDA/CDA is supported. A common custom-{{hce|HCE" - }, - { - "stem": "RRP", - "count": 2, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "gram|EMV}} **Relay Resistance Protocol (RRP)** in Kernel 2 v2.6+ binds round-trip t" - }, - { - "stem": "T1", - "count": 2, - "files": [ - "src/lib/data/protocols/ntp.ts" - ], - "sample": "DP]] packet with its current timestamp (T1). The packet is tiny β€” 48 bytes.' }," - }, - { - "stem": "T3", - "count": 2, - "files": [ - "src/lib/data/protocols/ntp.ts" - ], - "sample": "rives (T2) and when it sends the reply (T3). Both timestamps are included in the r" - }, - { - "stem": "T4", - "count": 2, - "files": [ - "src/lib/data/protocols/ntp.ts" - ], - "sample": "ient records when the response arrives (T4). Now it has four timestamps: T1 (sent)" - }, - { - "stem": "NBMA", - "count": 2, - "files": [ - "src/lib/data/protocols/ospf.ts" - ], - "sample": "default 10 s on point-to-point, 30 s on NBMA). Hellos carry the router\\'s {{id-ident" - }, - { - "stem": "HPRF", - "count": 2, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "Hz** in the default 802.15.4z mode or **HPRF 124.8 / 249.6 MHz** in higher-power mod" - }, - { - "stem": "RTLS", - "count": 2, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "f arrival β€” used for warehouse/hospital RTLS where anchors are wired. **AoA / PDoA:*" - }, - { - "stem": "EN", - "count": 2, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "Hz** across 3.1–10.6 GHz. {{etsi|ETSI}} EN 302 065 in Europe is similar with stric" - }, - { - "stem": "AR", - "count": 2, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "ision Finding, BMW Digital Key, and the AR experiences in {{apple|Apple}} Vision P" - }, - { - "stem": "T2024", - "count": 2, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "1-chip|U1}}'s 16 nm), internal codename T2024, part number 339M00298. **1.5Γ— longer P" - }, - { - "stem": "U400", - "count": 2, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "amsung wallets. First products: **Aqara U400** (first smart lock with UWB; {{aliro|A" - }, - { - "stem": "S21", - "count": 2, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "|Apple}} UWB tracker. Works with Galaxy S21+ / S21 Ultra / Note 20 Ultra / S22/S23/" - }, - { - "stem": "DW3000", - "count": 2, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "upports only Channel 5; everything from DW3000 / {{nxp|NXP}} SR150 / {{apple|Apple}} {" - }, - { - "stem": "SR150", - "count": 2, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "5; everything from DW3000 / {{nxp|NXP}} SR150 / {{apple|Apple}} {{u1-chip|U1}} onward" - }, - { - "stem": "NLOS", - "count": 2, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "ns = 30 cm, but in **non-line-of-sight (NLOS)** conditions through walls/people/meta" - }, - { - "stem": "ACL", - "count": 2, - "files": [ - "src/lib/data/protocols/wireguard.ts" - ], - "sample": "r which destination prefix) **and** the ACL (inbound: only accept packets from this" - }, - { - "stem": "TSPU", - "count": 2, - "files": [ - "src/lib/data/protocols/wireguard.ts" - ], - "sample": "mimicry', description: \"Russia's TSPU boxes learned to fingerprint and drop s" - }, - { - "stem": "S1/S2", - "count": 2, - "files": [ - "src/lib/data/protocols/wireguard.ts" - ], - "sample": "H4 ranges instead of fixed 1–4), random S1/S2 padding. AWG 2.0 adds optional QUIC/{{d" - }, - { - "stem": "WARP", - "count": 2, - "files": [ - "src/lib/data/protocols/wireguard.ts" - ], - "sample": "are}}'s consumer {{vpn|VPN}} (1.1.1.1 + WARP app) runs on **BoringTun**, {{cloudflar" - }, - { - "stem": "OTA", - "count": 2, - "files": [ - "src/lib/data/protocols/zigbee.ts" - ], - "sample": "ntrol = 0x0008, Color Control = 0x0300, OTA Upgrade = 0x0019), and an **APSCounter*" - }, - { - "stem": "FOSS", - "count": 2, - "files": [ - "src/lib/data/protocols/zigbee.ts" - ], - "sample": "and *no* microphone or camera. For the FOSS path the answer is **zigbee2mqtt** by K" - }, - { - "stem": "PSU", - "count": 2, - "files": [ - "src/lib/data/protocols/zigbee.ts" - ], - "sample": "ble Zigbee β€” the router's switched-mode PSU emits broadband 2.4 GHz noise.\" } ]," - }, - { - "stem": "CC2652", - "count": 2, - "files": [ - "src/lib/data/protocols/zigbee.ts" - ], - "sample": "dresden elektronik ConBee II, or any TI CC2652 stick β€” the radio is abstracted behind" - }, - { - "stem": "SES", - "count": 2, - "files": [ - "src/lib/data/protocols/zigbee.ts" - ], - "sample": "3 December 2024** VusionGroup (formerly SES-imagotag) announced acceleration of dig" - }, - { - "stem": "ESL", - "count": 2, - "files": [ - "src/lib/data/protocols/zigbee.ts" - ], - "sample": "500 stores. Vusion shipped 350 million ESLs in 2023 alone; the EdgeSense platform r" - }, - { - "stem": "AIR", - "count": 2, - "files": [ - "src/lib/data/protocols/zigbee.ts" - ], - "sample": "', description: \"Acuity's nLight AIR and Atrius lines are the dominant Zigbe" - }, - { - "stem": "SUN", - "count": 2, - "files": [ - "src/lib/data/protocols/zigbee.ts" - ], - "sample": "and later directed standards at the Wi-SUN Alliance. Almost every low-power 802.15" - }, - { - "stem": "VSAT", - "count": 1, - "files": [ - "src/lib/data/book/parts/async-iot.ts" - ], - "sample": "llips 66 oil pipelines over a brand-new VSAT satellite link. The 2-byte fixed header" - }, - { - "stem": "PINGREQ", - "count": 1, - "files": [ - "src/lib/data/book/parts/async-iot.ts" - ], - "sample": "ixed header**, smallest control packet (PINGREQ) is 2 bytes total. Designed in 1999 by" - }, - { - "stem": "JMS", - "count": 1, - "files": [ - "src/lib/data/book/parts/async-iot.ts" - ], - "sample": "sia is removed. RabbitMQ 4.3 also added JMS-style queues with {{sql|SQL}} message s" - }, - { - "stem": "NETSCOUT", - "count": 1, - "files": [ - "src/lib/data/book/parts/async-iot.ts" - ], - "sample": "{ kind: 'pull-quote', text: 'NETSCOUT\\'s January 2019 scan found 388,344 publ" - }, - { - "stem": "QLC", - "count": 1, - "files": [ - "src/lib/data/book/parts/async-iot.ts" - ], - "sample": "ey were Chinese smartphones running the QLC Chain {{peer-to-peer|peer-to-peer}} cry" - }, - { - "stem": "EDHOC", - "count": 1, - "files": [ - "src/lib/data/book/parts/async-iot.ts" - ], - "sample": "messages, ~100 bytes', text: '**EDHOC ([[rfc:9000|RFC 9528]], March 2024)** β€”" - }, - { - "stem": "DH", - "count": 1, - "files": [ - "src/lib/data/book/parts/async-iot.ts" - ], - "sample": "sages totalling ~100 bytes** for static-DH credentials, vs **~700+ bytes for a {{d" - }, - { - "stem": "OSCORE", - "count": 1, - "files": [ - "src/lib/data/book/parts/async-iot.ts" - ], - "sample": "years* of additional life. Companion: **OSCORE ([[rfc:8613|RFC 8613]])** wraps the [[c" - }, - { - "stem": "DNA", - "count": 1, - "files": [ - "src/lib/data/book/parts/famous-outages.ts" - ], - "sample": "g router carries the same architectural DNA: a control plane that builds the {{rout" - }, - { - "stem": "PREF64", - "count": 1, - "files": [ - "src/lib/data/book/parts/frontier.ts" - ], - "sample": "clients \"skip [[ip|IPv4]] entirely,\" **PREF64 in Router Advertisements ([[rfc:8781|RF" - }, - { - "stem": "RIR", - "count": 1, - "files": [ - "src/lib/data/book/parts/frontier.ts" - ], - "sample": "{{roa|ROA}} set. Lesson: enforce 2FA on RIR portals.', attribution: 'Author'" - }, - { - "stem": "OTC", - "count": 1, - "files": [ - "src/lib/data/book/parts/frontier.ts" - ], - "sample": "fc:9234|RFC 9234]] ([[bgp|BGP]] Roles + OTC) ate its lunch. The lesson: a security" - }, - { - "stem": "MW", - "count": 1, - "files": [ - "src/lib/data/book/parts/frontier.ts" - ], - "sample": "nal pluggable optics would consume ~180 MW of power for the optics alone. That is" - }, - { - "stem": "X1600", - "count": 1, - "files": [ - "src/lib/data/book/parts/frontier.ts" - ], - "sample": "AI}} workloads. **{{spectrum|Spectrum}}-X1600 (102.4 Tbps)** is expected 2H 2026.'" - }, - { - "stem": "GB200", - "count": 1, - "files": [ - "src/lib/data/book/parts/frontier.ts" - ], - "sample": "ption: 'The **{{nvidia|NVIDIA}} GB200 NVL72** Blackwell-architecture rack on" - }, - { - "stem": "NVL72", - "count": 1, - "files": [ - "src/lib/data/book/parts/frontier.ts" - ], - "sample": "'The **{{nvidia|NVIDIA}} GB200 NVL72** Blackwell-architecture rack on displa" - }, - { - "stem": "COMPUTEX", - "count": 1, - "files": [ - "src/lib/data/book/parts/frontier.ts" - ], - "sample": "ackwell-architecture rack on display at COMPUTEX 2024 β€” the kind of {{ai|AI}}-training e" - }, - { - "stem": "WECA", - "count": 1, - "files": [ - "src/lib/data/book/parts/frontier.ts" - ], - "sample": "as a tagline retrofitted briefly by the WECA board and dropped. The yin-yang logo is" - }, - { - "stem": "OET", - "count": 1, - "files": [ - "src/lib/data/book/parts/frontier.ts" - ], - "sample": "on **23 February 2024** the {{fcc|FCC}} OET approved **seven {{afc|AFC}} system ope" - }, - { - "stem": "RUCKUS", - "count": 1, - "files": [ - "src/lib/data/book/parts/frontier.ts" - ], - "sample": "d [[wifi|Wi-Fi]] 7 {{access-point|AP}} (RUCKUS R770) was certified 16 April 2024.** Bu" - }, - { - "stem": "R770", - "count": 1, - "files": [ - "src/lib/data/book/parts/frontier.ts" - ], - "sample": "i|Wi-Fi]] 7 {{access-point|AP}} (RUCKUS R770) was certified 16 April 2024.** But on" - }, - { - "stem": "SINR", - "count": 1, - "files": [ - "src/lib/data/book/parts/frontier.ts" - ], - "sample": "squeezes for **+25% throughput at given SINR, βˆ’25% 95th-percentile {{latency|latency" - }, - { - "stem": "MPDU", - "count": 1, - "files": [ - "src/lib/data/book/parts/frontier.ts" - ], - "sample": "th-percentile {{latency|latency}}, βˆ’25% MPDU loss across {{bss-coloring|BSS}} transi" - }, - { - "stem": "CS168", - "count": 1, - "files": [ - "src/lib/data/book/parts/how-to-learn-more.ts" - ], - "sample": "P]] stack), {{mit|MIT}} 6.829, Berkeley CS168.', slots: [ { kind: 'prose'" - }, - { - "stem": "PARC", - "count": 1, - "files": [ - "src/lib/data/book/parts/layer-2-3.ts" - ], - "sample": "still runs the original spec. The 1973 PARC sketch and a 2025 Ultra [[ethernet|Ethe" - }, - { - "stem": "KU", - "count": 1, - "files": [ - "src/lib/data/book/parts/layer-2-3.ts" - ], - "sample": ", text: '**Mathy Vanhoef and the KU Leuven team have broken [[wifi|Wi-Fi]]" - }, - { - "stem": "DCP", - "count": 1, - "files": [ - "src/lib/data/book/parts/layer-2-3.ts" - ], - "sample": "rote [[rfc:826|RFC 826]] from address \\`DCP@{{mit|MIT}}-MC\\` in November 1982. **ST" - }, - { - "stem": "MC", - "count": 1, - "files": [ - "src/lib/data/book/parts/layer-2-3.ts" - ], - "sample": "FC 826]] from address \\`DCP@{{mit|MIT}}-MC\\` in November 1982. **STD 37 has never" - }, - { - "stem": "L2", - "count": 1, - "files": [ - "src/lib/data/book/parts/layer-2-3.ts" - ], - "sample": "xt: '[[arp|ARP]] relies entirely on the L2 {{checksum|frame check sequence}} β€” no" - }, - { - "stem": "BRL", - "count": 1, - "files": [ - "src/lib/data/book/parts/layer-2-3.ts" - ], - "sample": "rote {{ping|ping}} in a single night at BRL Aberdeen in December 1983, named after" - }, - { - "stem": "TOPS-20", - "count": 1, - "files": [ - "src/lib/data/book/parts/layer-2-3.ts" - ], - "sample": "st server was named *Jeeves* and ran on TOPS-20.', credit: 'Image: Wikimedia Com" - }, - { - "stem": "KEX", - "count": 1, - "files": [ - "src/lib/data/book/parts/patterns-failures.ts" - ], - "sample": "llo|ServerHello}}/Finished, [[ssh|SSH]] KEX, [[mqtt|MQTT]] {{mqtt-connect|CONNECT}}" - }, - { - "stem": "CONNACK", - "count": 1, - "files": [ - "src/lib/data/book/parts/patterns-failures.ts" - ], - "sample": "[[mqtt|MQTT]] {{mqtt-connect|CONNECT}}/CONNACK, [[sctp|SCTP]]\\'s four-way {{cookie|Coo" - }, - { - "stem": "DAVE", - "count": 1, - "files": [ - "src/lib/data/book/parts/realtime-av.ts" - ], - "sample": "on a whiteboard in 2018.\" Discord\\'s **DAVE protocol** (deployed 1 March 2026) laye" - }, - { - "stem": "MLS", - "count": 1, - "files": [ - "src/lib/data/book/parts/realtime-av.ts" - ], - "sample": "otocol** (deployed 1 March 2026) layers MLS keys + SFrame on top of [[rtp|RTP]]/{{s" - }, - { - "stem": "E2EE", - "count": 1, - "files": [ - "src/lib/data/book/parts/realtime-av.ts" - ], - "sample": "on top of [[rtp|RTP]]/{{srtp|SRTP}} for E2EE voice across **2.5 million concurrent u" - }, - { - "stem": "M120", - "count": 1, - "files": [ - "src/lib/data/book/parts/realtime-av.ts" - ], - "sample": "AV1}} hardware encode shipped in Chrome M120 (Dec 2023). Firefox 125 added {{av1|AV1" - }, - { - "stem": "EME", - "count": 1, - "files": [ - "src/lib/data/book/parts/realtime-av.ts" - ], - "sample": "ec 2023). Firefox 125 added {{av1|AV1}}+EME in April 2024. But the royalty-free cla" - }, - { - "stem": "CMAF", - "count": 1, - "files": [ - "src/lib/data/book/parts/realtime-av.ts" - ], - "sample": "ate ladders of small .ts (or now .mp4 / CMAF) segments; a {{cdn|CDN}} serves them ov" - }, - { - "stem": "ISDN", - "count": 1, - "files": [ - "src/lib/data/book/parts/realtime-av.ts" - ], - "sample": "four wholesale rewrites later (analog β†’ ISDN β†’ [[rtp|RTP]]/H.323 β†’ [[webrtc|WebRTC]]" - }, - { - "stem": "PRNET/SATNET", - "count": 1, - "files": [ - "src/lib/data/book/parts/story-of-the-internet.ts" - ], - "sample": "et|ARPANET}}), and unreliable wireless (PRNET/SATNET) each forced different design pressures" - }, - { - "stem": "UCSB", - "count": 1, - "files": [ - "src/lib/data/book/parts/story-of-the-internet.ts" - ], - "sample": "rk that became the internet. UCLA, SRI, UCSB, and Utah; one {{imp|IMP}} per site.'," - }, - { - "stem": "EDGE", - "count": 1, - "files": [ - "src/lib/data/book/parts/story-of-the-internet.ts" - ], - "sample": "d on 29 June 2007 with [[wifi|Wi-Fi]] + EDGE; the App Store followed in July 2008; {" - }, - { - "stem": "GIGA", - "count": 1, - "files": [ - "src/lib/data/book/parts/transport.ts" - ], - "sample": "ple}} {{os|OS}} services, Korea Telecom GIGA Path, some specialised enterprise WANs)" - }, - { - "stem": "CA", - "count": 1, - "files": [ - "src/lib/data/book/parts/utilities-security.ts" - ], - "sample": "te-authority|CA}} signs an intermediate CA, which signs the end-entity {{certifica" - }, - { - "stem": "SIGALRM", - "count": 1, - "files": [ - "src/lib/data/book/parts/utilities-security.ts" - ], - "sample": "{{linux|Linux}}. Signal-handler race: \\`SIGALRM\\` handler calls \\`syslog()\\` (not async" - }, - { - "stem": "UNIX", - "count": 1, - "files": [ - "src/lib/data/book/parts/utilities-security.ts" - ], - "sample": "er than {{arpanet|ARPANET}}, older than UNIX, older than every other timestamp stand" - }, - { - "stem": "Y2036", - "count": 1, - "files": [ - "src/lib/data/book/parts/utilities-security.ts" - ], - "sample": "it and will need fixes before 2036. The Y2036 work has been quietly underway since 20" - }, - { - "stem": "SNDMSG", - "count": 1, - "files": [ - "src/lib/data/book/parts/utilities-security.ts" - ], - "sample": "picked the **@** sign in 1971 modifying SNDMSG. [[pioneer:jon-postel|Jon Postel]] publ" - }, - { - "stem": "DCE", - "count": 1, - "files": [ - "src/lib/data/book/parts/web-api.ts" - ], - "sample": "a 40-year lineage of Sun {{rpc|RPC}} / DCE / CORBA / Thrift. The client *stub* ser" - }, - { - "stem": "CORBA", - "count": 1, - "files": [ - "src/lib/data/book/parts/web-api.ts" - ], - "sample": "year lineage of Sun {{rpc|RPC}} / DCE / CORBA / Thrift. The client *stub* serialises" - }, - { - "stem": "NTIA", - "count": 1, - "files": [ - "src/lib/data/book/parts/wireless.ts" - ], - "sample": "d States Frequency Allocations Chart**, NTIA. Every coloured stripe is a *service* β€”" - }, - { - "stem": "WPA", - "count": 1, - "files": [ - "src/lib/data/book/parts/wireless.ts" - ], - "sample": "|OOB}} key or the Wi-Fi {{ssid|SSID}} + WPA key in an {{ndef|NDEF}} record. **[[zig" - }, - { - "stem": "MIMO", - "count": 1, - "files": [ - "src/lib/data/book/parts/wireless.ts" - ], - "sample": "11]] β€” {{csma-ca|CSMA/CA}} in practice, MIMO β†’ {{ofdma|OFDMA}} β†’ {{mlo|MLO}}, and th" - }, - { - "stem": "DIFS", - "count": 1, - "files": [ - "src/lib/data/book/parts/wireless.ts" - ], - "sample": "of the {{airtime|airtime}} is spent on DIFS gaps, {{ack|ACK}} frames, beacons, and" - }, - { - "stem": "NB", - "count": 1, - "files": [ - "src/lib/data/book/parts/wireless.ts" - ], - "sample": "volte|VoLTE}} / [[wifi|Wi-Fi]] calling, NB-IoT / {{lte|LTE}}-M, satellite {{direct" - }, - { - "stem": "N2/N3", - "count": 1, - "files": [ - "src/lib/data/book/parts/wireless.ts" - ], - "sample": "an|radio access network}} and the core (N2/N3 in 5G, S1 in {{lte|LTE}}) is wrapped in" - }, - { - "stem": "IOS", - "count": 1, - "files": [ - "src/lib/data/book/parts/wireless.ts" - ], - "sample": "teffen]]\\'s strongSwan, {{cisco|Cisco}} IOS, and Juniper {{junos|Junos}} run more [" - }, - { - "stem": "TACS", - "count": 1, - "files": [ - "src/lib/data/book/parts/wireless.ts" - ], - "sample": "ar|cellular]]** β€” from 1G analog AMPS / TACS / NMT in the early 1980s through 2G {{g" - }, - { - "stem": "NMT", - "count": 1, - "files": [ - "src/lib/data/book/parts/wireless.ts" - ], - "sample": "ular]]** β€” from 1G analog AMPS / TACS / NMT in the early 1980s through 2G {{gsm|GSM" - }, - { - "stem": "IS-95", - "count": 1, - "files": [ - "src/lib/data/book/parts/wireless.ts" - ], - "sample": "he early 1980s through 2G {{gsm|GSM}} / IS-95, 3G {{wcdma|WCDMA}} / CDMA2000, 4G {{lt" - }, - { - "stem": "CDMA2000", - "count": 1, - "files": [ - "src/lib/data/book/parts/wireless.ts" - ], - "sample": "gsm|GSM}} / IS-95, 3G {{wcdma|WCDMA}} / CDMA2000, 4G {{lte|LTE}}, and {{5g-nr|5G NR}}. E" - }, - { - "stem": "SYS.DDF01", - "count": 1, - "files": [ - "src/lib/data/book/parts/wireless.ts" - ], - "sample": "t System Environment {{aid|AID}} \\`2PAY.SYS.DDF01\\` β€” and the card returns an FCI listing" - }, - { - "stem": "A0000000041010", - "count": 1, - "files": [ - "src/lib/data/book/parts/wireless.ts" - ], - "sample": "The reader picks one (e.g. Mastercard \\`A0000000041010\\`), SELECTs it, gets back a {{pdol|PDOL" - }, - { - "stem": "TX", - "count": 1, - "files": [ - "src/lib/data/book/parts/wireless.ts" - ], - "sample": "*can* be cheated β€” a relay with enough TX power makes a distant device look near." - }, - { - "stem": "PAL", - "count": 1, - "files": [ - "src/lib/data/book/parts/wireless.ts" - ], - "sample": "iority), **Priority Access Licensees** (PALs, auctioned in 2020 for ~$4.5B), and **G" - }, - { - "stem": "PMSE", - "count": 1, - "files": [ - "src/lib/data/book/parts/wireless.ts" - ], - "sample": "has experimented with similar concepts (PMSE in the UK, {{lsa|LSA}} in some EU pilot" - }, - { - "stem": "PIE", - "count": 1, - "files": [ - "src/lib/data/category-deep-dives.ts" - ], - "sample": "{{aqm|Active Queue Management}} (CoDel, PIE, fq_codel) and algorithms like {{bbr|BB" - }, - { - "stem": "SCADA", - "count": 1, - "files": [ - "src/lib/data/category-stories/async-iot.ts" - ], - "sample": "on: \"Brought embedded systems and SCADA expertise to [[mqtt|MQTT]]'s design. Co" - }, - { - "stem": "CBOR", - "count": 1, - "files": [ - "src/lib/data/category-stories/async-iot.ts" - ], - "sample": "oap|CoAP]] specification and co-created CBOR, the efficient binary {{serialization|s" - }, - { - "stem": "NATS", - "count": 1, - "files": [ - "src/lib/data/category-stories/async-iot.ts" - ], - "sample": "o cloud-native microservices ([[amqp]], NATS, [[kafka]]). Today, it's one of the mos" - }, - { - "stem": "P802", - "count": 1, - "files": [ - "src/lib/data/category-stories/network-foundations.ts" - ], - "sample": "on 100 G lanes). The 1.6 TbE follow-up (P802.3dj, 200 G/lane) targets July 2026 β€” dr" - }, - { - "stem": "LO", - "count": 1, - "files": [ - "src/lib/data/category-stories/transport.ts" - ], - "sample": "two months before the first successful \"LO\" transmission to SRI.', credit: 'Pho" - }, - { - "stem": "PDP-11", - "count": 1, - "files": [ - "src/lib/data/category-stories/utilities.ts" - ], - "sample": "frastructure', caption: \"The DEC PDP-11 β€” machines like these ran early [[ntp|N" - }, - { - "stem": "POWER", - "count": 1, - "files": [ - "src/lib/data/category-stories/web-api.ts" - ], - "sample": "reads \"This machine is a server. DO NOT POWER IT DOWN!!\"', credit: 'Photo: Coolcae" - }, - { - "stem": "DOWN", - "count": 1, - "files": [ - "src/lib/data/category-stories/web-api.ts" - ], - "sample": "is machine is a server. DO NOT POWER IT DOWN!!\"', credit: 'Photo: Coolcaesar / CC" - }, - { - "stem": "AAIF", - "count": 1, - "files": [ - "src/lib/data/category-stories/web-api.ts" - ], - "sample": "es to the Agentic {{ai|AI}} Foundation (AAIF) and [[a2a|A2A]] launches as a {{linux|" - }, - { - "stem": "RF", - "count": 1, - "files": [ - "src/lib/data/category-stories/wireless.ts" - ], - "sample": "'Swedish engineer who owned the analog RF and CMOS implementation work that paire" - }, - { - "stem": "COMDEX", - "count": 1, - "files": [ - "src/lib/data/category-stories/wireless.ts" - ], - "sample": "product (a hands-free headset) ships at COMDEX 1999.', protocolId: 'bluetooth'" - }, - { - "stem": "SC-FDMA", - "count": 1, - "files": [ - "src/lib/data/category-stories/wireless.ts" - ], - "sample": "preading codes for an {{ofdma|OFDMA}} + SC-FDMA air interface β€” the clean-sheet radio d" - }, - { - "stem": "IQ", - "count": 1, - "files": [ - "src/lib/data/comparison/pairs.ts" - ], - "sample": "ble delivery of presence, messages, and IQ queries.', howTheyWork: 'An [[xmpp" - }, - { - "stem": "AMQPS", - "count": 1, - "files": [ - "src/lib/data/comparison/pairs.ts" - ], - "sample": "aps [[amqp|AMQP]] connections to create AMQPS, encrypting all {{broker|message broker" - }, - { - "stem": "MQTTS", - "count": 1, - "files": [ - "src/lib/data/comparison/pairs.ts" - ], - "sample": "aps [[mqtt|MQTT]] connections to create MQTTS, encrypting all pub/sub messaging betwe" - }, - { - "stem": "SIPS", - "count": 1, - "files": [ - "src/lib/data/comparison/pairs.ts" - ], - "sample": "SIP]] {{signaling|signaling}} to create SIPS, encrypting call setup, authentication," - }, - { - "stem": "WSS", - "count": 1, - "files": [ - "src/lib/data/comparison/pairs.ts" - ], - "sample": "ckets|WebSocket]] connections to create WSS (wss://), encrypting the {{full-duplex|" - }, - { - "stem": "M3U8", - "count": 1, - "files": [ - "src/lib/data/comparison/pairs.ts" - ], - "sample": "LS]] delivers adaptive video by serving M3U8 playlists and media segments as standar" - }, - { - "stem": "BOSH", - "count": 1, - "files": [ - "src/lib/data/comparison/pairs.ts" - ], - "sample": "network without long-polling hacks like BOSH.', howTheyWork: 'The browser opens" - }, - { - "stem": "PROXY", - "count": 1, - "files": [ - "src/lib/data/concept-foundations.ts" - ], - "sample": "ess you explicitly forward it via the **PROXY protocol** or an {{header|HTTP header}}" - }, - { - "stem": "ARPA", - "count": 1, - "files": [ - "src/lib/data/concept-foundations.ts" - ], - "sample": "down in 1986.', caption: 'The ARPA Network in September 1973, a few dozen" - }, - { - "stem": "DHT", - "count": 1, - "files": [ - "src/lib/data/concept-foundations.ts" - ], - "sample": "Torrent uses centralised trackers (or a DHT, which is a decentralised tracker) to b" - }, - { - "stem": "SHA384", - "count": 1, - "files": [ - "src/lib/data/concept-foundations.ts" - ], - "sample": "DigiCert [[tls|TLS]] Hybrid {{ecc|ECC}} SHA384 β†’ DigiCert Global Root G3\\`. Only the b" - }, - { - "stem": "G3", - "count": 1, - "files": [ - "src/lib/data/concept-foundations.ts" - ], - "sample": "ecc|ECC}} SHA384 β†’ DigiCert Global Root G3\\`. Only the bottom (root) {{certificate" - }, - { - "stem": "SIGTRAN", - "count": 1, - "files": [ - "src/lib/data/diagram-definitions.ts" - ], - "sample": "under telecom {{signaling|signaling}} (SIGTRAN) and [[webrtc|WebRTC]] data channels ([" - }, - { - "stem": "WHATWG", - "count": 1, - "files": [ - "src/lib/data/diagram-definitions.ts" - ], - "sample": "only need {{server-push|server push}} (WHATWG).', steps: { 0: 'Standard [[http1|" - }, - { - "stem": "OMA", - "count": 1, - "files": [ - "src/lib/data/diagram-definitions.ts" - ], - "sample": "App, and the {{matter|Matter}}-adjacent OMA-LwM2M IoT stack. Encrypted via {{startt" - }, - { - "stem": "CQRS", - "count": 1, - "files": [ - "src/lib/data/diagram-definitions.ts" - ], - "sample": "tream processing}}, event sourcing, and CQRS. **{{exactly-once-delivery|Exactly-once" - }, - { - "stem": "T1/T2/T3/T4", - "count": 1, - "files": [ - "src/lib/data/diagram-definitions.ts" - ], - "sample": "timestamps per {{exchange|exchange}}** (T1/T2/T3/T4) which cancel out network {{latency|lat" - }, - { - "stem": "TGS", - "count": 1, - "files": [ - "src/lib/data/diagram-definitions.ts" - ], - "sample": "ey Distribution Center, split into AS + TGS), and Service. Two {{encryption|encrypt" - }, - { - "stem": "SEND", - "count": 1, - "files": [ - "src/lib/data/journeys.ts" - ], - "sample": "ONNECT}}, {{mqtt-subscribe|SUBSCRIBE}}, SEND, and {{ack|ACK}} are self-explanatory," - }, - { - "stem": "ERP", - "count": 1, - "files": [ - "src/lib/data/journeys.ts" - ], - "sample": "ing queue, maintenance data goes to the ERP integration queue, and raw telemetry go" - }, - { - "stem": "VP8", - "count": 1, - "files": [ - "src/lib/data/journeys.ts" - ], - "sample": "round rules: which codecs they support (VP8, H.264, Opus), what transport addresses" - }, - { - "stem": "DANE", - "count": 1, - "files": [ - "src/lib/data/journeys.ts" - ], - "sample": "d [[dns|DNS]]-based authentication like DANE which allows domain owners to {{mqtt-pu" - }, - { - "stem": "TVR", - "count": 1, - "files": [ - "src/lib/data/journeys.ts" - ], - "sample": "the inputs (amount, currency, country, TVR, {{atc|ATC}}, Unpredictable Number, AIP" - }, - { - "stem": "POS", - "count": 1, - "files": [ - "src/lib/data/journeys.ts" - ], - "sample": "description: \"Modern wireless POS terminals (Square, Stripe, Verifone Eng" - }, - { - "stem": "APPROVED", - "count": 1, - "files": [ - "src/lib/data/journeys.ts" - ], - "sample": "sufficient balance + no fraud flag = **APPROVED**. The issuer returns an **ARPC** (Auth" - }, - { - "stem": "ARPC", - "count": 1, - "files": [ - "src/lib/data/journeys.ts" - ], - "sample": "= **APPROVED**. The issuer returns an **ARPC** (Authorisation Response Cryptogram) o" - }, - { - "stem": "RFRAME", - "count": 1, - "files": [ - "src/lib/data/journeys.ts" - ], - "sample": "n: \"The phone transmits a **Poll** RFRAME on [[uwb|UWB]] Channel 9 (7987.2 MHz, 4" - }, - { - "stem": "LQI", - "count": 1, - "files": [ - "src/lib/data/journeys.ts" - ], - "sample": "icks the best parent by {{rssi|RSSI}} + LQI. This is the slowest step β€” beacon scan" - }, - { - "stem": "WITHDRAWAL", - "count": 1, - "files": [ - "src/lib/data/outages.ts" - ], - "sample": "-system|AS}} 32934 β€” and then a wave of WITHDRAWALs of the [[ip|IPv4]] and [[ipv6|IPv6]] pr" - }, - { - "stem": "SERVFAIL", - "count": 1, - "files": [ - "src/lib/data/outages.ts" - ], - "sample": "ike 1.1.1.1 and 8.8.8.8 start returning SERVFAIL for facebook.com. Apps and humans retry" - }, - { - "stem": "NANOG", - "count": 1, - "files": [ - "src/lib/data/outages.ts" - ], - "sample": "tion: \"Vince Bono's apology email to NANOG that day is preserved in the archives β€”" - }, - { - "stem": "RIS", - "count": 1, - "files": [ - "src/lib/data/outages.ts" - ], - "sample": "ally for hours. {{ripe-ncc|RIPE NCC}}'s RIS data became the canonical post-mortem s" - }, - { - "stem": "LBL", - "count": 1, - "files": [ - "src/lib/data/outages.ts" - ], - "sample": "delivery less likely. Throughput on the LBL-to-UCB path collapsed from 32 kbps to 4" - }, - { - "stem": "UCB", - "count": 1, - "files": [ - "src/lib/data/outages.ts" - ], - "sample": "y less likely. Throughput on the LBL-to-UCB path collapsed from 32 kbps to 40 bps β€”" - }, - { - "stem": "LBL-UCB", - "count": 1, - "files": [ - "src/lib/data/outages.ts" - ], - "sample": "uplicates. Goodput approaches zero. The LBL-UCB path measures 40 bps where it had measu" - }, - { - "stem": "CT", - "count": 1, - "files": [ - "src/lib/data/outages.ts" - ], - "sample": "limit damage.\", mistake: \"At 02:42 CT, a network change with an equipment con" - }, - { - "stem": "GSO", - "count": 1, - "files": [ - "src/lib/data/outages.ts" - ], - "sample": "ff could be split into more than 65,535 GSO segments. The 16-bit counter overflowed" - }, - { - "stem": "OPEN", - "count": 1, - "files": [ - "src/lib/data/protocols/bgp.ts" - ], - "sample": "'Both routers {{exchange|exchange}} OPEN messages containing their {{autonomous-" - }, - { - "stem": "NLRI", - "count": 1, - "files": [ - "src/lib/data/protocols/bgp.ts" - ], - "sample": "messages containing reachable prefixes (NLRI) with path attributes: {{as-path|AS_PAT" - }, - { - "stem": "EGP", - "count": 1, - "files": [ - "src/lib/data/protocols/bgp.ts" - ], - "sample": "Austin. The previous routing protocol (EGP) was unmanageable. They sketched a repl" - }, - { - "stem": "GTSM", - "count": 1, - "files": [ - "src/lib/data/protocols/bgp.ts" - ], - "sample": "tcha', text: 'Some operators enable GTSM (Generalised {{ttl|TTL}} Security Mecha" - }, - { - "stem": "SBC", - "count": 1, - "files": [ - "src/lib/data/protocols/bluetooth.ts" - ], - "sample": "he mandatory {{codec|codec}} (replacing SBC and saving ~50% battery vs A2DP). **{{a" - }, - { - "stem": "A2DP", - "count": 1, - "files": [ - "src/lib/data/protocols/bluetooth.ts" - ], - "sample": "eplacing SBC and saving ~50% battery vs A2DP). **{{auracast|Auracast}}** is the {{si" - }, - { - "stem": "ISOAL", - "count": 1, - "files": [ - "src/lib/data/protocols/bluetooth.ts" - ], - "sample": "privacy against long-term tracking) and ISOAL improvements for {{le-audio|LE Audio}}" - }, - { - "stem": "EURECOM", - "count": 1, - "files": [ - "src/lib/data/protocols/bluetooth.ts" - ], - "sample": "mes', text: \"Daniele Antonioli (then EURECOM, now PostDoc-and-faculty) is the lead a" - }, - { - "stem": "DPSK", - "count": 1, - "files": [ - "src/lib/data/protocols/bluetooth.ts" - ], - "sample": "the air**. Different modulation (GFSK + DPSK for Classic, GFSK only for {{ble|BLE}}" - }, - { - "stem": "FR1", - "count": 1, - "files": [ - "src/lib/data/protocols/cellular.ts" - ], - "sample": "two very different deployment regimes (FR1 sub-6 GHz, FR2 {{mmwave|mmWave}} 24–52" - }, - { - "stem": "LLR", - "count": 1, - "files": [ - "src/lib/data/protocols/cellular.ts" - ], - "sample": "ion}}. The receiver stores soft-decoded LLRs from failed transmissions and combines" - }, - { - "stem": "RLC", - "count": 1, - "files": [ - "src/lib/data/protocols/cellular.ts" - ], - "sample": "er compression', description: '**RLC** runs in TM (transparent), UM (unackno" - }, - { - "stem": "TM", - "count": 1, - "files": [ - "src/lib/data/protocols/cellular.ts" - ], - "sample": "', description: '**RLC** runs in TM (transparent), UM (unacknowledged), or" - }, - { - "stem": "UM", - "count": 1, - "files": [ - "src/lib/data/protocols/cellular.ts" - ], - "sample": "'**RLC** runs in TM (transparent), UM (unacknowledged), or AM (acknowledged)" - }, - { - "stem": "AM", - "count": 1, - "files": [ - "src/lib/data/protocols/cellular.ts" - ], - "sample": "(transparent), UM (unacknowledged), or AM (acknowledged) mode with 10- or 16-bit" - }, - { - "stem": "PDCP", - "count": 1, - "files": [ - "src/lib/data/protocols/cellular.ts" - ], - "sample": "ce numbers}} ({{ts-3gpp|TS}} 38.322). **PDCP** above it ({{ts-3gpp|TS}} 38.323) does" - }, - { - "stem": "ROHC", - "count": 1, - "files": [ - "src/lib/data/protocols/cellular.ts" - ], - "sample": "* above it ({{ts-3gpp|TS}} 38.323) does ROHC {{header|header compression}} (squashin" - }, - { - "stem": "USIM", - "count": 1, - "files": [ - "src/lib/data/protocols/cellular.ts" - ], - "sample": "hentication vector, and the {{ue|UE}}'s USIM verifies AUTN and computes RES*. After" - }, - { - "stem": "AUTN", - "count": 1, - "files": [ - "src/lib/data/protocols/cellular.ts" - ], - "sample": "ctor, and the {{ue|UE}}'s USIM verifies AUTN and computes RES*. After Security Mode" - }, - { - "stem": "RES", - "count": 1, - "files": [ - "src/lib/data/protocols/cellular.ts" - ], - "sample": "|UE}}'s USIM verifies AUTN and computes RES*. After Security Mode Command, {{nas|NA" - }, - { - "stem": "PCF", - "count": 1, - "files": [ - "src/lib/data/protocols/cellular.ts" - ], - "sample": "{upf|UPF}}, {{ausf|AUSF}}, {{udm|UDM}}, PCF, NRF, NEF, NSSF, AF β€” each is a **netwo" - }, - { - "stem": "NRF", - "count": 1, - "files": [ - "src/lib/data/protocols/cellular.ts" - ], - "sample": "UPF}}, {{ausf|AUSF}}, {{udm|UDM}}, PCF, NRF, NEF, NSSF, AF β€” each is a **network fu" - }, - { - "stem": "NEF", - "count": 1, - "files": [ - "src/lib/data/protocols/cellular.ts" - ], - "sample": ", {{ausf|AUSF}}, {{udm|UDM}}, PCF, NRF, NEF, NSSF, AF β€” each is a **network functio" - }, - { - "stem": "NSSF", - "count": 1, - "files": [ - "src/lib/data/protocols/cellular.ts" - ], - "sample": "usf|AUSF}}, {{udm|UDM}}, PCF, NRF, NEF, NSSF, AF β€” each is a **network function** wi" - }, - { - "stem": "AF", - "count": 1, - "files": [ - "src/lib/data/protocols/cellular.ts" - ], - "sample": "SF}}, {{udm|UDM}}, PCF, NRF, NEF, NSSF, AF β€” each is a **network function** with a" - }, - { - "stem": "GPRS", - "count": 1, - "files": [ - "src/lib/data/protocols/cellular.ts" - ], - "sample": "|UPF}} travel over **{{gtp-u|GTP-U}}** (GPRS Tunnelling Protocol β€” User plane) on [[" - }, - { - "stem": "ML", - "count": 1, - "files": [ - "src/lib/data/protocols/cellular.ts" - ], - "sample": "vanced release. New features: {{ai|AI}}/ML in the air interface (CSI feedback comp" - }, - { - "stem": "CSI", - "count": 1, - "files": [ - "src/lib/data/protocols/cellular.ts" - ], - "sample": "res: {{ai|AI}}/ML in the air interface (CSI feedback compression, beam management)," - }, - { - "stem": "SOS", - "count": 1, - "files": [ - "src/lib/data/protocols/cellular.ts" - ], - "sample": "{{apple|Apple}}\\'s Globalstar Emergency SOS round out the satellite-{{direct-to-cel" - }, - { - "stem": "Q3", - "count": 1, - "files": [ - "src/lib/data/protocols/cellular.ts" - ], - "sample": "use cloud-native {{5g-core|5G core}} by Q3 2025; the network averages 6.5 PB/day." - }, - { - "stem": "NEC", - "count": 1, - "files": [ - "src/lib/data/protocols/cellular.ts" - ], - "sample": "land. Multi-vendor mix: Samsung radios, NEC baseband, Wind River cloud platform. Th" - }, - { - "stem": "ARIB", - "count": 1, - "files": [ - "src/lib/data/protocols/cellular.ts" - ], - "sample": "partnership of {{etsi|ETSI}} (Europe), ARIB + TTC (Japan), ATIS (North America), CC" - }, - { - "stem": "TTC", - "count": 1, - "files": [ - "src/lib/data/protocols/cellular.ts" - ], - "sample": "rship of {{etsi|ETSI}} (Europe), ARIB + TTC (Japan), ATIS (North America), CCSA (Ch" - }, - { - "stem": "ATIS", - "count": 1, - "files": [ - "src/lib/data/protocols/cellular.ts" - ], - "sample": "si|ETSI}} (Europe), ARIB + TTC (Japan), ATIS (North America), CCSA (China), TSDSI (I" - }, - { - "stem": "CCSA", - "count": 1, - "files": [ - "src/lib/data/protocols/cellular.ts" - ], - "sample": "IB + TTC (Japan), ATIS (North America), CCSA (China), TSDSI (India), TTA (Korea). Ev" - }, - { - "stem": "TSDSI", - "count": 1, - "files": [ - "src/lib/data/protocols/cellular.ts" - ], - "sample": "n), ATIS (North America), CCSA (China), TSDSI (India), TTA (Korea). Every cellular ph" - }, - { - "stem": "TTA", - "count": 1, - "files": [ - "src/lib/data/protocols/cellular.ts" - ], - "sample": "America), CCSA (China), TSDSI (India), TTA (Korea). Every cellular phone on Earth" - }, - { - "stem": "IMSI", - "count": 1, - "files": [ - "src/lib/data/protocols/cellular.ts" - ], - "sample": "obile Country Code at the start of your IMSI is the protocol\\'s private numbering pl" - }, - { - "stem": "MCC/MNC", - "count": 1, - "files": [ - "src/lib/data/protocols/cellular.ts" - ], - "sample": "ce. Your roaming bill itemises calls by MCC/MNC pair.' }, { title: \"The CDMA-vs-" - }, - { - "stem": "CTIA", - "count": 1, - "files": [ - "src/lib/data/protocols/cellular.ts" - ], - "sample": "tial\", text: 'In January 1989 the US CTIA voted for {{tdma|TDMA}}; later that yea" - }, - { - "stem": "DT", - "count": 1, - "files": [ - "src/lib/data/protocols/cellular.ts" - ], - "sample": "USA, Reliance Jio, parts of Verizon and DT), the {{ue|UE}} receives **only an [[ip" - }, - { - "stem": "PLAT", - "count": 1, - "files": [ - "src/lib/data/protocols/cellular.ts" - ], - "sample": ") β€” {{clat-acr|CLAT}} on the {{ue|UE}}, PLAT/{{nat64|NAT64}} at the operator. **Pitf" - }, - { - "stem": "N6", - "count": 1, - "files": [ - "src/lib/data/protocols/cellular.ts" - ], - "sample": "ode 4 (Frag Needed) messages on the SGi/N6 side. The {{mtu|MTU}} on a {{gtp-u|GTP-" - }, - { - "stem": "EDNS", - "count": 1, - "files": [ - "src/lib/data/protocols/dns.ts" - ], - "sample": "byte response. Today the limit is moot (EDNS allows larger responses), but the 13-le" - }, - { - "stem": "ALIAS", - "count": 1, - "files": [ - "src/lib/data/protocols/dns.ts" - ], - "sample": "ords. Some [[dns|DNS]] providers offer \"ALIAS\" or \"ANAME\" pseudo-records that work ar" - }, - { - "stem": "ANAME", - "count": 1, - "files": [ - "src/lib/data/protocols/dns.ts" - ], - "sample": "[[dns|DNS]] providers offer \"ALIAS\" or \"ANAME\" pseudo-records that work around this;" - }, - { - "stem": "USER", - "count": 1, - "files": [ - "src/lib/data/protocols/ftp.ts" - ], - "sample": "o server port 21 and authenticates with USER and PASS commands. This connection stay" - }, - { - "stem": "PASS", - "count": 1, - "files": [ - "src/lib/data/protocols/ftp.ts" - ], - "sample": "port 21 and authenticates with USER and PASS commands. This connection stays open fo" - }, - { - "stem": "CWD", - "count": 1, - "files": [ - "src/lib/data/protocols/ftp.ts" - ], - "sample": "ient browses the remote filesystem with CWD (change directory), PWD (print working" - }, - { - "stem": "PWD", - "count": 1, - "files": [ - "src/lib/data/protocols/ftp.ts" - ], - "sample": "filesystem with CWD (change directory), PWD (print working directory), and LIST (di" - }, - { - "stem": "LIST", - "count": 1, - "files": [ - "src/lib/data/protocols/ftp.ts" - ], - "sample": "ry), PWD (print working directory), and LIST (directory listing). All commands are h" - }, - { - "stem": "PASV", - "count": 1, - "files": [ - "src/lib/data/protocols/ftp.ts" - ], - "sample": "CP]] connection opens. In passive mode (PASV), the server tells the client which por" - }, - { - "stem": "RETR", - "count": 1, - "files": [ - "src/lib/data/protocols/ftp.ts" - ], - "sample": "er', description: 'Client issues RETR (download) or STOR (upload). Data flows" - }, - { - "stem": "STOR", - "count": 1, - "files": [ - "src/lib/data/protocols/ftp.ts" - ], - "sample": ": 'Client issues RETR (download) or STOR (upload). Data flows on the data connec" - }, - { - "stem": "SETTINGS", - "count": 1, - "files": [ - "src/lib/data/protocols/http2.ts" - ], - "sample": "client and server {{exchange|exchange}} SETTINGS frames establishing max concurrent stre" - }, - { - "stem": "RR", - "count": 1, - "files": [ - "src/lib/data/protocols/http3.ts" - ], - "sample": "st. The HTTPS [[dns|DNS]] record (HTTPS RR, [[rfc:9460|RFC 9460]]) closes this gap" - }, - { - "stem": "VT100", - "count": 1, - "files": [ - "src/lib/data/protocols/icmp.ts" - ], - "sample": "a DEC PDP-11/70', caption: 'A DEC VT100 terminal β€” the type of terminal where e" - }, - { - "stem": "INBOX", - "count": 1, - "files": [ - "src/lib/data/protocols/imap.ts" - ], - "sample": "ription: 'Client selects a mailbox (INBOX, Drafts, Sent, etc.). Server reports me" - }, - { - "stem": "UIDVALIDITY", - "count": 1, - "files": [ - "src/lib/data/protocols/imap.ts" - ], - "sample": ", recent messages, available flags, and UIDVALIDITY for cache validation.' }, { titl" - }, - { - "stem": "SEARCH", - "count": 1, - "files": [ - "src/lib/data/protocols/imap.ts" - ], - "sample": "tion: 'Client searches server-side (SEARCH FROM \"alice\" SINCE 1-Mar-2024) and modi" - }, - { - "stem": "FROM", - "count": 1, - "files": [ - "src/lib/data/protocols/imap.ts" - ], - "sample": "'Client searches server-side (SEARCH FROM \"alice\" SINCE 1-Mar-2024) and modifies" - }, - { - "stem": "SINCE", - "count": 1, - "files": [ - "src/lib/data/protocols/imap.ts" - ], - "sample": "arches server-side (SEARCH FROM \"alice\" SINCE 1-Mar-2024) and modifies flags (\\\\Seen," - }, - { - "stem": "SPD", - "count": 1, - "files": [ - "src/lib/data/protocols/ipsec.ts" - ], - "sample": "matching the Security Policy Database (SPD) is wrapped in an **{{esp|ESP}} {{heade" - }, - { - "stem": "CRYSTALS", - "count": 1, - "files": [ - "src/lib/data/protocols/ipsec.ts" - ], - "sample": "s|FIPS}} 203 β€” the standardised form of CRYSTALS-Kyber. This is the post-quantum {{kem|K" - }, - { - "stem": "KE", - "count": 1, - "files": [ - "src/lib/data/protocols/ipsec.ts" - ], - "sample": "ge}} and [[rfc:9370|RFC 9370]] multiple-KE β€” meaning two or more KEMs (e.g. classi" - }, - { - "stem": "TFS", - "count": 1, - "files": [ - "src/lib/data/protocols/ipsec.ts" - ], - "sample": "[[rfc:9347|RFC 9347]] {{ip-address|IP}}-TFS (Traffic Flow Security β€” fixed-size agg" - }, - { - "stem": "WG", - "count": 1, - "files": [ - "src/lib/data/protocols/ipsec.ts" - ], - "sample": ". Fifth revision of the [[ipsec|IPsec]] WG draft that bakes {{ml-kem|ML-KEM}} into" - }, - { - "stem": "HSR", - "count": 1, - "files": [ - "src/lib/data/protocols/ipsec.ts" - ], - "sample": "escription: 'strongSwan (originally HSR Rapperswil, now under [[pioneer:andreas" - }, - { - "stem": "OST", - "count": 1, - "files": [ - "src/lib/data/protocols/ipsec.ts" - ], - "sample": "dreas-steffen|Andreas Steffen]] and the OST team; owned by secunet AG since June 20" - }, - { - "stem": "AG", - "count": 1, - "files": [ - "src/lib/data/protocols/ipsec.ts" - ], - "sample": "en]] and the OST team; owned by secunet AG since June 2022, central to the BSI SIN" - }, - { - "stem": "BSI", - "count": 1, - "files": [ - "src/lib/data/protocols/ipsec.ts" - ], - "sample": "unet AG since June 2022, central to the BSI SINA high-security solution) and Libres" - }, - { - "stem": "SINA", - "count": 1, - "files": [ - "src/lib/data/protocols/ipsec.ts" - ], - "sample": "AG since June 2022, central to the BSI SINA high-security solution) and Libreswan (" - }, - { - "stem": "GCM", - "count": 1, - "files": [ - "src/lib/data/protocols/ipsec.ts" - ], - "sample": "VPN}} ({{ikev2|IKEv2}}, {{aes|AES}}-256-GCM, {{ecdh|ECDH}} groups 19–24, 5 Gbps/tun" - }, - { - "stem": "AZ", - "count": 1, - "files": [ - "src/lib/data/protocols/ipsec.ts" - ], - "sample": "VPN}} Gateway (10 Gbps aggregate on the AZ-redundant SKU), {{gcp|GCP}} Cloud {{vpn" - }, - { - "stem": "OCI", - "count": 1, - "files": [ - "src/lib/data/protocols/ipsec.ts" - ], - "sample": "nt SKU), {{gcp|GCP}} Cloud {{vpn|VPN}}, OCI Site-to-Site {{vpn|VPN}}. [[ipsec|IPsec" - }, - { - "stem": "VPC", - "count": 1, - "files": [ - "src/lib/data/protocols/ipsec.ts" - ], - "sample": "mqtt-connect|connect}} my on-prem to my VPC\" sku across every cloud.' }, { o" - }, - { - "stem": "ITAR", - "count": 1, - "files": [ - "src/lib/data/protocols/ipsec.ts" - ], - "sample": "same code as a regulated munition under ITAR. *Karn v. U.S. State Department* became" - }, - { - "stem": "BENIGNCERTAIN", - "count": 1, - "files": [ - "src/lib/data/protocols/ipsec.ts" - ], - "sample": "dow Brokers leak (August 2016) revealed BENIGNCERTAIN β€” an NSA exploit that extracted {{cisco" - }, - { - "stem": "PIX", - "count": 1, - "files": [ - "src/lib/data/protocols/ipsec.ts" - ], - "sample": "exploit that extracted {{cisco|Cisco}} PIX {{vpn|VPN}} private keys from IKEv1 ({{" - }, - { - "stem": "PPK", - "count": 1, - "files": [ - "src/lib/data/protocols/ipsec.ts" - ], - "sample": "table. [[rfc:8784|RFC 8784]] ({{pq|PQ}}-PPK) is co-authored by {{cisco|Cisco}}, {{a" - }, - { - "stem": "ELVIS-PLUS", - "count": 1, - "files": [ - "src/lib/data/protocols/ipsec.ts" - ], - "sample": "ed by {{cisco|Cisco}}, {{aws|AWS}}, and ELVIS-PLUS engineers β€” [[ipsec|IPsec]] has always" - }, - { - "stem": "ECMP", - "count": 1, - "files": [ - "src/lib/data/protocols/ipsec.ts" - ], - "sample": "efault to **32 entries**. On a 10 Gbps+ ECMP-parallel tunnel ({{linux|Linux}} {{xfrm" - }, - { - "stem": "KB", - "count": 1, - "files": [ - "src/lib/data/protocols/ipsec.ts" - ], - "sample": "he connection hangs after the first few KB. **Cure:** [[tcp|TCP]] {{mss|MSS}} clam" - }, - { - "stem": "IDL", - "count": 1, - "files": [ - "src/lib/data/protocols/json-rpc.ts" - ], - "sample": "] strips this to pure {{json|JSON}}: no IDL, no code generation, no binary encoding" - }, - { - "stem": "TGS-REQ", - "count": 1, - "files": [ - "src/lib/data/protocols/kerberos.ts" - ], - "sample": "TTP}}/web1.example.com\\`, she sends a **TGS-REQ** to the {{kerberos-kdc|KDC}}\\'s {{kerb" - }, - { - "stem": "REP", - "count": 1, - "files": [ - "src/lib/data/protocols/kerberos.ts" - ], - "sample": "eb1 returns an **{{ap-access-point|AP}}-REP** with its own timestamp for {{mtls|mut" - }, - { - "stem": "EXAMPLE.COM", - "count": 1, - "files": [ - "src/lib/data/protocols/kerberos.ts" - ], - "sample": "ls', description: \"When Alice in EXAMPLE.COM wants to access a service in PARTNER.CO" - }, - { - "stem": "SMB", - "count": 1, - "files": [ - "src/lib/data/protocols/kerberos.ts" - ], - "sample": "(`Authorization: Negotiate <base64>`), SMB, LDAP, and other applications transpare" - }, - { - "stem": "LDAP", - "count": 1, - "files": [ - "src/lib/data/protocols/kerberos.ts" - ], - "sample": "thorization: Negotiate <base64>`), SMB, LDAP, and other applications transparently u" - }, - { - "stem": "EC", - "count": 1, - "files": [ - "src/lib/data/protocols/kerberos.ts" - ], - "sample": "adline features: **PKINIT {{ecdh|ECDH}}/EC certs** (smart-card auth on {{curve2551" - }, - { - "stem": "FAST", - "count": 1, - "files": [ - "src/lib/data/protocols/kerberos.ts" - ], - "sample": "P-384), **paChecksum2** support (longer FAST-armored {{checksum|checksum}} to retire" - }, - { - "stem": "SU/KTH", - "count": 1, - "files": [ - "src/lib/data/protocols/kerberos.ts" - ], - "sample": "to {{mit|MIT}} Kerberos, originated at SU/KTH in Sweden. {{apple|Apple}} shipped Heim" - }, - { - "stem": "KER", - "count": 1, - "files": [ - "src/lib/data/protocols/kerberos.ts" - ], - "sample": "g crosses without a ticket. Pronounced *KER-ber-os* in English; *KEHR-ber-os* in mo" - }, - { - "stem": "KEHR", - "count": 1, - "files": [ - "src/lib/data/protocols/kerberos.ts" - ], - "sample": "t. Pronounced *KER-ber-os* in English; *KEHR-ber-os* in modern Greek.' }, { t" - }, - { - "stem": "V5", - "count": 1, - "files": [ - "src/lib/data/protocols/kerberos.ts" - ], - "sample": "ld ship Kerberos-shaped applications. **V5** ([[rfc:4120|RFC 4120]], 2005) was des" - }, - { - "stem": "UDP/123", - "count": 1, - "files": [ - "src/lib/data/protocols/kerberos.ts" - ], - "sample": "[[ntp|NTP]] servers, firewalls blocking UDP/123, virtualised {{hosts-bare|hosts}} with" - }, - { - "stem": "FQDN", - "count": 1, - "files": [ - "src/lib/data/protocols/kerberos.ts" - ], - "sample": "ails. **Cure:** register both short and FQDN SPNs in the keytab; set `dns_canonicali" - }, - { - "stem": "NEA1", - "count": 1, - "files": [ - "src/lib/data/protocols/kerberos.ts" - ], - "sample": "y|AD}} environments have **{{rc4|RC4}} (NEA1)** still enabled β€” the {{encryption|enc" - }, - { - "stem": "NT", - "count": 1, - "files": [ - "src/lib/data/protocols/kerberos.ts" - ], - "sample": "cause {{rc4|RC4}} keys are derived from NT hash and brute-force in hours. **Cure:*" - }, - { - "stem": "FB", - "count": 1, - "files": [ - "src/lib/data/protocols/mdns-dns-sd.ts" - ], - "sample": "\\`224.0.0.251\\` ([[ipv6|IPv6]]: \\`FF02::FB\\`). Two flag bits get repurposed: the h" - }, - { - "stem": "DLA-3990", - "count": 1, - "files": [ - "src/lib/data/protocols/mdns-dns-sd.ts" - ], - "sample": "DNS]] implementation. Patched in Debian DLA-3990 (December 2024); still under active mai" - }, - { - "stem": "CAPWAP", - "count": 1, - "files": [ - "src/lib/data/protocols/mdns-dns-sd.ts" - ], - "sample": "}} at 100% and Access Points lose their CAPWAP tunnel. The latest in a decade-long pat" - }, - { - "stem": "LGPL", - "count": 1, - "files": [ - "src/lib/data/protocols/mdns-dns-sd.ts" - ], - "sample": "nux|Linux}}/{{bsd|BSD}} implementation, LGPL, maintained by Trent Lloyd. Bundled by" - }, - { - "stem": "BBC", - "count": 1, - "files": [ - "src/lib/data/protocols/mdns-dns-sd.ts" - ], - "sample": "a 16-player networked tank game on the BBC Micro in 1987 and ported it to the Mac." - }, - { - "stem": "COBS", - "count": 1, - "files": [ - "src/lib/data/protocols/mdns-dns-sd.ts" - ], - "sample": "ed **Consistent Overhead Byte Stuffing (COBS)** β€” the framing algorithm now widely u" - }, - { - "stem": "BAF", - "count": 1, - "files": [ - "src/lib/data/protocols/mdns-dns-sd.ts" - ], - "sample": "l\" ({{ndss-conf|NDSS}} 2014)** measured BAF up to ~10Γ— for mDNS. **CERT/CC VU#55062" - }, - { - "stem": "CERT/CC", - "count": 1, - "files": [ - "src/lib/data/protocols/mdns-dns-sd.ts" - ], - "sample": ")** measured BAF up to ~10Γ— for mDNS. **CERT/CC VU#550620 (March 2015)** and **Akamai (" - }, - { - "stem": "VU", - "count": 1, - "files": [ - "src/lib/data/protocols/mdns-dns-sd.ts" - ], - "sample": "ured BAF up to ~10Γ— for mDNS. **CERT/CC VU#550620 (March 2015)** and **Akamai (Dec" - }, - { - "stem": "BCP", - "count": 1, - "files": [ - "src/lib/data/protocols/mdns-dns-sd.ts" - ], - "sample": "cal {{unicast|unicast}} queries; deploy BCP 38 ingress filtering.' }, { t" - }, - { - "stem": "DSN", - "count": 1, - "files": [ - "src/lib/data/protocols/mptcp.ts" - ], - "sample": "ta {{sequence-number|Sequence Number}} (DSN) ensures correct ordering across all su" - }, - { - "stem": "TB", - "count": 1, - "files": [ - "src/lib/data/protocols/nat-traversal.ts" - ], - "sample": "5+ locations with $0.05/GB egress and 1 TB free per month β€” the first major price" - }, - { - "stem": "FINGERPRINT", - "count": 1, - "files": [ - "src/lib/data/protocols/nat-traversal.ts" - ], - "sample": "p-address|IP}} version field, but the **FINGERPRINT** attribute {{checksum|checksum}} is XO" - }, - { - "stem": "SOCKS", - "count": 1, - "files": [ - "src/lib/data/protocols/nat-traversal.ts" - ], - "sample": "l`/`Frida` and use the server as a free SOCKS-style proxy into your private network." - }, - { - "stem": "NFC-A/B/F", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "range is ≀10 cm for {{iso|ISO}} 14443 (NFC-A/B/F) and historically ≀1 m for {{iso|ISO}}" - }, - { - "stem": "ALM", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "e {{load-modulation|load modulation}}* (ALM) instead, generating a small reflected" - }, - { - "stem": "WUPA", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "adcasts a 7-bit {{reqa|REQA}} (0x26) or WUPA (0x52) short frame; the card responds w" - }, - { - "stem": "NVB", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "collision}}** loop with {{sel-iso|SEL}}+NVB frames ({{sel-iso|SEL}}=0x93 for cascad" - }, - { - "stem": "CL2", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "EL}}=0x93 for cascade level 1, 0x95 for CL2, 0x97 for CL3), converging on each byte" - }, - { - "stem": "CL3", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "cascade level 1, 0x95 for CL2, 0x97 for CL3), converging on each byte of the {{uid|" - }, - { - "stem": "FWI", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "negotiate frame size (FSCI) and timing (FWI). T2T cards skip {{rats|RATS}} and go s" - }, - { - "stem": "RECORD", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "ich files to read; {{read-record|READ}} RECORDs pull the {{pan-id|PAN}}, expiry, and pu" - }, - { - "stem": "MB/ME", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "cord begins with a 1-byte header β€” bits MB/ME (Message Begin/End), CF (Chunk Flag), S" - }, - { - "stem": "CF", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "eader β€” bits MB/ME (Message Begin/End), CF (Chunk Flag), SR (Short Record β€” 1-byte" - }, - { - "stem": "SR", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "E (Message Begin/End), CF (Chunk Flag), SR (Short Record β€” 1-byte length vs 4), IL" - }, - { - "stem": "IL", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "SR (Short Record β€” 1-byte length vs 4), IL ({{id-identifier|ID}} Length present)," - }, - { - "stem": "NFC-WLC", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "EC standard in **March 2026** alongside NFC-WLC.\" }, { title: 'Three transports," - }, - { - "stem": "FPAN", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "rdholder's real Funding {{pan-id|PAN}} (FPAN) is never stored on the device; instead" - }, - { - "stem": "EEA", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "eld-Detect. Available **only inside the EEA** (27 EU states + Iceland, Liechtenstei" - }, - { - "stem": "CMA", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "emplated and the watch-items are the UK CMA, Japan JFTC, and Australian ACCC.\"," - }, - { - "stem": "JFTC", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "d the watch-items are the UK CMA, Japan JFTC, and Australian ACCC.\", source: {" - }, - { - "stem": "ACCC", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "the UK CMA, Japan JFTC, and Australian ACCC.\", source: { url: 'https://ec.eu" - }, - { - "stem": "CR15", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "ting volume). Certification Release 15 (CR15) accepts applications by early 2026; fu" - }, - { - "stem": "DK3", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "line: *cross-version compatibility* β€” a DK3 phone unlocks a DK4 car and vice versa." - }, - { - "stem": "DK4", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "compatibility* β€” a DK3 phone unlocks a DK4 car and vice versa. **115 vehicle/modul" - }, - { - "stem": "ESPR", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "gn for Sustainable Products Regulation (ESPR).\", source: { url: 'https://nfc-" - }, - { - "stem": "CIPURSE", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "smart cards ({{mifare|MIFARE}}, FeliCa, CIPURSE), TfL bet on **bank-issued {{emv-crypto" - }, - { - "stem": "DG1", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "with a small {{icao|ICAO}} file system (DG1 {{mrz|MRZ}}, DG2 photo, EF.SOD signatur" - }, - { - "stem": "DG2", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "ao|ICAO}} file system (DG1 {{mrz|MRZ}}, DG2 photo, EF.SOD signature, EF.COM index," - }, - { - "stem": "EF.SOD", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "ile system (DG1 {{mrz|MRZ}}, DG2 photo, EF.SOD signature, EF.COM index, plus optional" - }, - { - "stem": "EF.COM", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "mrz|MRZ}}, DG2 photo, EF.SOD signature, EF.COM index, plus optional DG3 fingerprints /" - }, - { - "stem": "DG3", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "signature, EF.COM index, plus optional DG3 fingerprints / DG4 iris). The reader ca" - }, - { - "stem": "DG4", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "index, plus optional DG3 fingerprints / DG4 iris). The reader cannot get any data w" - }, - { - "stem": "BAC", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "he reader cannot get any data without **BAC** (legacy 3DES from MRZ) or **PACE** (m" - }, - { - "stem": "PACE", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "out **BAC** (legacy 3DES from MRZ) or **PACE** (modern {{ecdh|ECDH}} from MRZ or 6-d" - }, - { - "stem": "DTC-PC/VC", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "it CAN). The Digital Travel Credential (DTC-PC/VC) β€” passport on phone β€” is in airport pi" - }, - { - "stem": "EV1", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "e|MIFARE}} Classic in **1994**, DESFire EV1 in **2006**, {{mifare|MIFARE}} Plus in" - }, - { - "stem": "EV2", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "fare|MIFARE}} Plus in **2011**, DESFire EV2 in 2016, EV3 in the early 2020s. The Cl" - }, - { - "stem": "EAL5", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "nts β€” full {{aes|AES}}, Common Criteria EAL5+, side-channel hardened. Dutch OV-chipk" - }, - { - "stem": "ZEEKR", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": ", XPENG, Geely group β€” Volvo, Polestar, ZEEKR, Lynk & Co., smart, Lotus).\" } ]," - }, - { - "stem": "LC", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "PCD}} and {{picc|PICC}} each present an LC resonant tank around 13.56 MHz; small d" - }, - { - "stem": "PN553", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "lation}} in the controller ({{nxp|NXP}} PN553 onward). Q factor: lower Q broadens the" - }, - { - "stem": "CDA", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "am|EMV}} Mode** (normal 'fast tap' with CDA). The card returns an AIP byte that sig" - }, - { - "stem": "TU", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ], - "sample": "to a confederate's phone at a terminal. TU Darmstadt's **NFCGate** (2015+) made th" - }, - { - "stem": "T2-T1", - "count": 1, - "files": [ - "src/lib/data/protocols/ntp.ts" - ], - "sample": "description: '{{offset|Offset}} = ((T2-T1) + (T3-T4)) / 2. Delay = (T4-T1) - (T3-" - }, - { - "stem": "T3-T4", - "count": 1, - "files": [ - "src/lib/data/protocols/ntp.ts" - ], - "sample": "n: '{{offset|Offset}} = ((T2-T1) + (T3-T4)) / 2. Delay = (T4-T1) - (T3-T2). The c" - }, - { - "stem": "T4-T1", - "count": 1, - "files": [ - "src/lib/data/protocols/ntp.ts" - ], - "sample": "t}} = ((T2-T1) + (T3-T4)) / 2. Delay = (T4-T1) - (T3-T2). The clock is adjusted gradu" - }, - { - "stem": "T3-T2", - "count": 1, - "files": [ - "src/lib/data/protocols/ntp.ts" - ], - "sample": "-T1) + (T3-T4)) / 2. Delay = (T4-T1) - (T3-T2). The clock is adjusted gradually to av" - }, - { - "stem": "INITIAL", - "count": 1, - "files": [ - "src/lib/data/protocols/ospf.ts" - ], - "sample": "fc-doc|RFC}} 8405 {{spf|SPF}} back-off (INITIAL/SHORT_WAIT/LONG_WAIT) throttles {{spf|S" - }, - { - "stem": "TE", - "count": 1, - "files": [ - "src/lib/data/protocols/ospf.ts" - ], - "sample": "with its own metric ({{igp|IGP}} cost, TE cost, min-delay) and constraints (inclu" - }, - { - "stem": "SID", - "count": 1, - "files": [ - "src/lib/data/protocols/ospf.ts" - ], - "sample": "Rv6 Locator advertisement, and SRv6 End SID encoding to [[ospf|OSPFv3]]. Edited by" - }, - { - "stem": "FAD", - "count": 1, - "files": [ - "src/lib/data/protocols/ospf.ts" - ], - "sample": "-2}} keychain authentication, Flex-Algo FAD with {{srlg|SRLG}}-exclude, and link-de" - }, - { - "stem": "ACX/PTX", - "count": 1, - "files": [ - "src/lib/data/protocols/ospf.ts" - ], - "sample": "xclude, and link-delay normalisation on ACX/PTX hardware β€” bringing Flex-Algo from \"shi" - }, - { - "stem": "C0/S0", - "count": 1, - "files": [ - "src/lib/data/protocols/rtmp.ts" - ], - "sample": "[[rtmp|RTMP]] {{handshake|handshake}} (C0/S0, C1/S1, C2/S2) exchanging timestamps an" - }, - { - "stem": "C1/S1", - "count": 1, - "files": [ - "src/lib/data/protocols/rtmp.ts" - ], - "sample": "|RTMP]] {{handshake|handshake}} (C0/S0, C1/S1, C2/S2) exchanging timestamps and rando" - }, - { - "stem": "C2/S2", - "count": 1, - "files": [ - "src/lib/data/protocols/rtmp.ts" - ], - "sample": "{{handshake|handshake}} (C0/S0, C1/S1, C2/S2) exchanging timestamps and random bytes" - }, - { - "stem": "ECHO", - "count": 1, - "files": [ - "src/lib/data/protocols/sctp.ts" - ], - "sample": "k|INIT}}-{{ack|ACK}}, {{cookie|COOKIE}}-ECHO, {{cookie|COOKIE}}-{{ack|ACK}}) that pr" - }, - { - "stem": "SAVPF", - "count": 1, - "files": [ - "src/lib/data/protocols/sdp.ts" - ], - "sample": "video), transport protocol ([[rtp|RTP]]/SAVPF), port number, and list of supported {{" - }, - { - "stem": "CTS-3000", - "count": 1, - "files": [ - "src/lib/data/protocols/sdp.ts" - ], - "sample": "n: 'The {{cisco|Cisco}} TelePresence CTS-3000 prototype β€” the kind of immersive video" - }, - { - "stem": "PJSIP", - "count": 1, - "files": [ - "src/lib/data/protocols/sip.ts" - ], - "sample": "fg) # Sends SIP REGISTER`, caption: 'PJSIP registers with a [[sip|SIP]] server β€” t" - }, - { - "stem": "PLAIN", - "count": 1, - "files": [ - "src/lib/data/protocols/smtp.ts" - ], - "sample": "ogin-auth|LOGIN}} or {{smtp-auth|AUTH}} PLAIN.' }, { title: 'Envelope & messag" - }, - { - "stem": "USDA", - "count": 1, - "files": [ - "src/lib/data/protocols/soap.ts" - ], - "sample": ": 'The {{ibm|IBM}} System/360 at the USDA (1966). Mainframes like these laid the" - }, - { - "stem": "MESSAGE", - "count": 1, - "files": [ - "src/lib/data/protocols/stomp.ts" - ], - "sample": "ers matching messages to subscribers as MESSAGE frames. Client can {{ack|ACK}}/{{nack|N" - }, - { - "stem": "LDP", - "count": 1, - "files": [ - "src/lib/data/protocols/tcp.ts" - ], - "sample": "p|TCP]]-{{md5|MD5}} used by [[bgp|BGP]]/LDP. Same release added microsecond-resolut" - }, - { - "stem": "MSL", - "count": 1, - "files": [ - "src/lib/data/protocols/tcp.ts" - ], - "sample": "-wait|TIME_WAIT}}** for ~60 seconds (2Γ— MSL) on {{linux|Linux}}. Why? A delayed seg" - }, - { - "stem": "ACME", - "count": 1, - "files": [ - "src/lib/data/protocols/tls.ts" - ], - "sample": "or the web. All certificates issued via ACME. ~3M certificates renewed daily.' }" - }, - { - "stem": "IR-UWB", - "count": 1, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "d of modulating a continuous carrier, **IR-UWB** transmits sub-nanosecond Gaussian-mon" - }, - { - "stem": "BPM", - "count": 1, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "lses at one of two time-slot positions (BPM) with chosen polarity ({{bpsk|BPSK}}) β€”" - }, - { - "stem": "GAP", - "count": 1, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "liro|Aliro 1.0}}**: **(1)** {{ble|BLE}} GAP advertising with the application's serv" - }, - { - "stem": "TB/NTB", - "count": 1, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "10–30 cm. *Secure ranging:* Wi-Fi 11az TB/NTB with PASN vs. UWB {{sts|STS}}. *Infrast" - }, - { - "stem": "PASN", - "count": 1, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "Secure ranging:* Wi-Fi 11az TB/NTB with PASN vs. UWB {{sts|STS}}. *Infrastructure:*" - }, - { - "stem": "PSD", - "count": 1, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "\"{{fcc|FCC}} Part 15.519 caps average PSD at **βˆ’41.3 dBm/MHz** across 3.1–10.6 GH" - }, - { - "stem": "AV", - "count": 1, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "la Model 3 / Y phone-as-a-key (CVSS 6.8 AV:A/AC:H/PR:N/{{ui|UI}}:N/S:U/C:H/I:H/A:N" - }, - { - "stem": "AC", - "count": 1, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "del 3 / Y phone-as-a-key (CVSS 6.8 AV:A/AC:H/PR:N/{{ui|UI}}:N/S:U/C:H/I:H/A:N). ~$" - }, - { - "stem": "PIN", - "count": 1, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "Kwikset/Weiser Kevo. Tesla recommended PIN-to-Drive as a stopgap; the deeper indus" - }, - { - "stem": "D02", - "count": 1, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "sed to **Draft D03 in September 2025** (D02 March 2025), with ratification expected" - }, - { - "stem": "NCAP", - "count": 1, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "d-presence detection (driven by EU Euro NCAP rules from 2025); LRP+{{hrp-uwb|HRP}} d" - }, - { - "stem": "LRP", - "count": 1, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "riven by EU Euro NCAP rules from 2025); LRP+{{hrp-uwb|HRP}} dual-mode hardware supp" - }, - { - "stem": "ST64UWB", - "count": 1, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "ound {{sts|STS}}. STMicroelectronics' **ST64UWB** (announced Q1 2026, 18 nm FD-SOI) is" - }, - { - "stem": "FD-SOI", - "count": 1, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "' **ST64UWB** (announced Q1 2026, 18 nm FD-SOI) is the first commercial 4ab silicon, w" - }, - { - "stem": "VW", - "count": 1, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "edes, Hyundai/Kia, Audi (new for 2025), VW, Porsche, GM, Ford, and Chinese OEMs (N" - }, - { - "stem": "ASSA", - "count": 1, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "le|Apple}}, {{google|Google}}, Samsung, ASSA ABLOY, {{nxp|NXP}}, Infineon, STMicroel" - }, - { - "stem": "ABLOY", - "count": 1, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "ple}}, {{google|Google}}, Samsung, ASSA ABLOY, {{nxp|NXP}}, Infineon, STMicroelectron" - }, - { - "stem": "EQS", - "count": 1, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "on the Wallet-based Digital Key for the EQS and S-Class from 2022. **{{nxp|NXP}} SR" - }, - { - "stem": "S22/S23/S24", - "count": 1, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "laxy S21+ / S21 Ultra / Note 20 Ultra / S22/S23/S24 (UWB-equipped models) for AR-based dire" - }, - { - "stem": "U100", - "count": 1, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "ung's **Exynos {{mqtt-connect|Connect}} U100** in-house UWB silicon also shipped in" - }, - { - "stem": "PTP", - "count": 1, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "} over wired [[ethernet|Ethernet]] with PTP-grade clock distribution. **{{cisco|Cis" - }, - { - "stem": "L1", - "count": 1, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "d-won against {{gps|GPS}} (operating at L1=1575.42 MHz), avionics, and DoD interes" - }, - { - "stem": "EIRP", - "count": 1, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "-of-life systems. The **βˆ’41.3 dBm/MHz** EIRP limit is essentially the Β§15.209 backgr" - }, - { - "stem": "MB-OFDM", - "count": 1, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "After three years of deadlock between **MB-OFDM** ({{intel|Intel}} + WiMedia Alliance)" - }, - { - "stem": "DS-UWB", - "count": 1, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "intel|Intel}} + WiMedia Alliance) and **DS-UWB** (Freescale + UWB Forum), neither side" - }, - { - "stem": "HI", - "count": 1, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "ty required to ratify. At the Waikoloa, HI interim on **19 January 2006** the task" - }, - { - "stem": "DW1000", - "count": 1, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "Hz wide. Older silicon ({{qorvo|Qorvo}} DW1000) supports only Channel 5; everything fr" - }, - { - "stem": "PCB", - "count": 1, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "handle UWB anchors typically use planar PCB patches with carefully controlled groun" - }, - { - "stem": "BLE/UWB", - "count": 1, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "eeps the user in their car. **(d)** Log BLE/UWB transition failures separately for diag" - }, - { - "stem": "CIR", - "count": 1, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "rection using channel-impulse-response (CIR) features; recent Adaptive Kalman Filte" - }, - { - "stem": "LOS", - "count": 1, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "lace infrastructure anchors to maximise LOS to the working volume; ceiling mounts a" - }, - { - "stem": "PRF", - "count": 1, - "files": [ - "src/lib/data/protocols/uwb.ts" - ], - "sample": "**(b)** Use {{bprf|BPRF}} (~64 MHz mean PRF) for tag-side rather than HPRF. **(c)**" - }, - { - "stem": "EAPOL", - "count": 1, - "files": [ - "src/lib/data/protocols/wifi.ts" - ], - "sample": "{{access-point|AP}} perform a 4-message EAPOL {{handshake|handshake}} to derive per-s" - }, - { - "stem": "RA", - "count": 1, - "files": [ - "src/lib/data/protocols/wifi.ts" - ], - "sample": "AC}} addresses (three typically used) β€” RA, TA, and DA β€” and are encrypted with th" - }, - { - "stem": "TA", - "count": 1, - "files": [ - "src/lib/data/protocols/wifi.ts" - ], - "sample": "addresses (three typically used) β€” RA, TA, and DA β€” and are encrypted with the se" - }, - { - "stem": "DA", - "count": 1, - "files": [ - "src/lib/data/protocols/wifi.ts" - ], - "sample": "es (three typically used) β€” RA, TA, and DA β€” and are encrypted with the session ke" - }, - { - "stem": "BSSID", - "count": 1, - "files": [ - "src/lib/data/protocols/wifi.ts" - ], - "sample": "capy in monitor mode β€” revealing SSIDs, BSSIDs, and channels', alternatives: [ {" - }, - { - "stem": "MAC1", - "count": 1, - "files": [ - "src/lib/data/protocols/wireguard.ts" - ], - "sample": "a {{wg-tai64n|TAI64N timestamp}}. Plus MAC1 (proves the initiator knows the respond" - }, - { - "stem": "MAC2", - "count": 1, - "files": [ - "src/lib/data/protocols/wireguard.ts" - ], - "sample": "iator knows the responder's pubkey) and MAC2 ({{cookie|cookie}} under load, DoS shie" - }, - { - "stem": "H1", - "count": 1, - "files": [ - "src/lib/data/protocols/wireguard.ts" - ], - "sample": "et sizes, randomised header type bytes (H1–H4 ranges instead of fixed 1–4), random" - }, - { - "stem": "H4", - "count": 1, - "files": [ - "src/lib/data/protocols/wireguard.ts" - ], - "sample": "sizes, randomised header type bytes (H1–H4 ranges instead of fixed 1–4), random S1" - }, - { - "stem": "AWG", - "count": 1, - "files": [ - "src/lib/data/protocols/wireguard.ts" - ], - "sample": "ad of fixed 1–4), random S1/S2 padding. AWG 2.0 adds optional QUIC/{{dns-resolution" - }, - { - "stem": "XEP", - "count": 1, - "files": [ - "src/lib/data/protocols/xmpp.ts" - ], - "sample": "e base protocol is minimal. Hundreds of XEPs add features: multi-user chat, {{http-m" - }, - { - "stem": "QPSK", - "count": 1, - "files": [ - "src/lib/data/protocols/zigbee.ts" - ], - "sample": "The dominant {{phy|PHY}} is **2.4 GHz O-QPSK** with 16 channels (11–26), 5 MHz spaci" - }, - { - "stem": "NA", - "count": 1, - "files": [ - "src/lib/data/protocols/zigbee.ts" - ], - "sample": "kbit/s {{bpsk|BPSK}}) and 902–928 MHz (NA, 40 kbit/s {{bpsk|BPSK}}) give better w" - }, - { - "stem": "FSK", - "count": 1, - "files": [ - "src/lib/data/protocols/zigbee.ts" - ], - "sample": "terference at lower bit rates; R23 adds FSK PHYs in those same bands. {{frame|Frame" - }, - { - "stem": "PSDU", - "count": 1, - "files": [ - "src/lib/data/protocols/zigbee.ts" - ], - "sample": "me|Frames}} are bounded at **127 octets PSDU** with a **16-bit {{checksum|FCS}}**. T" - }, - { - "stem": "CSMA-CA", - "count": 1, - "files": [ - "src/lib/data/protocols/zigbee.ts" - ], - "sample": "The {{mac-address|MAC}} uses unslotted CSMA-CA in most deployments (FFDs as routers, R" - }, - { - "stem": "R20", - "count": 1, - "files": [ - "src/lib/data/protocols/zigbee.ts" - ], - "sample": "mesh {{routing-table|routing}}** (since R20, 2007). Every mains-powered router main" - }, - { - "stem": "TI", - "count": 1, - "files": [ - "src/lib/data/protocols/zigbee.ts" - ], - "sample": "t, dresden elektronik ConBee II, or any TI CC2652 stick β€” the radio is abstracted" - }, - { - "stem": "MMO-128", - "count": 1, - "files": [ - "src/lib/data/protocols/zigbee.ts" - ], - "sample": "urve25519|Curve25519}} with {{aes|AES}}-MMO-128 (kills the *ZigBeeAlliance09* default-k" - }, - { - "stem": "IR", - "count": 1, - "files": [ - "src/lib/data/protocols/zigbee.ts" - ], - "sample": "]], Power-over-Ethernet, {{usb|USB}}-C, IR blaster, **8 GB encrypted local storage" - }, - { - "stem": "BOM", - "count": 1, - "files": [ - "src/lib/data/protocols/zigbee.ts" - ], - "sample": "a Bluetooth Low Energy radio, reducing BOM cost for cheaper {{matter|Matter}}-brid" - }, - { - "stem": "ZLL", - "count": 1, - "files": [ - "src/lib/data/protocols/zigbee.ts" - ], - "sample": "sy that nudged Signify back to standard ZLL compatibility. IKEA remains an active {" - }, - { - "stem": "ROAM", - "count": 1, - "files": [ - "src/lib/data/protocols/zigbee.ts" - ], - "sample": "ns covering Atrius, nLight, nLight AIR, ROAM, SensorSwitch, Synergy, and XPoint Wire" - }, - { - "stem": "GPL", - "count": 1, - "files": [ - "src/lib/data/protocols/zigbee.ts" - ], - "sample": "s from 568 vendors', text: \"A single GPL-licensed Node.js project β€” maintained p" - }, - { - "stem": "NV", - "count": 1, - "files": [ - "src/lib/data/protocols/zigbee.ts" - ], - "sample": "ke regular backups of the coordinator's NV (zigbee2mqtt writes `coordinator_backup" - }, - { - "stem": "UPS", - "count": 1, - "files": [ - "src/lib/data/protocols/zigbee.ts" - ], - "sample": "cally); **(b)** keep the Coordinator on UPS or PoE; **(c)** use a {{usb|USB}} exten" - }, - { - "stem": "SSD", - "count": 1, - "files": [ - "src/lib/data/protocols/zigbee.ts" - ], - "sample": "gle away from {{usb|USB}} 3.0 ports and SSDs, which emit 2.4 GHz noise; **(d)** cons" - }, - { - "stem": "EFR32", - "count": 1, - "files": [ - "src/lib/data/protocols/zigbee.ts" - ], - "sample": "child-table size on a typical CC2652 / EFR32 firmware is **32**; the Sonoff ZBDongle" - } - ], - "concept": [ - { - "stem": "API", - "suggestedId": "api", - "count": 32, - "files": [ - "src/lib/data/book/parts/web-api.ts", - "src/lib/data/category-deep-dives.ts", - "src/lib/data/category-stories/web-api.ts", - "src/lib/data/comparison/pairs.ts", - "src/lib/data/diagram-definitions.ts", - "src/lib/data/journeys.ts", - "src/lib/data/protocols/graphql.ts", - "src/lib/data/protocols/oauth2.ts", - "src/lib/data/protocols/rest.ts", - "src/lib/data/protocols/tcp.ts" - ] - }, - { - "stem": "NAT", - "suggestedId": "nat", - "count": 13, - "files": [ - "src/lib/data/book/parts/patterns-failures.ts", - "src/lib/data/comparison/pairs.ts", - "src/lib/data/journeys.ts", - "src/lib/data/protocols/nat-traversal.ts" - ] - }, - { - "stem": "URL", - "suggestedId": "url", - "count": 11, - "files": [ - "src/lib/data/category-stories/web-api.ts", - "src/lib/data/comparison/pairs.ts", - "src/lib/data/diagram-definitions.ts", - "src/lib/data/journeys.ts", - "src/lib/data/protocols/dash.ts", - "src/lib/data/protocols/hls.ts", - "src/lib/data/protocols/nat-traversal.ts", - "src/lib/data/protocols/tls.ts" - ] - }, - { - "stem": "RFC", - "suggestedId": "rfc-doc", - "count": 10, - "files": [ - "src/lib/data/book/parts/how-to-learn-more.ts", - "src/lib/data/category-stories/utilities.ts", - "src/lib/data/protocols/nat-traversal.ts", - "src/lib/data/protocols/ospf.ts" - ] - }, - { - "stem": "CDN", - "suggestedId": "cdn-acr", - "count": 8, - "files": [ - "src/lib/data/category-stories/realtime-av.ts", - "src/lib/data/comparison/pairs.ts", - "src/lib/data/journeys.ts", - "src/lib/data/protocols/hls.ts", - "src/lib/data/protocols/quic.ts", - "src/lib/data/protocols/tls.ts" - ] - }, - { - "stem": "LSA", - "suggestedId": "lsa", - "count": 6, - "files": [ - "src/lib/data/protocols/ospf.ts" - ] - }, - { - "stem": "IMP", - "suggestedId": "imp", - "count": 4, - "files": [ - "src/lib/data/book/parts/story-of-the-internet.ts", - "src/lib/data/concept-foundations.ts", - "src/lib/data/outages.ts" - ] - }, - { - "stem": "AP", - "suggestedId": "ap-access-point", - "count": 4, - "files": [ - "src/lib/data/category-deep-dives.ts", - "src/lib/data/protocols/bluetooth.ts", - "src/lib/data/protocols/mdns-dns-sd.ts", - "src/lib/data/protocols/uwb.ts" - ] - }, - { - "stem": "MAC", - "suggestedId": "mac-media", - "count": 4, - "files": [ - "src/lib/data/comparison/pairs.ts", - "src/lib/data/journeys.ts", - "src/lib/data/protocols/ethernet.ts" - ] - }, - { - "stem": "ISP", - "suggestedId": "isp", - "count": 3, - "files": [ - "src/lib/data/diagram-definitions.ts", - "src/lib/data/journeys.ts", - "src/lib/data/outages.ts" - ] - }, - { - "stem": "ACK", - "suggestedId": "ack", - "count": 3, - "files": [ - "src/lib/data/outages.ts", - "src/lib/data/protocols/coap.ts", - "src/lib/data/protocols/tcp.ts" - ] - }, - { - "stem": "OEM", - "suggestedId": "oem", - "count": 3, - "files": [ - "src/lib/data/protocols/nfc.ts", - "src/lib/data/protocols/uwb.ts" - ] - }, - { - "stem": "CLAT", - "suggestedId": "clat-acr", - "count": 2, - "files": [ - "src/lib/data/book/parts/frontier.ts" - ] - }, - { - "stem": "GPU", - "suggestedId": "gpu", - "count": 2, - "files": [ - "src/lib/data/book/parts/frontier.ts" - ] - }, - { - "stem": "ASK", - "suggestedId": "ask-modulation", - "count": 2, - "files": [ - "src/lib/data/book/parts/wireless.ts", - "src/lib/data/protocols/nfc.ts" - ] - }, - { - "stem": "POP", - "suggestedId": "pop-acr", - "count": 2, - "files": [ - "src/lib/data/category-stories/utilities.ts", - "src/lib/data/protocols/bgp.ts" - ] - }, - { - "stem": "LAN", - "suggestedId": "lan-acr", - "count": 2, - "files": [ - "src/lib/data/comparison/pairs.ts", - "src/lib/data/journeys.ts" - ] - }, - { - "stem": "TLD", - "suggestedId": "tld", - "count": 2, - "files": [ - "src/lib/data/diagram-definitions.ts" - ] - }, - { - "stem": "URI", - "suggestedId": "uri", - "count": 2, - "files": [ - "src/lib/data/journeys.ts", - "src/lib/data/protocols/coap.ts" - ] - }, - { - "stem": "SELECT", - "suggestedId": "imap-select", - "count": 2, - "files": [ - "src/lib/data/journeys.ts", - "src/lib/data/protocols/nfc.ts" - ] - }, - { - "stem": "CPU", - "suggestedId": "cpu", - "count": 2, - "files": [ - "src/lib/data/outages.ts" - ] - }, - { - "stem": "KEM", - "suggestedId": "kem-acr", - "count": 2, - "files": [ - "src/lib/data/protocols/ipsec.ts" - ] - }, - { - "stem": "KDC", - "suggestedId": "kerberos-kdc", - "count": 2, - "files": [ - "src/lib/data/protocols/kerberos.ts" - ] - }, - { - "stem": "ID", - "suggestedId": "id-identifier", - "count": 2, - "files": [ - "src/lib/data/protocols/mdns-dns-sd.ts", - "src/lib/data/protocols/wireguard.ts" - ] - }, - { - "stem": "SSID", - "suggestedId": "ssid", - "count": 2, - "files": [ - "src/lib/data/protocols/mdns-dns-sd.ts", - "src/lib/data/protocols/wifi.ts" - ] - }, - { - "stem": "MRZ", - "suggestedId": "mrz", - "count": 2, - "files": [ - "src/lib/data/protocols/nfc.ts" - ] - }, - { - "stem": "DR", - "suggestedId": "ospf-dr", - "count": 2, - "files": [ - "src/lib/data/protocols/ospf.ts" - ] - }, - { - "stem": "FTM", - "suggestedId": "ftm", - "count": 2, - "files": [ - "src/lib/data/protocols/uwb.ts" - ] - }, - { - "stem": "PHY", - "suggestedId": "phy", - "count": 2, - "files": [ - "src/lib/data/protocols/zigbee.ts" - ] - }, - { - "stem": "ISN", - "suggestedId": "isn", - "count": 1, - "files": [ - "src/lib/data/book/parts/famous-outages.ts" - ] - }, - { - "stem": "X25519MLKEM768", - "suggestedId": "pq-ciphersuite", - "count": 1, - "files": [ - "src/lib/data/book/parts/frontier.ts" - ] - }, - { - "stem": "ROA", - "suggestedId": "roa", - "count": 1, - "files": [ - "src/lib/data/book/parts/frontier.ts" - ] - }, - { - "stem": "MED", - "suggestedId": "med", - "count": 1, - "files": [ - "src/lib/data/book/parts/layer-2-3.ts" - ] - }, - { - "stem": "SFU", - "suggestedId": "sfu", - "count": 1, - "files": [ - "src/lib/data/book/parts/realtime-av.ts" - ] - }, - { - "stem": "WAN", - "suggestedId": "wan-acr", - "count": 1, - "files": [ - "src/lib/data/book/parts/transport.ts" - ] - }, - { - "stem": "SCP", - "suggestedId": "scp-copy", - "count": 1, - "files": [ - "src/lib/data/book/parts/utilities-security.ts" - ] - }, - { - "stem": "CVE", - "suggestedId": "cve", - "count": 1, - "files": [ - "src/lib/data/book/parts/web-api.ts" - ] - }, - { - "stem": "VLAN", - "suggestedId": "vlan", - "count": 1, - "files": [ - "src/lib/data/category-deep-dives.ts" - ] - }, - { - "stem": "UI", - "suggestedId": "ui", - "count": 1, - "files": [ - "src/lib/data/journeys.ts" - ] - }, - { - "stem": "LLM", - "suggestedId": "llm", - "count": 1, - "files": [ - "src/lib/data/journeys.ts" - ] - }, - { - "stem": "KEEPALIVE", - "suggestedId": "bgp-keepalive", - "count": 1, - "files": [ - "src/lib/data/protocols/bgp.ts" - ] - }, - { - "stem": "UPDATE", - "suggestedId": "bgp-update", - "count": 1, - "files": [ - "src/lib/data/protocols/bgp.ts" - ] - }, - { - "stem": "UUID", - "suggestedId": "uuid", - "count": 1, - "files": [ - "src/lib/data/protocols/bluetooth.ts" - ] - }, - { - "stem": "DC", - "suggestedId": "dc-domain-controller", - "count": 1, - "files": [ - "src/lib/data/protocols/kerberos.ts" - ] - }, - { - "stem": "SPN", - "suggestedId": "spn", - "count": 1, - "files": [ - "src/lib/data/protocols/kerberos.ts" - ] - }, - { - "stem": "APDU", - "suggestedId": "apdu", - "count": 1, - "files": [ - "src/lib/data/protocols/nfc.ts" - ] - }, - { - "stem": "LSDB", - "suggestedId": "lsdb", - "count": 1, - "files": [ - "src/lib/data/protocols/ospf.ts" - ] - }, - { - "stem": "SRLG", - "suggestedId": "srlg", - "count": 1, - "files": [ - "src/lib/data/protocols/ospf.ts" - ] - }, - { - "stem": "TLV", - "suggestedId": "tlv", - "count": 1, - "files": [ - "src/lib/data/protocols/ospf.ts" - ] - }, - { - "stem": "NIC", - "suggestedId": "nic", - "count": 1, - "files": [ - "src/lib/data/protocols/quic.ts" - ] - }, - { - "stem": "BLE", - "suggestedId": "ble", - "count": 1, - "files": [ - "src/lib/data/protocols/uwb.ts" - ] - }, - { - "stem": "U2", - "suggestedId": "u2-chip", - "count": 1, - "files": [ - "src/lib/data/protocols/uwb.ts" - ] - }, - { - "stem": "U1", - "suggestedId": "u1-chip", - "count": 1, - "files": [ - "src/lib/data/protocols/uwb.ts" - ] - }, - { - "stem": "FFD", - "suggestedId": "ffd", - "count": 1, - "files": [ - "src/lib/data/protocols/zigbee.ts" - ] - }, - { - "stem": "RFD", - "suggestedId": "rfd", - "count": 1, - "files": [ - "src/lib/data/protocols/zigbee.ts" - ] - } - ], - "protocol": [ - { - "stem": "UWB", - "suggestedId": "uwb", - "count": 74 - }, - { - "stem": "NFC", - "suggestedId": "nfc", - "count": 37 - }, - { - "stem": "HTTPS", - "suggestedId": "http1", - "count": 19 - }, - { - "stem": "IP", - "suggestedId": "ip", - "count": 9 - }, - { - "stem": "UDP", - "suggestedId": "udp", - "count": 2 - }, - { - "stem": "QUIC", - "suggestedId": "quic", - "count": 2 - }, - { - "stem": "OAUTH2", - "suggestedId": "oauth2", - "count": 1 - } - ] -} \ No newline at end of file + "unknown": [ + { + "stem": "FF", + "count": 12, + "files": ["src/lib/data/journeys.ts", "src/lib/data/protocols/arp.ts"], + "sample": "to the {{broadcast|broadcast}} address (FF:FF:FF:FF:FF:FF) asking \"Who has 192.168" + }, + { + "stem": "BMW", + "count": 9, + "files": [ + "src/lib/data/book/parts/wireless.ts", + "src/lib/data/diagram-definitions.ts", + "src/lib/data/protocols/nfc.ts", + "src/lib/data/protocols/uwb.ts" + ], + "sample": "t bootstraps {{matter|Matter}}, unlocks BMWs, and broadcasts public hearing-loops ac" + }, + { + "stem": "R23", + "count": 9, + "files": [ + "src/lib/data/book/parts/wireless.ts", + "src/lib/data/journeys.ts", + "src/lib/data/protocols/zigbee.ts" + ], + "sample": "zigbee|IEEE 802.15.4 mesh]], Zigbee PRO R23 ({{dynamic-link-key|Dynamic Link Key}}," + }, + { + "stem": "AIP", + "count": 6, + "files": ["src/lib/data/journeys.ts", "src/lib/data/protocols/nfc.ts"], + "sample": "After GET PROCESSING OPTIONS (returning AIP+{{afl|AFL}}) and {{read-record|READ REC" + }, + { + "stem": "GB", + "count": 6, + "files": [ + "src/lib/data/protocols/ipsec.ts", + "src/lib/data/protocols/nat-traversal.ts", + "src/lib/data/protocols/tcp.ts", + "src/lib/data/protocols/zigbee.ts" + ], + "sample": "-byte lifetime (default ~8 hours / ~100 GB). Before either limit is hit, peers run" + }, + { + "stem": "Q1", + "count": 5, + "files": [ + "src/lib/data/book/parts/transport.ts", + "src/lib/data/book/parts/web-api.ts", + "src/lib/data/protocols/uwb.ts", + "src/lib/data/protocols/zigbee.ts" + ], + "sample": "he in-kernel push', text: 'As of Q1 2026, [[quic|QUIC]] carries roughly **2" + }, + { + "stem": "OV", + "count": 5, + "files": ["src/lib/data/book/parts/wireless.ts", "src/lib/data/protocols/nfc.ts"], + "sample": "to seconds of cloning time. **The Dutch OV-chipkaart kept shipping affected cards" + }, + { + "stem": "M3", + "count": 5, + "files": ["src/lib/data/book/parts/wireless.ts", "src/lib/data/protocols/zigbee.ts"], + "sample": "atter}} devices* (Hue Bridge, Aqara Hub M3) translate {{matter|Matter}} operations" + }, + { + "stem": "II", + "count": 4, + "files": [ + "src/lib/data/book/parts/layer-2-3.ts", + "src/lib/data/category-stories/network-foundations.ts", + "src/lib/data/concept-foundations.ts", + "src/lib/data/protocols/zigbee.ts" + ], + "sample": "'The **[[ethernet|Ethernet]] Type II frame format** β€” six bytes of destinati" + }, + { + "stem": "F1", + "count": 4, + "files": [ + "src/lib/data/book/parts/utilities-security.ts", + "src/lib/data/protocols/cellular.ts", + "src/lib/data/protocols/ipsec.ts", + "src/lib/data/protocols/ntp.ts" + ], + "sample": "caption: '**{{nist|NIST}}-F1**, the caesium fountain atomic clock th" + }, + { + "stem": "SPEKE", + "count": 4, + "files": ["src/lib/data/journeys.ts", "src/lib/data/protocols/zigbee.ts"], + "sample": "amic-link-key|Dynamic Link Key}}** with SPEKE-over-{{curve25519|Curve25519}} removes" + }, + { + "stem": "MAI", + "count": 4, + "files": ["src/lib/data/outages.ts"], + "sample": "the upstream took it.\", mistake: \"MAI Network Services ({{autonomous-system|A" + }, + { + "stem": "PCCW", + "count": 4, + "files": ["src/lib/data/outages.ts"], + "sample": "ocally. But Pakistan Telecom's upstream PCCW ({{autonomous-system|AS}} 3491) had no" + }, + { + "stem": "IKEA", + "count": 4, + "files": ["src/lib/data/protocols/mdns-dns-sd.ts", "src/lib/data/protocols/zigbee.ts"], + "sample": "azon, Samsung, Aqara, Eve, Philips Hue, IKEA, Schlage, Yale, and dozens more.' }" + }, + { + "stem": "MUST", + "count": 3, + "files": ["src/lib/data/book/parts/layer-2-3.ts", "src/lib/data/protocols/kerberos.ts"], + "sample": "t of [[ip|IP]].\"** Every [[ip|IP]] host MUST answer Echo Requests by spec. Dropping" + }, + { + "stem": "RS-232", + "count": 3, + "files": ["src/lib/data/book/parts/wireless.ts", "src/lib/data/category-stories/wireless.ts"], + "sample": "pposed to be the wire that replaced the RS-232 cable to a mobile-phone headset. Thirty" + }, + { + "stem": "S1", + "count": 3, + "files": [ + "src/lib/data/book/parts/wireless.ts", + "src/lib/data/protocols/cellular.ts", + "src/lib/data/protocols/ipsec.ts" + ], + "sample": "ss network}} and the core (N2/N3 in 5G, S1 in {{lte|LTE}}) is wrapped in [[ipsec|I" + }, + { + "stem": "CONNECTED", + "count": 3, + "files": [ + "src/lib/data/book/parts/wireless.ts", + "src/lib/data/protocols/cellular.ts", + "src/lib/data/protocols/stomp.ts" + ], + "sample": "connection state machine β€” \\`RRC_IDLE β†’ CONNECTED β†’ INACTIVE\\` for 5G β€” and **{{nas|NAS}}" + }, + { + "stem": "ET", + "count": 3, + "files": ["src/lib/data/book/parts/wireless.ts", "src/lib/data/protocols/uwb.ts"], + "sample": "text: 'On **22 February 2024 at 03:30 ET**, AT&T Mobility customers across the U" + }, + { + "stem": "AST", + "count": 3, + "files": ["src/lib/data/category-stories/wireless.ts", "src/lib/data/protocols/cellular.ts"], + "sample": "}}\\'s Globalstar partnership and AT&T's AST SpaceMobile follow similar patterns. Re" + }, + { + "stem": "UDP/5353", + "count": 3, + "files": ["src/lib/data/diagram-definitions.ts", "src/lib/data/protocols/mdns-dns-sd.ts"], + "sample": "-local {{multicast|multicast}} group on UDP/5353, with a probe/announce/respond/goodbye" + }, + { + "stem": "RX", + "count": 3, + "files": ["src/lib/data/journeys.ts"], + "sample": "n. The car (multiple anchors typically) RX-timestamps at t2, delays by `T_reply1`" + }, + { + "stem": "PARTNER.COM", + "count": 3, + "files": ["src/lib/data/protocols/kerberos.ts"], + "sample": "XAMPLE.COM wants to access a service in PARTNER.COM, her {{kerberos-kdc|KDC}} issues a **re" + }, + { + "stem": "PR", + "count": 3, + "files": [ + "src/lib/data/protocols/mdns-dns-sd.ts", + "src/lib/data/protocols/ospf.ts", + "src/lib/data/protocols/uwb.ts" + ], + "sample": "ded-clients DoS in 0.9-rc2 was fixed in PR #808.', source: { url: 'https://" + }, + { + "stem": "NIO", + "count": 3, + "files": ["src/lib/data/protocols/nfc.ts", "src/lib/data/protocols/uwb.ts"], + "sample": "lone, including the first Chinese OEMs (NIO, XPENG, Geely group brands). Devices mu" + }, + { + "stem": "XPENG", + "count": 3, + "files": ["src/lib/data/protocols/nfc.ts", "src/lib/data/protocols/uwb.ts"], + "sample": "including the first Chinese OEMs (NIO, XPENG, Geely group brands). Devices must supp" + }, + { + "stem": "T2", + "count": 3, + "files": ["src/lib/data/protocols/ntp.ts", "src/lib/data/protocols/uwb.ts"], + "sample": "Server records when the packet arrives (T2) and when it sends the reply (T3). Both" + }, + { + "stem": "SIZE", + "count": 2, + "files": ["src/lib/data/book/parts/async-iot.ts", "src/lib/data/journeys.ts"], + "sample": "he sentinel and uses an authoritative \\`SIZE\\` field. [[amqp|AMQP]] itself adds no a" + }, + { + "stem": "GA", + "count": 2, + "files": ["src/lib/data/book/parts/async-iot.ts"], + "sample": "protocol', text: '**RabbitMQ 4.0 GA (18 September 2024)** made [[amqp|AMQP]" + }, + { + "stem": "KIP-1150", + "count": 2, + "files": ["src/lib/data/book/parts/async-iot.ts"], + "sample": "ess Topics β€” KIP-1150', text: '**KIP-1150 \"Diskless Topics\"** was accepted by the" + }, + { + "stem": "S3", + "count": 2, + "files": ["src/lib/data/book/parts/async-iot.ts"], + "sample": "less / Bufstream architecture that uses S3 as primary storage. Brokers become {{st" + }, + { + "stem": "MD", + "count": 2, + "files": ["src/lib/data/book/parts/frontier.ts"], + "sample": "lorado Springs, Philadelphia, Rockville MD, San Francisco), with {{apple|Apple}}," + }, + { + "stem": "VSX", + "count": 2, + "files": [ + "src/lib/data/book/parts/realtime-av.ts", + "src/lib/data/category-stories/realtime-av.ts" + ], + "sample": "', caption: 'A **Polycom VSX 7000** video-conferencing system β€” the" + }, + { + "stem": "IIS", + "count": 2, + "files": ["src/lib/data/book/parts/realtime-av.ts", "src/lib/data/protocols/http3.ts"], + "sample": "which was created in 1995 by Fraunhofer IIS for **WinPlay3** and popularised by **N" + }, + { + "stem": "TV", + "count": 2, + "files": ["src/lib/data/book/parts/realtime-av.ts", "src/lib/data/protocols/mdns-dns-sd.ts"], + "sample": "y Netflix stream, every {{apple|Apple}} TV {{broadcast|broadcast}} β€” still starts" + }, + { + "stem": "EXT-X-PRELOAD-HINT", + "count": 2, + "files": ["src/lib/data/book/parts/realtime-av.ts", "src/lib/data/protocols/hls.ts"], + "sample": "ttp2|HTTP/2]] push requirement with **\\`EXT-X-PRELOAD-HINT\\`** β€” a simpler, {{cdn|CDN}}-friendly h" + }, + { + "stem": "UCLA", + "count": 2, + "files": [ + "src/lib/data/book/parts/story-of-the-internet.ts", + "src/lib/data/category-stories/transport.ts" + ], + "sample": "-node network that became the internet. UCLA, SRI, UCSB, and Utah; one {{imp|IMP}} p" + }, + { + "stem": "SRI", + "count": 2, + "files": [ + "src/lib/data/book/parts/story-of-the-internet.ts", + "src/lib/data/category-stories/transport.ts" + ], + "sample": "network that became the internet. UCLA, SRI, UCSB, and Utah; one {{imp|IMP}} per si" + }, + { + "stem": "ISI", + "count": 2, + "files": [ + "src/lib/data/book/parts/story-of-the-internet.ts", + "src/lib/data/concept-foundations.ts" + ], + "sample": "'[[pioneer:jon-postel|Jon Postel]] at ISI. He edited [[rfc:791|RFC 791]] ([[ip|IP" + }, + { + "stem": "L7", + "count": 2, + "files": [ + "src/lib/data/book/parts/story-of-the-internet.ts", + "src/lib/data/book/parts/web-api.ts" + ], + "sample": "n the registry. The first genuinely new L7 protocol since [[websockets|WebSockets]" + }, + { + "stem": "WS", + "count": 2, + "files": [ + "src/lib/data/book/parts/utilities-security.ts", + "src/lib/data/comparison/pairs.ts" + ], + "sample": "dern protocol history. His core line: *\"WS-\\* bad\"* β€” shorthand among {{ietf|IETF}" + }, + { + "stem": "INACTIVE", + "count": 2, + "files": ["src/lib/data/book/parts/wireless.ts", "src/lib/data/protocols/cellular.ts"], + "sample": "tate machine β€” \\`RRC_IDLE β†’ CONNECTED β†’ INACTIVE\\` for 5G β€” and **{{nas|NAS}}** carries" + }, + { + "stem": "AMPS", + "count": 2, + "files": ["src/lib/data/book/parts/wireless.ts", "src/lib/data/protocols/cellular.ts"], + "sample": "[cellular|cellular]]** β€” from 1G analog AMPS / TACS / NMT in the early 1980s through" + }, + { + "stem": "NFC-A", + "count": 2, + "files": ["src/lib/data/book/parts/wireless.ts", "src/lib/data/protocols/nfc.ts"], + "sample": "e flavours on the air', text: '**NFC-A** ({{iso|ISO}} 14443-A): {{pcd|PCD}}β†’{{" + }, + { + "stem": "OOK", + "count": 2, + "files": ["src/lib/data/book/parts/wireless.ts", "src/lib/data/protocols/nfc.ts"], + "sample": "ed-Miller; {{picc|PICC}}β†’{{pcd|PCD}} is OOK Manchester on the 847.5 kHz subcarrier." + }, + { + "stem": "NFC-B", + "count": 2, + "files": ["src/lib/data/book/parts/wireless.ts", "src/lib/data/protocols/nfc.ts"], + "sample": "Base rate 106 kbit/s, scaling to 848. **NFC-B** ({{iso|ISO}} 14443-B): {{pcd|PCD}}β†’{{" + }, + { + "stem": "NRZ-L", + "count": 2, + "files": ["src/lib/data/book/parts/wireless.ts", "src/lib/data/protocols/nfc.ts"], + "sample": "cc|PICC}} is 10% {{ask-modulation|ASK}} NRZ-L; {{picc|PICC}}β†’{{pcd|PCD}} is {{bpsk|BP" + }, + { + "stem": "JIS", + "count": 2, + "files": ["src/lib/data/book/parts/wireless.ts", "src/lib/data/protocols/nfc.ts"], + "sample": "assports. **{{nfc-f|NFC-F}}** (FeliCa / JIS X 6319-4): 212/424 kbit/s Manchester-co" + }, + { + "stem": "PASMO", + "count": 2, + "files": ["src/lib/data/book/parts/wireless.ts", "src/lib/data/protocols/nfc.ts"], + "sample": "nt in Japan {{transit|transit}} (Suica, PASMO) and Hong Kong (Octopus). **{{nfc-v|NFC" + }, + { + "stem": "ETH", + "count": 2, + "files": ["src/lib/data/book/parts/wireless.ts", "src/lib/data/protocols/uwb.ts"], + "sample": "u, Giovanni Camurati, and colleagues at ETH ZΓΌrich published **Ghost Peak** β€” an at" + }, + { + "stem": "D03", + "count": 2, + "files": ["src/lib/data/book/parts/wireless.ts", "src/lib/data/protocols/uwb.ts"], + "sample": "eee-802-15-4|IEEE}} 802.15.4ab** (Draft D03 September 2025, ratification expected e" + }, + { + "stem": "ABI", + "count": 2, + "files": ["src/lib/data/book/parts/wireless.ts", "src/lib/data/protocols/uwb.ts"], + "sample": "eness of [[uwb|UWB]] into one purchase. ABI projects [[uwb|UWB]] phone penetration" + }, + { + "stem": "PRO", + "count": 2, + "files": ["src/lib/data/book/parts/wireless.ts", "src/lib/data/journeys.ts"], + "sample": "'[[zigbee|IEEE 802.15.4 mesh]], Zigbee PRO R23 ({{dynamic-link-key|Dynamic Link Ke" + }, + { + "stem": "RTSP", + "count": 2, + "files": ["src/lib/data/book/parts/wireless.ts", "src/lib/data/protocols/zigbee.ts"], + "sample": "mber 2025)**, with camera streaming via RTSP, removing the last category that previo" + }, + { + "stem": "OASIS", + "count": 2, + "files": [ + "src/lib/data/category-stories/async-iot.ts", + "src/lib/data/diagram-definitions.ts" + ], + "sample": "ce the protocol and shepherd it through OASIS standardization.', imagePath:" + }, + { + "stem": "CEO", + "count": 2, + "files": ["src/lib/data/category-stories/async-iot.ts", "src/lib/data/protocols/amqp.ts"], + "sample": "oyed [[amqp|AMQP]] broker. Later became CEO of Weaveworks, bringing messaging patte" + }, + { + "stem": "TIBCO", + "count": 2, + "files": [ + "src/lib/data/category-stories/async-iot.ts", + "src/lib/data/protocols/mdns-dns-sd.ts" + ], + "sample": "rneyed from Wall Street trading floors (TIBCO) to IoT sensors ([[mqtt|MQTT]]) to clou" + }, + { + "stem": "DIX", + "count": 2, + "files": ["src/lib/data/category-stories/network-foundations.ts"], + "sample": "c|Xerox PARC}} in 1973, co-authored the DIX [[ethernet|Ethernet]] standard (1980)," + }, + { + "stem": "DEC", + "count": 2, + "files": ["src/lib/data/category-stories/utilities.ts", "src/lib/data/protocols/icmp.ts"], + "sample": "t infrastructure', caption: \"The DEC PDP-11 β€” machines like these ran early" + }, + { + "stem": "BIND", + "count": 2, + "files": ["src/lib/data/category-stories/utilities.ts", "src/lib/data/protocols/dns.ts"], + "sample": "urity', contribution: 'Wrote BIND, the most widely deployed [[dns|DNS]] s" + }, + { + "stem": "HTML5", + "count": 2, + "files": ["src/lib/data/category-stories/web-api.ts", "src/lib/data/protocols/sse.ts"], + "sample": "sse|Server-Sent Events]] as part of the HTML5 specification, enabling simple server-t" + }, + { + "stem": "CMOS", + "count": 2, + "files": ["src/lib/data/category-stories/wireless.ts", "src/lib/data/protocols/uwb.ts"], + "sample": "sh engineer who owned the analog RF and CMOS implementation work that paired with Ja" + }, + { + "stem": "IC", + "count": 2, + "files": ["src/lib/data/category-stories/wireless.ts", "src/lib/data/protocols/nfc.ts"], + "sample": "Jaap Haartsen\\'s digital baseband. The IC-level decisions that made [[bluetooth|B" + }, + { + "stem": "FR2", + "count": 2, + "files": ["src/lib/data/category-stories/wireless.ts", "src/lib/data/protocols/cellular.ts"], + "sample": "flexible numerology, {{mmwave|mmWave}} (FR2) support, network slicing. First commer" + }, + { + "stem": "RTT", + "count": 2, + "files": ["src/lib/data/category-stories/wireless.ts", "src/lib/data/protocols/quic.ts"], + "sample": "Adopted 3 September 2024. Phase-based + RTT distance measurement on a new {{le-audi" + }, + { + "stem": "H1/H2", + "count": 2, + "files": ["src/lib/data/category-stories/wireless.ts", "src/lib/data/protocols/bluetooth.ts"], + "sample": "m|Broadcom}}, Qualcomm, {{apple|Apple}} H1/H2) uses **time-division arbitration** at" + }, + { + "stem": "SMTPS", + "count": 2, + "files": ["src/lib/data/comparison/pairs.ts"], + "sample": "ication protocols transparently (HTTPS, SMTPS); [[ssh|SSH]] provides an encrypted cha" + }, + { + "stem": "RTMPS", + "count": 2, + "files": ["src/lib/data/comparison/pairs.ts", "src/lib/data/diagram-definitions.ts"], + "sample": "aps [[rtmp|RTMP]] connections to create RTMPS, encrypting live stream ingest traffic" + }, + { + "stem": "MB", + "count": 2, + "files": ["src/lib/data/concept-foundations.ts", "src/lib/data/protocols/ospf.ts"], + "sample": "r packet is **1460 bytes**. Sending a 1 MB file means roughly 685 packets. {{path-" + }, + { + "stem": "NSFNET", + "count": 2, + "files": ["src/lib/data/concept-foundations.ts", "src/lib/data/outages.ts"], + "sample": "1986 the same architecture was carrying NSFNET traffic across the country β€” and the bu" + }, + { + "stem": "UC", + "count": 2, + "files": ["src/lib/data/concept-foundations.ts", "src/lib/data/outages.ts"], + "sample": "ffers between Lawrence Berkeley Lab and UC Berkeley, three hops apart, were where" + }, + { + "stem": "RACK-TLP", + "count": 2, + "files": ["src/lib/data/concept-foundations.ts", "src/lib/data/outages.ts"], + "sample": "ubic|CUBIC}}, {{bbr|BBR}}, {{l4s|L4S}}, RACK-TLP β€” are each refinements of the same cons" + }, + { + "stem": "HPC", + "count": 2, + "files": ["src/lib/data/concept-foundations.ts", "src/lib/data/frontier.ts"], + "sample": "rnet|Ethernet]]+[[ip|IP]] for {{ai|AI}}/HPC scale-out: {{connectionless|connectionl" + }, + { + "stem": "CBC", + "count": 2, + "files": ["src/lib/data/concept-foundations.ts", "src/lib/data/protocols/tls.ts"], + "sample": "}} key {{exchange|exchange}}, and every CBC-mode cipher β€” keeping only {{chacha20-p" + }, + { + "stem": "BEAST", + "count": 2, + "files": ["src/lib/data/concept-foundations.ts", "src/lib/data/protocols/tls.ts"], + "sample": "been weaponised in a published attack (BEAST, CRIME, BREACH, Lucky 13, FREAK, Logjam" + }, + { + "stem": "CRIME", + "count": 2, + "files": ["src/lib/data/concept-foundations.ts", "src/lib/data/protocols/tls.ts"], + "sample": "eaponised in a published attack (BEAST, CRIME, BREACH, Lucky 13, FREAK, Logjam, ROBOT" + }, + { + "stem": "BREACH", + "count": 2, + "files": ["src/lib/data/concept-foundations.ts", "src/lib/data/protocols/tls.ts"], + "sample": "ed in a published attack (BEAST, CRIME, BREACH, Lucky 13, FREAK, Logjam, ROBOT, …). [[" + }, + { + "stem": "FREAK", + "count": 2, + "files": ["src/lib/data/concept-foundations.ts", "src/lib/data/protocols/tls.ts"], + "sample": "attack (BEAST, CRIME, BREACH, Lucky 13, FREAK, Logjam, ROBOT, …). [[tls|TLS]] 1.3 als" + }, + { + "stem": "ROBOT", + "count": 2, + "files": ["src/lib/data/concept-foundations.ts", "src/lib/data/protocols/tls.ts"], + "sample": "CRIME, BREACH, Lucky 13, FREAK, Logjam, ROBOT, …). [[tls|TLS]] 1.3 also reduced the {" + }, + { + "stem": "OBS", + "count": 2, + "files": ["src/lib/data/diagram-definitions.ts", "src/lib/data/journeys.ts"], + "sample": "eam ingest}}** protocol β€” your encoder (OBS, Wirecast) pushes a long-lived [[tcp|TC" + }, + { + "stem": "STD", + "count": 2, + "files": ["src/lib/data/diagram-definitions.ts", "src/lib/data/protocols/ospf.ts"], + "sample": "tra|Dijkstra]] ([[rfc:2328|RFC 2328]] / STD 54).', steps: { 0: '{{ospf-hello|H" + }, + { + "stem": "CTR", + "count": 2, + "files": ["src/lib/data/diagram-definitions.ts", "src/lib/data/protocols/cellular.ts"], + "sample": "t}}; **{{sts|STS}}** is the {{aes|AES}}-CTR-generated pulse pattern that makes the" + }, + { + "stem": "WHERE", + "count": 2, + "files": ["src/lib/data/journeys.ts"], + "sample": "transition: 'The browser now knows WHERE the server lives β€” but packets on the i" + }, + { + "stem": "FSCI", + "count": 2, + "files": ["src/lib/data/journeys.ts", "src/lib/data/protocols/nfc.ts"], + "sample": "TS}}** declaring its frame-size budget (FSCI=5 = 64 bytes max). Both ends now know h" + }, + { + "stem": "FCI", + "count": 2, + "files": ["src/lib/data/journeys.ts", "src/lib/data/protocols/nfc.ts"], + "sample": "} `2PAY.SYS.DDF01`). The eSE returns an FCI Template listing every payment {{aid|AI" + }, + { + "stem": "PROCESSING", + "count": 2, + "files": ["src/lib/data/journeys.ts", "src/lib/data/protocols/nfc.ts"], + "sample": "gram', description: \"After GET PROCESSING OPTIONS (returning AIP+{{afl|AFL}}) and" + }, + { + "stem": "CDOL1", + "count": 2, + "files": ["src/lib/data/journeys.ts", "src/lib/data/protocols/nfc.ts"], + "sample": "nerate-ac|GENERATE AC}} with the filled CDOL1 data. The eSE composes the inputs (amou" + }, + { + "stem": "QR", + "count": 2, + "files": ["src/lib/data/journeys.ts", "src/lib/data/protocols/nfc.ts"], + "sample": "e}} (printed on the Hue bulb's box as a QR code), that link key is unique and an e" + }, + { + "stem": "CVSS", + "count": 2, + "files": ["src/lib/data/outages.ts", "src/lib/data/protocols/uwb.ts"], + "sample": "on the public internet were vulnerable. CVSS 7.5 (high). Operators scrambled to patc" + }, + { + "stem": "CID", + "count": 2, + "files": ["src/lib/data/protocols/bluetooth.ts"], + "sample": "att-mtu|ATT}}) lives on {{l2cap|L2CAP}} CID 0x0004 and provides read/write/notify/i" + }, + { + "stem": "LTK", + "count": 2, + "files": ["src/lib/data/protocols/bluetooth.ts"], + "sample": "Curve P-256 to derive a Long-Term Key (LTK); the link is then {{encryption|encrypt" + }, + { + "stem": "CIS", + "count": 2, + "files": ["src/lib/data/protocols/bluetooth.ts"], + "sample": "nels** β€” Connected Isochronous Streams (CIS) for {{unicast|unicast}} earbuds/hearin" + }, + { + "stem": "LL", + "count": 2, + "files": ["src/lib/data/protocols/bluetooth.ts"], + "sample": "scription: 'Two devices in a normal LL connection schedule **{{channel-soundin" + }, + { + "stem": "NCC", + "count": 2, + "files": ["src/lib/data/protocols/bluetooth.ts", "src/lib/data/protocols/uwb.ts"], + "sample": "s the protocol-level answer to the 2022 NCC Group {{ble|BLE}} relay attack that ope" + }, + { + "stem": "GFSK", + "count": 2, + "files": ["src/lib/data/protocols/bluetooth.ts"], + "sample": "s over the air**. Different modulation (GFSK + DPSK for Classic, GFSK only for {{ble" + }, + { + "stem": "PB", + "count": 2, + "files": ["src/lib/data/protocols/cellular.ts"], + "sample": "}} by Q3 2025; the network averages 6.5 PB/day. The first proof that a hyperscale" + }, + { + "stem": "NR", + "count": 2, + "files": ["src/lib/data/protocols/cellular.ts"], + "sample": "ecified in Release 17 (2022), the first NR-{{ntn|NTN}} deployments shipped in late" + }, + { + "stem": "USA", + "count": 2, + "files": ["src/lib/data/protocols/cellular.ts"], + "sample": "numbering plan: 234/235 = UK, 310–316 = USA, 460 = China, 405 = India, 440–441 = Ja" + }, + { + "stem": "X2", + "count": 2, + "files": ["src/lib/data/protocols/cellular.ts", "src/lib/data/protocols/ipsec.ts"], + "sample": "*mandate** [[ipsec|IPsec]] on every S1, X2, N2, N3, Xn, F1, and E1 interface. Forg" + }, + { + "stem": "N2", + "count": 2, + "files": ["src/lib/data/protocols/cellular.ts", "src/lib/data/protocols/ipsec.ts"], + "sample": "date** [[ipsec|IPsec]] on every S1, X2, N2, N3, Xn, F1, and E1 interface. Forgetti" + }, + { + "stem": "N3", + "count": 2, + "files": ["src/lib/data/protocols/cellular.ts", "src/lib/data/protocols/ipsec.ts"], + "sample": "** [[ipsec|IPsec]] on every S1, X2, N2, N3, Xn, F1, and E1 interface. Forgetting t" + }, + { + "stem": "E1", + "count": 2, + "files": ["src/lib/data/protocols/cellular.ts", "src/lib/data/protocols/ipsec.ts"], + "sample": "]] on every S1, X2, N2, N3, Xn, F1, and E1 interface. Forgetting this in a private" + }, + { + "stem": "SOA", + "count": 2, + "files": ["src/lib/data/protocols/dns.ts"], + "sample": "pex must also have {{ns-record|NS}} and SOA records. Some [[dns|DNS]] providers off" + }, + { + "stem": "NXDOMAIN", + "count": 2, + "files": ["src/lib/data/protocols/dns.ts"], + "sample": "g can hurt', text: 'Resolvers cache NXDOMAIN responses based on the SOA minimum fiel" + }, + { + "stem": "UDP/4500", + "count": 2, + "files": ["src/lib/data/protocols/ipsec.ts"], + "sample": "{{security-association|SA}} switches to UDP/4500 {{encapsulation|encapsulation}}. Two me" + }, + { + "stem": "MOBIKE", + "count": 2, + "files": ["src/lib/data/protocols/ipsec.ts"], + "sample": "me routers don\\'t corrupt the packet. **MOBIKE** ([[rfc:4555|RFC 4555]]) lets a roadwa" + }, + { + "stem": "SKU", + "count": 2, + "files": ["src/lib/data/protocols/ipsec.ts", "src/lib/data/protocols/mdns-dns-sd.ts"], + "sample": "(10 Gbps aggregate on the AZ-redundant SKU), {{gcp|GCP}} Cloud {{vpn|VPN}}, OCI Si" + }, + { + "stem": "AS-REQ", + "count": 2, + "files": ["src/lib/data/protocols/kerberos.ts"], + "sample": "description: 'Client sends an **AS-REQ** to the {{kerberos-kdc|KDC}}\\'s Authen" + }, + { + "stem": "TGS-REP", + "count": 2, + "files": ["src/lib/data/protocols/kerberos.ts"], + "sample": "ion key for Alice↔web1, and returns a **TGS-REP** with a **service ticket** encrypted u" + }, + { + "stem": "GSS", + "count": 2, + "files": ["src/lib/data/protocols/kerberos.ts"], + "sample": "y speak Kerberos directly. They speak **GSS-{{api|API}}** (Generic Security Service" + }, + { + "stem": "SPNEGO", + "count": 2, + "files": ["src/lib/data/protocols/kerberos.ts"], + "sample": "ntext\\` / \\`gss_accept_sec_context\\`. **SPNEGO** ([[rfc:4178|RFC 4178]]) is the protoc" + }, + { + "stem": "PKINIT", + "count": 2, + "files": ["src/lib/data/protocols/kerberos.ts"], + "sample": "gust 2025 release. Headline features: **PKINIT {{ecdh|ECDH}}/EC certs** (smart-card au" + }, + { + "stem": "DES", + "count": 2, + "files": ["src/lib/data/protocols/kerberos.ts"], + "sample": "IT}}-internal for years because it used DES β€” and DES exports required State Depart" + }, + { + "stem": "FF02", + "count": 2, + "files": ["src/lib/data/protocols/mdns-dns-sd.ts", "src/lib/data/protocols/ospf.ts"], + "sample": "s* on \\`224.0.0.251\\` ([[ipv6|IPv6]]: \\`FF02::FB\\`). Two flag bits get repurposed: t" + }, + { + "stem": "SD", + "count": 2, + "files": ["src/lib/data/protocols/mdns-dns-sd.ts", "src/lib/data/protocols/ospf.ts"], + "sample": "cription: \"A {{dns-resolution|DNS}}-SD client looking for printers sends a {{p" + }, + { + "stem": "SRP", + "count": 2, + "files": ["src/lib/data/protocols/mdns-dns-sd.ts"], + "sample": "col) published', description: '**SRP** ({{rfc-doc|RFC}} 9665, Lemon + [[pion" + }, + { + "stem": "LLMNR", + "count": 2, + "files": ["src/lib/data/protocols/mdns-dns-sd.ts"], + "sample": "th [[mdns-dns-sd|mDNS]] **enabled** and LLMNR **disabled** in the security baseline." + }, + { + "stem": "IGMP", + "count": 2, + "files": ["src/lib/data/protocols/mdns-dns-sd.ts"], + "sample": "e (often 6 Mbps); managed switches with IGMP snooping enabled drop frames whose list" + }, + { + "stem": "WLC", + "count": 2, + "files": ["src/lib/data/protocols/mdns-dns-sd.ts", "src/lib/data/protocols/nfc.ts"], + "sample": "-dns-sd|mDNS]] gateway ({{cisco|Cisco}} WLC `mdns-sd` profile, Aruba AirGroup, Aero" + }, + { + "stem": "DERP", + "count": 2, + "files": ["src/lib/data/protocols/nat-traversal.ts", "src/lib/data/protocols/wireguard.ts"], + "sample": "path between peers; their proprietary **DERP** relays absorb the rest as a {{turn|TU" + }, + { + "stem": "CTO", + "count": 2, + "files": ["src/lib/data/protocols/nat-traversal.ts", "src/lib/data/protocols/rtp.ts"], + "sample": "turn|TURN}}, and {{ice|ICE}}. Currently CTO + Head of {{ai|AI}} at Five9.' } ]," + }, + { + "stem": "T2T", + "count": 2, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "ate frame size (FSCI) and timing (FWI). T2T cards skip {{rats|RATS}} and go straigh" + }, + { + "stem": "TC", + "count": 2, + "files": ["src/lib/data/protocols/nfc.ts", "src/lib/data/protocols/zigbee.ts"], + "sample": "} β€” either an {{arqc|ARQC}} (online) or TC (offline). The cryptogram is signed in" + }, + { + "stem": "TNF", + "count": 2, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "ifier|ID}} Length present), and a 3-bit TNF (Type Name Format: 0=Empty, 1=Well-Know" + }, + { + "stem": "IEC", + "count": 2, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "{ndef|NDEF}} was formally adopted as an IEC standard in **March 2026** alongside NF" + }, + { + "stem": "HID", + "count": 2, + "files": ["src/lib/data/protocols/nfc.ts", "src/lib/data/protocols/uwb.ts"], + "sample": "}}, Allegion, Aqara, {{google|Google}}, HID, Kastle, Kwikset, Last Lock, Nordic, Nu" + }, + { + "stem": "EV3", + "count": 2, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "Plus in **2011**, DESFire EV2 in 2016, EV3 in the early 2020s. The Classic Crypto1" + }, + { + "stem": "GM", + "count": 2, + "files": ["src/lib/data/protocols/nfc.ts", "src/lib/data/protocols/uwb.ts"], + "sample": "is, Audi (new in 2025), Volvo, Porsche, GM, Ford, plus a wave of Chinese OEMs (NIO" + }, + { + "stem": "DDA/CDA", + "count": 2, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "eturns an AIP byte that signals whether DDA/CDA is supported. A common custom-{{hce|HCE" + }, + { + "stem": "RRP", + "count": 2, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "gram|EMV}} **Relay Resistance Protocol (RRP)** in Kernel 2 v2.6+ binds round-trip t" + }, + { + "stem": "T1", + "count": 2, + "files": ["src/lib/data/protocols/ntp.ts"], + "sample": "DP]] packet with its current timestamp (T1). The packet is tiny β€” 48 bytes.' }," + }, + { + "stem": "T3", + "count": 2, + "files": ["src/lib/data/protocols/ntp.ts"], + "sample": "rives (T2) and when it sends the reply (T3). Both timestamps are included in the r" + }, + { + "stem": "T4", + "count": 2, + "files": ["src/lib/data/protocols/ntp.ts"], + "sample": "ient records when the response arrives (T4). Now it has four timestamps: T1 (sent)" + }, + { + "stem": "NBMA", + "count": 2, + "files": ["src/lib/data/protocols/ospf.ts"], + "sample": "default 10 s on point-to-point, 30 s on NBMA). Hellos carry the router\\'s {{id-ident" + }, + { + "stem": "HPRF", + "count": 2, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "Hz** in the default 802.15.4z mode or **HPRF 124.8 / 249.6 MHz** in higher-power mod" + }, + { + "stem": "RTLS", + "count": 2, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "f arrival β€” used for warehouse/hospital RTLS where anchors are wired. **AoA / PDoA:*" + }, + { + "stem": "EN", + "count": 2, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "Hz** across 3.1–10.6 GHz. {{etsi|ETSI}} EN 302 065 in Europe is similar with stric" + }, + { + "stem": "AR", + "count": 2, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "ision Finding, BMW Digital Key, and the AR experiences in {{apple|Apple}} Vision P" + }, + { + "stem": "T2024", + "count": 2, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "1-chip|U1}}'s 16 nm), internal codename T2024, part number 339M00298. **1.5Γ— longer P" + }, + { + "stem": "U400", + "count": 2, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "amsung wallets. First products: **Aqara U400** (first smart lock with UWB; {{aliro|A" + }, + { + "stem": "S21", + "count": 2, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "|Apple}} UWB tracker. Works with Galaxy S21+ / S21 Ultra / Note 20 Ultra / S22/S23/" + }, + { + "stem": "DW3000", + "count": 2, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "upports only Channel 5; everything from DW3000 / {{nxp|NXP}} SR150 / {{apple|Apple}} {" + }, + { + "stem": "SR150", + "count": 2, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "5; everything from DW3000 / {{nxp|NXP}} SR150 / {{apple|Apple}} {{u1-chip|U1}} onward" + }, + { + "stem": "NLOS", + "count": 2, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "ns = 30 cm, but in **non-line-of-sight (NLOS)** conditions through walls/people/meta" + }, + { + "stem": "ACL", + "count": 2, + "files": ["src/lib/data/protocols/wireguard.ts"], + "sample": "r which destination prefix) **and** the ACL (inbound: only accept packets from this" + }, + { + "stem": "TSPU", + "count": 2, + "files": ["src/lib/data/protocols/wireguard.ts"], + "sample": "mimicry', description: \"Russia's TSPU boxes learned to fingerprint and drop s" + }, + { + "stem": "S1/S2", + "count": 2, + "files": ["src/lib/data/protocols/wireguard.ts"], + "sample": "H4 ranges instead of fixed 1–4), random S1/S2 padding. AWG 2.0 adds optional QUIC/{{d" + }, + { + "stem": "WARP", + "count": 2, + "files": ["src/lib/data/protocols/wireguard.ts"], + "sample": "are}}'s consumer {{vpn|VPN}} (1.1.1.1 + WARP app) runs on **BoringTun**, {{cloudflar" + }, + { + "stem": "OTA", + "count": 2, + "files": ["src/lib/data/protocols/zigbee.ts"], + "sample": "ntrol = 0x0008, Color Control = 0x0300, OTA Upgrade = 0x0019), and an **APSCounter*" + }, + { + "stem": "FOSS", + "count": 2, + "files": ["src/lib/data/protocols/zigbee.ts"], + "sample": "and *no* microphone or camera. For the FOSS path the answer is **zigbee2mqtt** by K" + }, + { + "stem": "PSU", + "count": 2, + "files": ["src/lib/data/protocols/zigbee.ts"], + "sample": "ble Zigbee β€” the router's switched-mode PSU emits broadband 2.4 GHz noise.\" } ]," + }, + { + "stem": "CC2652", + "count": 2, + "files": ["src/lib/data/protocols/zigbee.ts"], + "sample": "dresden elektronik ConBee II, or any TI CC2652 stick β€” the radio is abstracted behind" + }, + { + "stem": "SES", + "count": 2, + "files": ["src/lib/data/protocols/zigbee.ts"], + "sample": "3 December 2024** VusionGroup (formerly SES-imagotag) announced acceleration of dig" + }, + { + "stem": "ESL", + "count": 2, + "files": ["src/lib/data/protocols/zigbee.ts"], + "sample": "500 stores. Vusion shipped 350 million ESLs in 2023 alone; the EdgeSense platform r" + }, + { + "stem": "AIR", + "count": 2, + "files": ["src/lib/data/protocols/zigbee.ts"], + "sample": "', description: \"Acuity's nLight AIR and Atrius lines are the dominant Zigbe" + }, + { + "stem": "SUN", + "count": 2, + "files": ["src/lib/data/protocols/zigbee.ts"], + "sample": "and later directed standards at the Wi-SUN Alliance. Almost every low-power 802.15" + }, + { + "stem": "VSAT", + "count": 1, + "files": ["src/lib/data/book/parts/async-iot.ts"], + "sample": "llips 66 oil pipelines over a brand-new VSAT satellite link. The 2-byte fixed header" + }, + { + "stem": "PINGREQ", + "count": 1, + "files": ["src/lib/data/book/parts/async-iot.ts"], + "sample": "ixed header**, smallest control packet (PINGREQ) is 2 bytes total. Designed in 1999 by" + }, + { + "stem": "JMS", + "count": 1, + "files": ["src/lib/data/book/parts/async-iot.ts"], + "sample": "sia is removed. RabbitMQ 4.3 also added JMS-style queues with {{sql|SQL}} message s" + }, + { + "stem": "NETSCOUT", + "count": 1, + "files": ["src/lib/data/book/parts/async-iot.ts"], + "sample": "{ kind: 'pull-quote', text: 'NETSCOUT\\'s January 2019 scan found 388,344 publ" + }, + { + "stem": "QLC", + "count": 1, + "files": ["src/lib/data/book/parts/async-iot.ts"], + "sample": "ey were Chinese smartphones running the QLC Chain {{peer-to-peer|peer-to-peer}} cry" + }, + { + "stem": "EDHOC", + "count": 1, + "files": ["src/lib/data/book/parts/async-iot.ts"], + "sample": "messages, ~100 bytes', text: '**EDHOC ([[rfc:9000|RFC 9528]], March 2024)** β€”" + }, + { + "stem": "DH", + "count": 1, + "files": ["src/lib/data/book/parts/async-iot.ts"], + "sample": "sages totalling ~100 bytes** for static-DH credentials, vs **~700+ bytes for a {{d" + }, + { + "stem": "OSCORE", + "count": 1, + "files": ["src/lib/data/book/parts/async-iot.ts"], + "sample": "years* of additional life. Companion: **OSCORE ([[rfc:8613|RFC 8613]])** wraps the [[c" + }, + { + "stem": "DNA", + "count": 1, + "files": ["src/lib/data/book/parts/famous-outages.ts"], + "sample": "g router carries the same architectural DNA: a control plane that builds the {{rout" + }, + { + "stem": "PREF64", + "count": 1, + "files": ["src/lib/data/book/parts/frontier.ts"], + "sample": "clients \"skip [[ip|IPv4]] entirely,\" **PREF64 in Router Advertisements ([[rfc:8781|RF" + }, + { + "stem": "RIR", + "count": 1, + "files": ["src/lib/data/book/parts/frontier.ts"], + "sample": "{{roa|ROA}} set. Lesson: enforce 2FA on RIR portals.', attribution: 'Author'" + }, + { + "stem": "OTC", + "count": 1, + "files": ["src/lib/data/book/parts/frontier.ts"], + "sample": "fc:9234|RFC 9234]] ([[bgp|BGP]] Roles + OTC) ate its lunch. The lesson: a security" + }, + { + "stem": "MW", + "count": 1, + "files": ["src/lib/data/book/parts/frontier.ts"], + "sample": "nal pluggable optics would consume ~180 MW of power for the optics alone. That is" + }, + { + "stem": "X1600", + "count": 1, + "files": ["src/lib/data/book/parts/frontier.ts"], + "sample": "AI}} workloads. **{{spectrum|Spectrum}}-X1600 (102.4 Tbps)** is expected 2H 2026.'" + }, + { + "stem": "GB200", + "count": 1, + "files": ["src/lib/data/book/parts/frontier.ts"], + "sample": "ption: 'The **{{nvidia|NVIDIA}} GB200 NVL72** Blackwell-architecture rack on" + }, + { + "stem": "NVL72", + "count": 1, + "files": ["src/lib/data/book/parts/frontier.ts"], + "sample": "'The **{{nvidia|NVIDIA}} GB200 NVL72** Blackwell-architecture rack on displa" + }, + { + "stem": "COMPUTEX", + "count": 1, + "files": ["src/lib/data/book/parts/frontier.ts"], + "sample": "ackwell-architecture rack on display at COMPUTEX 2024 β€” the kind of {{ai|AI}}-training e" + }, + { + "stem": "WECA", + "count": 1, + "files": ["src/lib/data/book/parts/frontier.ts"], + "sample": "as a tagline retrofitted briefly by the WECA board and dropped. The yin-yang logo is" + }, + { + "stem": "OET", + "count": 1, + "files": ["src/lib/data/book/parts/frontier.ts"], + "sample": "on **23 February 2024** the {{fcc|FCC}} OET approved **seven {{afc|AFC}} system ope" + }, + { + "stem": "RUCKUS", + "count": 1, + "files": ["src/lib/data/book/parts/frontier.ts"], + "sample": "d [[wifi|Wi-Fi]] 7 {{access-point|AP}} (RUCKUS R770) was certified 16 April 2024.** Bu" + }, + { + "stem": "R770", + "count": 1, + "files": ["src/lib/data/book/parts/frontier.ts"], + "sample": "i|Wi-Fi]] 7 {{access-point|AP}} (RUCKUS R770) was certified 16 April 2024.** But on" + }, + { + "stem": "SINR", + "count": 1, + "files": ["src/lib/data/book/parts/frontier.ts"], + "sample": "squeezes for **+25% throughput at given SINR, βˆ’25% 95th-percentile {{latency|latency" + }, + { + "stem": "MPDU", + "count": 1, + "files": ["src/lib/data/book/parts/frontier.ts"], + "sample": "th-percentile {{latency|latency}}, βˆ’25% MPDU loss across {{bss-coloring|BSS}} transi" + }, + { + "stem": "CS168", + "count": 1, + "files": ["src/lib/data/book/parts/how-to-learn-more.ts"], + "sample": "P]] stack), {{mit|MIT}} 6.829, Berkeley CS168.', slots: [ { kind: 'prose'" + }, + { + "stem": "PARC", + "count": 1, + "files": ["src/lib/data/book/parts/layer-2-3.ts"], + "sample": "still runs the original spec. The 1973 PARC sketch and a 2025 Ultra [[ethernet|Ethe" + }, + { + "stem": "KU", + "count": 1, + "files": ["src/lib/data/book/parts/layer-2-3.ts"], + "sample": ", text: '**Mathy Vanhoef and the KU Leuven team have broken [[wifi|Wi-Fi]]" + }, + { + "stem": "DCP", + "count": 1, + "files": ["src/lib/data/book/parts/layer-2-3.ts"], + "sample": "rote [[rfc:826|RFC 826]] from address \\`DCP@{{mit|MIT}}-MC\\` in November 1982. **ST" + }, + { + "stem": "MC", + "count": 1, + "files": ["src/lib/data/book/parts/layer-2-3.ts"], + "sample": "FC 826]] from address \\`DCP@{{mit|MIT}}-MC\\` in November 1982. **STD 37 has never" + }, + { + "stem": "L2", + "count": 1, + "files": ["src/lib/data/book/parts/layer-2-3.ts"], + "sample": "xt: '[[arp|ARP]] relies entirely on the L2 {{checksum|frame check sequence}} β€” no" + }, + { + "stem": "BRL", + "count": 1, + "files": ["src/lib/data/book/parts/layer-2-3.ts"], + "sample": "rote {{ping|ping}} in a single night at BRL Aberdeen in December 1983, named after" + }, + { + "stem": "TOPS-20", + "count": 1, + "files": ["src/lib/data/book/parts/layer-2-3.ts"], + "sample": "st server was named *Jeeves* and ran on TOPS-20.', credit: 'Image: Wikimedia Com" + }, + { + "stem": "KEX", + "count": 1, + "files": ["src/lib/data/book/parts/patterns-failures.ts"], + "sample": "llo|ServerHello}}/Finished, [[ssh|SSH]] KEX, [[mqtt|MQTT]] {{mqtt-connect|CONNECT}}" + }, + { + "stem": "CONNACK", + "count": 1, + "files": ["src/lib/data/book/parts/patterns-failures.ts"], + "sample": "[[mqtt|MQTT]] {{mqtt-connect|CONNECT}}/CONNACK, [[sctp|SCTP]]\\'s four-way {{cookie|Coo" + }, + { + "stem": "DAVE", + "count": 1, + "files": ["src/lib/data/book/parts/realtime-av.ts"], + "sample": "on a whiteboard in 2018.\" Discord\\'s **DAVE protocol** (deployed 1 March 2026) laye" + }, + { + "stem": "MLS", + "count": 1, + "files": ["src/lib/data/book/parts/realtime-av.ts"], + "sample": "otocol** (deployed 1 March 2026) layers MLS keys + SFrame on top of [[rtp|RTP]]/{{s" + }, + { + "stem": "E2EE", + "count": 1, + "files": ["src/lib/data/book/parts/realtime-av.ts"], + "sample": "on top of [[rtp|RTP]]/{{srtp|SRTP}} for E2EE voice across **2.5 million concurrent u" + }, + { + "stem": "M120", + "count": 1, + "files": ["src/lib/data/book/parts/realtime-av.ts"], + "sample": "AV1}} hardware encode shipped in Chrome M120 (Dec 2023). Firefox 125 added {{av1|AV1" + }, + { + "stem": "EME", + "count": 1, + "files": ["src/lib/data/book/parts/realtime-av.ts"], + "sample": "ec 2023). Firefox 125 added {{av1|AV1}}+EME in April 2024. But the royalty-free cla" + }, + { + "stem": "CMAF", + "count": 1, + "files": ["src/lib/data/book/parts/realtime-av.ts"], + "sample": "ate ladders of small .ts (or now .mp4 / CMAF) segments; a {{cdn|CDN}} serves them ov" + }, + { + "stem": "ISDN", + "count": 1, + "files": ["src/lib/data/book/parts/realtime-av.ts"], + "sample": "four wholesale rewrites later (analog β†’ ISDN β†’ [[rtp|RTP]]/H.323 β†’ [[webrtc|WebRTC]]" + }, + { + "stem": "PRNET/SATNET", + "count": 1, + "files": ["src/lib/data/book/parts/story-of-the-internet.ts"], + "sample": "et|ARPANET}}), and unreliable wireless (PRNET/SATNET) each forced different design pressures" + }, + { + "stem": "UCSB", + "count": 1, + "files": ["src/lib/data/book/parts/story-of-the-internet.ts"], + "sample": "rk that became the internet. UCLA, SRI, UCSB, and Utah; one {{imp|IMP}} per site.'," + }, + { + "stem": "EDGE", + "count": 1, + "files": ["src/lib/data/book/parts/story-of-the-internet.ts"], + "sample": "d on 29 June 2007 with [[wifi|Wi-Fi]] + EDGE; the App Store followed in July 2008; {" + }, + { + "stem": "GIGA", + "count": 1, + "files": ["src/lib/data/book/parts/transport.ts"], + "sample": "ple}} {{os|OS}} services, Korea Telecom GIGA Path, some specialised enterprise WANs)" + }, + { + "stem": "CA", + "count": 1, + "files": ["src/lib/data/book/parts/utilities-security.ts"], + "sample": "te-authority|CA}} signs an intermediate CA, which signs the end-entity {{certifica" + }, + { + "stem": "SIGALRM", + "count": 1, + "files": ["src/lib/data/book/parts/utilities-security.ts"], + "sample": "{{linux|Linux}}. Signal-handler race: \\`SIGALRM\\` handler calls \\`syslog()\\` (not async" + }, + { + "stem": "UNIX", + "count": 1, + "files": ["src/lib/data/book/parts/utilities-security.ts"], + "sample": "er than {{arpanet|ARPANET}}, older than UNIX, older than every other timestamp stand" + }, + { + "stem": "Y2036", + "count": 1, + "files": ["src/lib/data/book/parts/utilities-security.ts"], + "sample": "it and will need fixes before 2036. The Y2036 work has been quietly underway since 20" + }, + { + "stem": "SNDMSG", + "count": 1, + "files": ["src/lib/data/book/parts/utilities-security.ts"], + "sample": "picked the **@** sign in 1971 modifying SNDMSG. [[pioneer:jon-postel|Jon Postel]] publ" + }, + { + "stem": "DCE", + "count": 1, + "files": ["src/lib/data/book/parts/web-api.ts"], + "sample": "a 40-year lineage of Sun {{rpc|RPC}} / DCE / CORBA / Thrift. The client *stub* ser" + }, + { + "stem": "CORBA", + "count": 1, + "files": ["src/lib/data/book/parts/web-api.ts"], + "sample": "year lineage of Sun {{rpc|RPC}} / DCE / CORBA / Thrift. The client *stub* serialises" + }, + { + "stem": "NTIA", + "count": 1, + "files": ["src/lib/data/book/parts/wireless.ts"], + "sample": "d States Frequency Allocations Chart**, NTIA. Every coloured stripe is a *service* β€”" + }, + { + "stem": "WPA", + "count": 1, + "files": ["src/lib/data/book/parts/wireless.ts"], + "sample": "|OOB}} key or the Wi-Fi {{ssid|SSID}} + WPA key in an {{ndef|NDEF}} record. **[[zig" + }, + { + "stem": "MIMO", + "count": 1, + "files": ["src/lib/data/book/parts/wireless.ts"], + "sample": "11]] β€” {{csma-ca|CSMA/CA}} in practice, MIMO β†’ {{ofdma|OFDMA}} β†’ {{mlo|MLO}}, and th" + }, + { + "stem": "DIFS", + "count": 1, + "files": ["src/lib/data/book/parts/wireless.ts"], + "sample": "of the {{airtime|airtime}} is spent on DIFS gaps, {{ack|ACK}} frames, beacons, and" + }, + { + "stem": "NB", + "count": 1, + "files": ["src/lib/data/book/parts/wireless.ts"], + "sample": "volte|VoLTE}} / [[wifi|Wi-Fi]] calling, NB-IoT / {{lte|LTE}}-M, satellite {{direct" + }, + { + "stem": "N2/N3", + "count": 1, + "files": ["src/lib/data/book/parts/wireless.ts"], + "sample": "an|radio access network}} and the core (N2/N3 in 5G, S1 in {{lte|LTE}}) is wrapped in" + }, + { + "stem": "IOS", + "count": 1, + "files": ["src/lib/data/book/parts/wireless.ts"], + "sample": "teffen]]\\'s strongSwan, {{cisco|Cisco}} IOS, and Juniper {{junos|Junos}} run more [" + }, + { + "stem": "TACS", + "count": 1, + "files": ["src/lib/data/book/parts/wireless.ts"], + "sample": "ar|cellular]]** β€” from 1G analog AMPS / TACS / NMT in the early 1980s through 2G {{g" + }, + { + "stem": "NMT", + "count": 1, + "files": ["src/lib/data/book/parts/wireless.ts"], + "sample": "ular]]** β€” from 1G analog AMPS / TACS / NMT in the early 1980s through 2G {{gsm|GSM" + }, + { + "stem": "IS-95", + "count": 1, + "files": ["src/lib/data/book/parts/wireless.ts"], + "sample": "he early 1980s through 2G {{gsm|GSM}} / IS-95, 3G {{wcdma|WCDMA}} / CDMA2000, 4G {{lt" + }, + { + "stem": "CDMA2000", + "count": 1, + "files": ["src/lib/data/book/parts/wireless.ts"], + "sample": "gsm|GSM}} / IS-95, 3G {{wcdma|WCDMA}} / CDMA2000, 4G {{lte|LTE}}, and {{5g-nr|5G NR}}. E" + }, + { + "stem": "SYS.DDF01", + "count": 1, + "files": ["src/lib/data/book/parts/wireless.ts"], + "sample": "t System Environment {{aid|AID}} \\`2PAY.SYS.DDF01\\` β€” and the card returns an FCI listing" + }, + { + "stem": "A0000000041010", + "count": 1, + "files": ["src/lib/data/book/parts/wireless.ts"], + "sample": "The reader picks one (e.g. Mastercard \\`A0000000041010\\`), SELECTs it, gets back a {{pdol|PDOL" + }, + { + "stem": "TX", + "count": 1, + "files": ["src/lib/data/book/parts/wireless.ts"], + "sample": "*can* be cheated β€” a relay with enough TX power makes a distant device look near." + }, + { + "stem": "PAL", + "count": 1, + "files": ["src/lib/data/book/parts/wireless.ts"], + "sample": "iority), **Priority Access Licensees** (PALs, auctioned in 2020 for ~$4.5B), and **G" + }, + { + "stem": "PMSE", + "count": 1, + "files": ["src/lib/data/book/parts/wireless.ts"], + "sample": "has experimented with similar concepts (PMSE in the UK, {{lsa|LSA}} in some EU pilot" + }, + { + "stem": "PIE", + "count": 1, + "files": ["src/lib/data/category-deep-dives.ts"], + "sample": "{{aqm|Active Queue Management}} (CoDel, PIE, fq_codel) and algorithms like {{bbr|BB" + }, + { + "stem": "SCADA", + "count": 1, + "files": ["src/lib/data/category-stories/async-iot.ts"], + "sample": "on: \"Brought embedded systems and SCADA expertise to [[mqtt|MQTT]]'s design. Co" + }, + { + "stem": "CBOR", + "count": 1, + "files": ["src/lib/data/category-stories/async-iot.ts"], + "sample": "oap|CoAP]] specification and co-created CBOR, the efficient binary {{serialization|s" + }, + { + "stem": "NATS", + "count": 1, + "files": ["src/lib/data/category-stories/async-iot.ts"], + "sample": "o cloud-native microservices ([[amqp]], NATS, [[kafka]]). Today, it's one of the mos" + }, + { + "stem": "P802", + "count": 1, + "files": ["src/lib/data/category-stories/network-foundations.ts"], + "sample": "on 100 G lanes). The 1.6 TbE follow-up (P802.3dj, 200 G/lane) targets July 2026 β€” dr" + }, + { + "stem": "LO", + "count": 1, + "files": ["src/lib/data/category-stories/transport.ts"], + "sample": "two months before the first successful \"LO\" transmission to SRI.', credit: 'Pho" + }, + { + "stem": "PDP-11", + "count": 1, + "files": ["src/lib/data/category-stories/utilities.ts"], + "sample": "frastructure', caption: \"The DEC PDP-11 β€” machines like these ran early [[ntp|N" + }, + { + "stem": "POWER", + "count": 1, + "files": ["src/lib/data/category-stories/web-api.ts"], + "sample": "reads \"This machine is a server. DO NOT POWER IT DOWN!!\"', credit: 'Photo: Coolcae" + }, + { + "stem": "DOWN", + "count": 1, + "files": ["src/lib/data/category-stories/web-api.ts"], + "sample": "is machine is a server. DO NOT POWER IT DOWN!!\"', credit: 'Photo: Coolcaesar / CC" + }, + { + "stem": "AAIF", + "count": 1, + "files": ["src/lib/data/category-stories/web-api.ts"], + "sample": "es to the Agentic {{ai|AI}} Foundation (AAIF) and [[a2a|A2A]] launches as a {{linux|" + }, + { + "stem": "RF", + "count": 1, + "files": ["src/lib/data/category-stories/wireless.ts"], + "sample": "'Swedish engineer who owned the analog RF and CMOS implementation work that paire" + }, + { + "stem": "COMDEX", + "count": 1, + "files": ["src/lib/data/category-stories/wireless.ts"], + "sample": "product (a hands-free headset) ships at COMDEX 1999.', protocolId: 'bluetooth'" + }, + { + "stem": "SC-FDMA", + "count": 1, + "files": ["src/lib/data/category-stories/wireless.ts"], + "sample": "preading codes for an {{ofdma|OFDMA}} + SC-FDMA air interface β€” the clean-sheet radio d" + }, + { + "stem": "IQ", + "count": 1, + "files": ["src/lib/data/comparison/pairs.ts"], + "sample": "ble delivery of presence, messages, and IQ queries.', howTheyWork: 'An [[xmpp" + }, + { + "stem": "AMQPS", + "count": 1, + "files": ["src/lib/data/comparison/pairs.ts"], + "sample": "aps [[amqp|AMQP]] connections to create AMQPS, encrypting all {{broker|message broker" + }, + { + "stem": "MQTTS", + "count": 1, + "files": ["src/lib/data/comparison/pairs.ts"], + "sample": "aps [[mqtt|MQTT]] connections to create MQTTS, encrypting all pub/sub messaging betwe" + }, + { + "stem": "SIPS", + "count": 1, + "files": ["src/lib/data/comparison/pairs.ts"], + "sample": "SIP]] {{signaling|signaling}} to create SIPS, encrypting call setup, authentication," + }, + { + "stem": "WSS", + "count": 1, + "files": ["src/lib/data/comparison/pairs.ts"], + "sample": "ckets|WebSocket]] connections to create WSS (wss://), encrypting the {{full-duplex|" + }, + { + "stem": "M3U8", + "count": 1, + "files": ["src/lib/data/comparison/pairs.ts"], + "sample": "LS]] delivers adaptive video by serving M3U8 playlists and media segments as standar" + }, + { + "stem": "BOSH", + "count": 1, + "files": ["src/lib/data/comparison/pairs.ts"], + "sample": "network without long-polling hacks like BOSH.', howTheyWork: 'The browser opens" + }, + { + "stem": "PROXY", + "count": 1, + "files": ["src/lib/data/concept-foundations.ts"], + "sample": "ess you explicitly forward it via the **PROXY protocol** or an {{header|HTTP header}}" + }, + { + "stem": "ARPA", + "count": 1, + "files": ["src/lib/data/concept-foundations.ts"], + "sample": "down in 1986.', caption: 'The ARPA Network in September 1973, a few dozen" + }, + { + "stem": "DHT", + "count": 1, + "files": ["src/lib/data/concept-foundations.ts"], + "sample": "Torrent uses centralised trackers (or a DHT, which is a decentralised tracker) to b" + }, + { + "stem": "SHA384", + "count": 1, + "files": ["src/lib/data/concept-foundations.ts"], + "sample": "DigiCert [[tls|TLS]] Hybrid {{ecc|ECC}} SHA384 β†’ DigiCert Global Root G3\\`. Only the b" + }, + { + "stem": "G3", + "count": 1, + "files": ["src/lib/data/concept-foundations.ts"], + "sample": "ecc|ECC}} SHA384 β†’ DigiCert Global Root G3\\`. Only the bottom (root) {{certificate" + }, + { + "stem": "SIGTRAN", + "count": 1, + "files": ["src/lib/data/diagram-definitions.ts"], + "sample": "under telecom {{signaling|signaling}} (SIGTRAN) and [[webrtc|WebRTC]] data channels ([" + }, + { + "stem": "WHATWG", + "count": 1, + "files": ["src/lib/data/diagram-definitions.ts"], + "sample": "only need {{server-push|server push}} (WHATWG).', steps: { 0: 'Standard [[http1|" + }, + { + "stem": "OMA", + "count": 1, + "files": ["src/lib/data/diagram-definitions.ts"], + "sample": "App, and the {{matter|Matter}}-adjacent OMA-LwM2M IoT stack. Encrypted via {{startt" + }, + { + "stem": "CQRS", + "count": 1, + "files": ["src/lib/data/diagram-definitions.ts"], + "sample": "tream processing}}, event sourcing, and CQRS. **{{exactly-once-delivery|Exactly-once" + }, + { + "stem": "T1/T2/T3/T4", + "count": 1, + "files": ["src/lib/data/diagram-definitions.ts"], + "sample": "timestamps per {{exchange|exchange}}** (T1/T2/T3/T4) which cancel out network {{latency|lat" + }, + { + "stem": "TGS", + "count": 1, + "files": ["src/lib/data/diagram-definitions.ts"], + "sample": "ey Distribution Center, split into AS + TGS), and Service. Two {{encryption|encrypt" + }, + { + "stem": "SEND", + "count": 1, + "files": ["src/lib/data/journeys.ts"], + "sample": "ONNECT}}, {{mqtt-subscribe|SUBSCRIBE}}, SEND, and {{ack|ACK}} are self-explanatory," + }, + { + "stem": "ERP", + "count": 1, + "files": ["src/lib/data/journeys.ts"], + "sample": "ing queue, maintenance data goes to the ERP integration queue, and raw telemetry go" + }, + { + "stem": "VP8", + "count": 1, + "files": ["src/lib/data/journeys.ts"], + "sample": "round rules: which codecs they support (VP8, H.264, Opus), what transport addresses" + }, + { + "stem": "DANE", + "count": 1, + "files": ["src/lib/data/journeys.ts"], + "sample": "d [[dns|DNS]]-based authentication like DANE which allows domain owners to {{mqtt-pu" + }, + { + "stem": "TVR", + "count": 1, + "files": ["src/lib/data/journeys.ts"], + "sample": "the inputs (amount, currency, country, TVR, {{atc|ATC}}, Unpredictable Number, AIP" + }, + { + "stem": "POS", + "count": 1, + "files": ["src/lib/data/journeys.ts"], + "sample": "description: \"Modern wireless POS terminals (Square, Stripe, Verifone Eng" + }, + { + "stem": "APPROVED", + "count": 1, + "files": ["src/lib/data/journeys.ts"], + "sample": "sufficient balance + no fraud flag = **APPROVED**. The issuer returns an **ARPC** (Auth" + }, + { + "stem": "ARPC", + "count": 1, + "files": ["src/lib/data/journeys.ts"], + "sample": "= **APPROVED**. The issuer returns an **ARPC** (Authorisation Response Cryptogram) o" + }, + { + "stem": "RFRAME", + "count": 1, + "files": ["src/lib/data/journeys.ts"], + "sample": "n: \"The phone transmits a **Poll** RFRAME on [[uwb|UWB]] Channel 9 (7987.2 MHz, 4" + }, + { + "stem": "LQI", + "count": 1, + "files": ["src/lib/data/journeys.ts"], + "sample": "icks the best parent by {{rssi|RSSI}} + LQI. This is the slowest step β€” beacon scan" + }, + { + "stem": "WITHDRAWAL", + "count": 1, + "files": ["src/lib/data/outages.ts"], + "sample": "-system|AS}} 32934 β€” and then a wave of WITHDRAWALs of the [[ip|IPv4]] and [[ipv6|IPv6]] pr" + }, + { + "stem": "SERVFAIL", + "count": 1, + "files": ["src/lib/data/outages.ts"], + "sample": "ike 1.1.1.1 and 8.8.8.8 start returning SERVFAIL for facebook.com. Apps and humans retry" + }, + { + "stem": "NANOG", + "count": 1, + "files": ["src/lib/data/outages.ts"], + "sample": "tion: \"Vince Bono's apology email to NANOG that day is preserved in the archives β€”" + }, + { + "stem": "RIS", + "count": 1, + "files": ["src/lib/data/outages.ts"], + "sample": "ally for hours. {{ripe-ncc|RIPE NCC}}'s RIS data became the canonical post-mortem s" + }, + { + "stem": "LBL", + "count": 1, + "files": ["src/lib/data/outages.ts"], + "sample": "delivery less likely. Throughput on the LBL-to-UCB path collapsed from 32 kbps to 4" + }, + { + "stem": "UCB", + "count": 1, + "files": ["src/lib/data/outages.ts"], + "sample": "y less likely. Throughput on the LBL-to-UCB path collapsed from 32 kbps to 40 bps β€”" + }, + { + "stem": "LBL-UCB", + "count": 1, + "files": ["src/lib/data/outages.ts"], + "sample": "uplicates. Goodput approaches zero. The LBL-UCB path measures 40 bps where it had measu" + }, + { + "stem": "CT", + "count": 1, + "files": ["src/lib/data/outages.ts"], + "sample": "limit damage.\", mistake: \"At 02:42 CT, a network change with an equipment con" + }, + { + "stem": "GSO", + "count": 1, + "files": ["src/lib/data/outages.ts"], + "sample": "ff could be split into more than 65,535 GSO segments. The 16-bit counter overflowed" + }, + { + "stem": "OPEN", + "count": 1, + "files": ["src/lib/data/protocols/bgp.ts"], + "sample": "'Both routers {{exchange|exchange}} OPEN messages containing their {{autonomous-" + }, + { + "stem": "NLRI", + "count": 1, + "files": ["src/lib/data/protocols/bgp.ts"], + "sample": "messages containing reachable prefixes (NLRI) with path attributes: {{as-path|AS_PAT" + }, + { + "stem": "EGP", + "count": 1, + "files": ["src/lib/data/protocols/bgp.ts"], + "sample": "Austin. The previous routing protocol (EGP) was unmanageable. They sketched a repl" + }, + { + "stem": "GTSM", + "count": 1, + "files": ["src/lib/data/protocols/bgp.ts"], + "sample": "tcha', text: 'Some operators enable GTSM (Generalised {{ttl|TTL}} Security Mecha" + }, + { + "stem": "SBC", + "count": 1, + "files": ["src/lib/data/protocols/bluetooth.ts"], + "sample": "he mandatory {{codec|codec}} (replacing SBC and saving ~50% battery vs A2DP). **{{a" + }, + { + "stem": "A2DP", + "count": 1, + "files": ["src/lib/data/protocols/bluetooth.ts"], + "sample": "eplacing SBC and saving ~50% battery vs A2DP). **{{auracast|Auracast}}** is the {{si" + }, + { + "stem": "ISOAL", + "count": 1, + "files": ["src/lib/data/protocols/bluetooth.ts"], + "sample": "privacy against long-term tracking) and ISOAL improvements for {{le-audio|LE Audio}}" + }, + { + "stem": "EURECOM", + "count": 1, + "files": ["src/lib/data/protocols/bluetooth.ts"], + "sample": "mes', text: \"Daniele Antonioli (then EURECOM, now PostDoc-and-faculty) is the lead a" + }, + { + "stem": "DPSK", + "count": 1, + "files": ["src/lib/data/protocols/bluetooth.ts"], + "sample": "the air**. Different modulation (GFSK + DPSK for Classic, GFSK only for {{ble|BLE}}" + }, + { + "stem": "FR1", + "count": 1, + "files": ["src/lib/data/protocols/cellular.ts"], + "sample": "two very different deployment regimes (FR1 sub-6 GHz, FR2 {{mmwave|mmWave}} 24–52" + }, + { + "stem": "LLR", + "count": 1, + "files": ["src/lib/data/protocols/cellular.ts"], + "sample": "ion}}. The receiver stores soft-decoded LLRs from failed transmissions and combines" + }, + { + "stem": "RLC", + "count": 1, + "files": ["src/lib/data/protocols/cellular.ts"], + "sample": "er compression', description: '**RLC** runs in TM (transparent), UM (unackno" + }, + { + "stem": "TM", + "count": 1, + "files": ["src/lib/data/protocols/cellular.ts"], + "sample": "', description: '**RLC** runs in TM (transparent), UM (unacknowledged), or" + }, + { + "stem": "UM", + "count": 1, + "files": ["src/lib/data/protocols/cellular.ts"], + "sample": "'**RLC** runs in TM (transparent), UM (unacknowledged), or AM (acknowledged)" + }, + { + "stem": "AM", + "count": 1, + "files": ["src/lib/data/protocols/cellular.ts"], + "sample": "(transparent), UM (unacknowledged), or AM (acknowledged) mode with 10- or 16-bit" + }, + { + "stem": "PDCP", + "count": 1, + "files": ["src/lib/data/protocols/cellular.ts"], + "sample": "ce numbers}} ({{ts-3gpp|TS}} 38.322). **PDCP** above it ({{ts-3gpp|TS}} 38.323) does" + }, + { + "stem": "ROHC", + "count": 1, + "files": ["src/lib/data/protocols/cellular.ts"], + "sample": "* above it ({{ts-3gpp|TS}} 38.323) does ROHC {{header|header compression}} (squashin" + }, + { + "stem": "USIM", + "count": 1, + "files": ["src/lib/data/protocols/cellular.ts"], + "sample": "hentication vector, and the {{ue|UE}}'s USIM verifies AUTN and computes RES*. After" + }, + { + "stem": "AUTN", + "count": 1, + "files": ["src/lib/data/protocols/cellular.ts"], + "sample": "ctor, and the {{ue|UE}}'s USIM verifies AUTN and computes RES*. After Security Mode" + }, + { + "stem": "RES", + "count": 1, + "files": ["src/lib/data/protocols/cellular.ts"], + "sample": "|UE}}'s USIM verifies AUTN and computes RES*. After Security Mode Command, {{nas|NA" + }, + { + "stem": "PCF", + "count": 1, + "files": ["src/lib/data/protocols/cellular.ts"], + "sample": "{upf|UPF}}, {{ausf|AUSF}}, {{udm|UDM}}, PCF, NRF, NEF, NSSF, AF β€” each is a **netwo" + }, + { + "stem": "NRF", + "count": 1, + "files": ["src/lib/data/protocols/cellular.ts"], + "sample": "UPF}}, {{ausf|AUSF}}, {{udm|UDM}}, PCF, NRF, NEF, NSSF, AF β€” each is a **network fu" + }, + { + "stem": "NEF", + "count": 1, + "files": ["src/lib/data/protocols/cellular.ts"], + "sample": ", {{ausf|AUSF}}, {{udm|UDM}}, PCF, NRF, NEF, NSSF, AF β€” each is a **network functio" + }, + { + "stem": "NSSF", + "count": 1, + "files": ["src/lib/data/protocols/cellular.ts"], + "sample": "usf|AUSF}}, {{udm|UDM}}, PCF, NRF, NEF, NSSF, AF β€” each is a **network function** wi" + }, + { + "stem": "AF", + "count": 1, + "files": ["src/lib/data/protocols/cellular.ts"], + "sample": "SF}}, {{udm|UDM}}, PCF, NRF, NEF, NSSF, AF β€” each is a **network function** with a" + }, + { + "stem": "GPRS", + "count": 1, + "files": ["src/lib/data/protocols/cellular.ts"], + "sample": "|UPF}} travel over **{{gtp-u|GTP-U}}** (GPRS Tunnelling Protocol β€” User plane) on [[" + }, + { + "stem": "ML", + "count": 1, + "files": ["src/lib/data/protocols/cellular.ts"], + "sample": "vanced release. New features: {{ai|AI}}/ML in the air interface (CSI feedback comp" + }, + { + "stem": "CSI", + "count": 1, + "files": ["src/lib/data/protocols/cellular.ts"], + "sample": "res: {{ai|AI}}/ML in the air interface (CSI feedback compression, beam management)," + }, + { + "stem": "SOS", + "count": 1, + "files": ["src/lib/data/protocols/cellular.ts"], + "sample": "{{apple|Apple}}\\'s Globalstar Emergency SOS round out the satellite-{{direct-to-cel" + }, + { + "stem": "Q3", + "count": 1, + "files": ["src/lib/data/protocols/cellular.ts"], + "sample": "use cloud-native {{5g-core|5G core}} by Q3 2025; the network averages 6.5 PB/day." + }, + { + "stem": "NEC", + "count": 1, + "files": ["src/lib/data/protocols/cellular.ts"], + "sample": "land. Multi-vendor mix: Samsung radios, NEC baseband, Wind River cloud platform. Th" + }, + { + "stem": "ARIB", + "count": 1, + "files": ["src/lib/data/protocols/cellular.ts"], + "sample": "partnership of {{etsi|ETSI}} (Europe), ARIB + TTC (Japan), ATIS (North America), CC" + }, + { + "stem": "TTC", + "count": 1, + "files": ["src/lib/data/protocols/cellular.ts"], + "sample": "rship of {{etsi|ETSI}} (Europe), ARIB + TTC (Japan), ATIS (North America), CCSA (Ch" + }, + { + "stem": "ATIS", + "count": 1, + "files": ["src/lib/data/protocols/cellular.ts"], + "sample": "si|ETSI}} (Europe), ARIB + TTC (Japan), ATIS (North America), CCSA (China), TSDSI (I" + }, + { + "stem": "CCSA", + "count": 1, + "files": ["src/lib/data/protocols/cellular.ts"], + "sample": "IB + TTC (Japan), ATIS (North America), CCSA (China), TSDSI (India), TTA (Korea). Ev" + }, + { + "stem": "TSDSI", + "count": 1, + "files": ["src/lib/data/protocols/cellular.ts"], + "sample": "n), ATIS (North America), CCSA (China), TSDSI (India), TTA (Korea). Every cellular ph" + }, + { + "stem": "TTA", + "count": 1, + "files": ["src/lib/data/protocols/cellular.ts"], + "sample": "America), CCSA (China), TSDSI (India), TTA (Korea). Every cellular phone on Earth" + }, + { + "stem": "IMSI", + "count": 1, + "files": ["src/lib/data/protocols/cellular.ts"], + "sample": "obile Country Code at the start of your IMSI is the protocol\\'s private numbering pl" + }, + { + "stem": "MCC/MNC", + "count": 1, + "files": ["src/lib/data/protocols/cellular.ts"], + "sample": "ce. Your roaming bill itemises calls by MCC/MNC pair.' }, { title: \"The CDMA-vs-" + }, + { + "stem": "CTIA", + "count": 1, + "files": ["src/lib/data/protocols/cellular.ts"], + "sample": "tial\", text: 'In January 1989 the US CTIA voted for {{tdma|TDMA}}; later that yea" + }, + { + "stem": "DT", + "count": 1, + "files": ["src/lib/data/protocols/cellular.ts"], + "sample": "USA, Reliance Jio, parts of Verizon and DT), the {{ue|UE}} receives **only an [[ip" + }, + { + "stem": "PLAT", + "count": 1, + "files": ["src/lib/data/protocols/cellular.ts"], + "sample": ") β€” {{clat-acr|CLAT}} on the {{ue|UE}}, PLAT/{{nat64|NAT64}} at the operator. **Pitf" + }, + { + "stem": "N6", + "count": 1, + "files": ["src/lib/data/protocols/cellular.ts"], + "sample": "ode 4 (Frag Needed) messages on the SGi/N6 side. The {{mtu|MTU}} on a {{gtp-u|GTP-" + }, + { + "stem": "EDNS", + "count": 1, + "files": ["src/lib/data/protocols/dns.ts"], + "sample": "byte response. Today the limit is moot (EDNS allows larger responses), but the 13-le" + }, + { + "stem": "ALIAS", + "count": 1, + "files": ["src/lib/data/protocols/dns.ts"], + "sample": "ords. Some [[dns|DNS]] providers offer \"ALIAS\" or \"ANAME\" pseudo-records that work ar" + }, + { + "stem": "ANAME", + "count": 1, + "files": ["src/lib/data/protocols/dns.ts"], + "sample": "[[dns|DNS]] providers offer \"ALIAS\" or \"ANAME\" pseudo-records that work around this;" + }, + { + "stem": "USER", + "count": 1, + "files": ["src/lib/data/protocols/ftp.ts"], + "sample": "o server port 21 and authenticates with USER and PASS commands. This connection stay" + }, + { + "stem": "PASS", + "count": 1, + "files": ["src/lib/data/protocols/ftp.ts"], + "sample": "port 21 and authenticates with USER and PASS commands. This connection stays open fo" + }, + { + "stem": "CWD", + "count": 1, + "files": ["src/lib/data/protocols/ftp.ts"], + "sample": "ient browses the remote filesystem with CWD (change directory), PWD (print working" + }, + { + "stem": "PWD", + "count": 1, + "files": ["src/lib/data/protocols/ftp.ts"], + "sample": "filesystem with CWD (change directory), PWD (print working directory), and LIST (di" + }, + { + "stem": "LIST", + "count": 1, + "files": ["src/lib/data/protocols/ftp.ts"], + "sample": "ry), PWD (print working directory), and LIST (directory listing). All commands are h" + }, + { + "stem": "PASV", + "count": 1, + "files": ["src/lib/data/protocols/ftp.ts"], + "sample": "CP]] connection opens. In passive mode (PASV), the server tells the client which por" + }, + { + "stem": "RETR", + "count": 1, + "files": ["src/lib/data/protocols/ftp.ts"], + "sample": "er', description: 'Client issues RETR (download) or STOR (upload). Data flows" + }, + { + "stem": "STOR", + "count": 1, + "files": ["src/lib/data/protocols/ftp.ts"], + "sample": ": 'Client issues RETR (download) or STOR (upload). Data flows on the data connec" + }, + { + "stem": "SETTINGS", + "count": 1, + "files": ["src/lib/data/protocols/http2.ts"], + "sample": "client and server {{exchange|exchange}} SETTINGS frames establishing max concurrent stre" + }, + { + "stem": "RR", + "count": 1, + "files": ["src/lib/data/protocols/http3.ts"], + "sample": "st. The HTTPS [[dns|DNS]] record (HTTPS RR, [[rfc:9460|RFC 9460]]) closes this gap" + }, + { + "stem": "VT100", + "count": 1, + "files": ["src/lib/data/protocols/icmp.ts"], + "sample": "a DEC PDP-11/70', caption: 'A DEC VT100 terminal β€” the type of terminal where e" + }, + { + "stem": "INBOX", + "count": 1, + "files": ["src/lib/data/protocols/imap.ts"], + "sample": "ription: 'Client selects a mailbox (INBOX, Drafts, Sent, etc.). Server reports me" + }, + { + "stem": "UIDVALIDITY", + "count": 1, + "files": ["src/lib/data/protocols/imap.ts"], + "sample": ", recent messages, available flags, and UIDVALIDITY for cache validation.' }, { titl" + }, + { + "stem": "SEARCH", + "count": 1, + "files": ["src/lib/data/protocols/imap.ts"], + "sample": "tion: 'Client searches server-side (SEARCH FROM \"alice\" SINCE 1-Mar-2024) and modi" + }, + { + "stem": "FROM", + "count": 1, + "files": ["src/lib/data/protocols/imap.ts"], + "sample": "'Client searches server-side (SEARCH FROM \"alice\" SINCE 1-Mar-2024) and modifies" + }, + { + "stem": "SINCE", + "count": 1, + "files": ["src/lib/data/protocols/imap.ts"], + "sample": "arches server-side (SEARCH FROM \"alice\" SINCE 1-Mar-2024) and modifies flags (\\\\Seen," + }, + { + "stem": "SPD", + "count": 1, + "files": ["src/lib/data/protocols/ipsec.ts"], + "sample": "matching the Security Policy Database (SPD) is wrapped in an **{{esp|ESP}} {{heade" + }, + { + "stem": "CRYSTALS", + "count": 1, + "files": ["src/lib/data/protocols/ipsec.ts"], + "sample": "s|FIPS}} 203 β€” the standardised form of CRYSTALS-Kyber. This is the post-quantum {{kem|K" + }, + { + "stem": "KE", + "count": 1, + "files": ["src/lib/data/protocols/ipsec.ts"], + "sample": "ge}} and [[rfc:9370|RFC 9370]] multiple-KE β€” meaning two or more KEMs (e.g. classi" + }, + { + "stem": "TFS", + "count": 1, + "files": ["src/lib/data/protocols/ipsec.ts"], + "sample": "[[rfc:9347|RFC 9347]] {{ip-address|IP}}-TFS (Traffic Flow Security β€” fixed-size agg" + }, + { + "stem": "WG", + "count": 1, + "files": ["src/lib/data/protocols/ipsec.ts"], + "sample": ". Fifth revision of the [[ipsec|IPsec]] WG draft that bakes {{ml-kem|ML-KEM}} into" + }, + { + "stem": "HSR", + "count": 1, + "files": ["src/lib/data/protocols/ipsec.ts"], + "sample": "escription: 'strongSwan (originally HSR Rapperswil, now under [[pioneer:andreas" + }, + { + "stem": "OST", + "count": 1, + "files": ["src/lib/data/protocols/ipsec.ts"], + "sample": "dreas-steffen|Andreas Steffen]] and the OST team; owned by secunet AG since June 20" + }, + { + "stem": "AG", + "count": 1, + "files": ["src/lib/data/protocols/ipsec.ts"], + "sample": "en]] and the OST team; owned by secunet AG since June 2022, central to the BSI SIN" + }, + { + "stem": "BSI", + "count": 1, + "files": ["src/lib/data/protocols/ipsec.ts"], + "sample": "unet AG since June 2022, central to the BSI SINA high-security solution) and Libres" + }, + { + "stem": "SINA", + "count": 1, + "files": ["src/lib/data/protocols/ipsec.ts"], + "sample": "AG since June 2022, central to the BSI SINA high-security solution) and Libreswan (" + }, + { + "stem": "GCM", + "count": 1, + "files": ["src/lib/data/protocols/ipsec.ts"], + "sample": "VPN}} ({{ikev2|IKEv2}}, {{aes|AES}}-256-GCM, {{ecdh|ECDH}} groups 19–24, 5 Gbps/tun" + }, + { + "stem": "AZ", + "count": 1, + "files": ["src/lib/data/protocols/ipsec.ts"], + "sample": "VPN}} Gateway (10 Gbps aggregate on the AZ-redundant SKU), {{gcp|GCP}} Cloud {{vpn" + }, + { + "stem": "OCI", + "count": 1, + "files": ["src/lib/data/protocols/ipsec.ts"], + "sample": "nt SKU), {{gcp|GCP}} Cloud {{vpn|VPN}}, OCI Site-to-Site {{vpn|VPN}}. [[ipsec|IPsec" + }, + { + "stem": "VPC", + "count": 1, + "files": ["src/lib/data/protocols/ipsec.ts"], + "sample": "mqtt-connect|connect}} my on-prem to my VPC\" sku across every cloud.' }, { o" + }, + { + "stem": "ITAR", + "count": 1, + "files": ["src/lib/data/protocols/ipsec.ts"], + "sample": "same code as a regulated munition under ITAR. *Karn v. U.S. State Department* became" + }, + { + "stem": "BENIGNCERTAIN", + "count": 1, + "files": ["src/lib/data/protocols/ipsec.ts"], + "sample": "dow Brokers leak (August 2016) revealed BENIGNCERTAIN β€” an NSA exploit that extracted {{cisco" + }, + { + "stem": "PIX", + "count": 1, + "files": ["src/lib/data/protocols/ipsec.ts"], + "sample": "exploit that extracted {{cisco|Cisco}} PIX {{vpn|VPN}} private keys from IKEv1 ({{" + }, + { + "stem": "PPK", + "count": 1, + "files": ["src/lib/data/protocols/ipsec.ts"], + "sample": "table. [[rfc:8784|RFC 8784]] ({{pq|PQ}}-PPK) is co-authored by {{cisco|Cisco}}, {{a" + }, + { + "stem": "ELVIS-PLUS", + "count": 1, + "files": ["src/lib/data/protocols/ipsec.ts"], + "sample": "ed by {{cisco|Cisco}}, {{aws|AWS}}, and ELVIS-PLUS engineers β€” [[ipsec|IPsec]] has always" + }, + { + "stem": "ECMP", + "count": 1, + "files": ["src/lib/data/protocols/ipsec.ts"], + "sample": "efault to **32 entries**. On a 10 Gbps+ ECMP-parallel tunnel ({{linux|Linux}} {{xfrm" + }, + { + "stem": "KB", + "count": 1, + "files": ["src/lib/data/protocols/ipsec.ts"], + "sample": "he connection hangs after the first few KB. **Cure:** [[tcp|TCP]] {{mss|MSS}} clam" + }, + { + "stem": "IDL", + "count": 1, + "files": ["src/lib/data/protocols/json-rpc.ts"], + "sample": "] strips this to pure {{json|JSON}}: no IDL, no code generation, no binary encoding" + }, + { + "stem": "TGS-REQ", + "count": 1, + "files": ["src/lib/data/protocols/kerberos.ts"], + "sample": "TTP}}/web1.example.com\\`, she sends a **TGS-REQ** to the {{kerberos-kdc|KDC}}\\'s {{kerb" + }, + { + "stem": "REP", + "count": 1, + "files": ["src/lib/data/protocols/kerberos.ts"], + "sample": "eb1 returns an **{{ap-access-point|AP}}-REP** with its own timestamp for {{mtls|mut" + }, + { + "stem": "EXAMPLE.COM", + "count": 1, + "files": ["src/lib/data/protocols/kerberos.ts"], + "sample": "ls', description: \"When Alice in EXAMPLE.COM wants to access a service in PARTNER.CO" + }, + { + "stem": "SMB", + "count": 1, + "files": ["src/lib/data/protocols/kerberos.ts"], + "sample": "(`Authorization: Negotiate <base64>`), SMB, LDAP, and other applications transpare" + }, + { + "stem": "LDAP", + "count": 1, + "files": ["src/lib/data/protocols/kerberos.ts"], + "sample": "thorization: Negotiate <base64>`), SMB, LDAP, and other applications transparently u" + }, + { + "stem": "EC", + "count": 1, + "files": ["src/lib/data/protocols/kerberos.ts"], + "sample": "adline features: **PKINIT {{ecdh|ECDH}}/EC certs** (smart-card auth on {{curve2551" + }, + { + "stem": "FAST", + "count": 1, + "files": ["src/lib/data/protocols/kerberos.ts"], + "sample": "P-384), **paChecksum2** support (longer FAST-armored {{checksum|checksum}} to retire" + }, + { + "stem": "SU/KTH", + "count": 1, + "files": ["src/lib/data/protocols/kerberos.ts"], + "sample": "to {{mit|MIT}} Kerberos, originated at SU/KTH in Sweden. {{apple|Apple}} shipped Heim" + }, + { + "stem": "KER", + "count": 1, + "files": ["src/lib/data/protocols/kerberos.ts"], + "sample": "g crosses without a ticket. Pronounced *KER-ber-os* in English; *KEHR-ber-os* in mo" + }, + { + "stem": "KEHR", + "count": 1, + "files": ["src/lib/data/protocols/kerberos.ts"], + "sample": "t. Pronounced *KER-ber-os* in English; *KEHR-ber-os* in modern Greek.' }, { t" + }, + { + "stem": "V5", + "count": 1, + "files": ["src/lib/data/protocols/kerberos.ts"], + "sample": "ld ship Kerberos-shaped applications. **V5** ([[rfc:4120|RFC 4120]], 2005) was des" + }, + { + "stem": "UDP/123", + "count": 1, + "files": ["src/lib/data/protocols/kerberos.ts"], + "sample": "[[ntp|NTP]] servers, firewalls blocking UDP/123, virtualised {{hosts-bare|hosts}} with" + }, + { + "stem": "FQDN", + "count": 1, + "files": ["src/lib/data/protocols/kerberos.ts"], + "sample": "ails. **Cure:** register both short and FQDN SPNs in the keytab; set `dns_canonicali" + }, + { + "stem": "NEA1", + "count": 1, + "files": ["src/lib/data/protocols/kerberos.ts"], + "sample": "y|AD}} environments have **{{rc4|RC4}} (NEA1)** still enabled β€” the {{encryption|enc" + }, + { + "stem": "NT", + "count": 1, + "files": ["src/lib/data/protocols/kerberos.ts"], + "sample": "cause {{rc4|RC4}} keys are derived from NT hash and brute-force in hours. **Cure:*" + }, + { + "stem": "FB", + "count": 1, + "files": ["src/lib/data/protocols/mdns-dns-sd.ts"], + "sample": "\\`224.0.0.251\\` ([[ipv6|IPv6]]: \\`FF02::FB\\`). Two flag bits get repurposed: the h" + }, + { + "stem": "DLA-3990", + "count": 1, + "files": ["src/lib/data/protocols/mdns-dns-sd.ts"], + "sample": "DNS]] implementation. Patched in Debian DLA-3990 (December 2024); still under active mai" + }, + { + "stem": "CAPWAP", + "count": 1, + "files": ["src/lib/data/protocols/mdns-dns-sd.ts"], + "sample": "}} at 100% and Access Points lose their CAPWAP tunnel. The latest in a decade-long pat" + }, + { + "stem": "LGPL", + "count": 1, + "files": ["src/lib/data/protocols/mdns-dns-sd.ts"], + "sample": "nux|Linux}}/{{bsd|BSD}} implementation, LGPL, maintained by Trent Lloyd. Bundled by" + }, + { + "stem": "BBC", + "count": 1, + "files": ["src/lib/data/protocols/mdns-dns-sd.ts"], + "sample": "a 16-player networked tank game on the BBC Micro in 1987 and ported it to the Mac." + }, + { + "stem": "COBS", + "count": 1, + "files": ["src/lib/data/protocols/mdns-dns-sd.ts"], + "sample": "ed **Consistent Overhead Byte Stuffing (COBS)** β€” the framing algorithm now widely u" + }, + { + "stem": "BAF", + "count": 1, + "files": ["src/lib/data/protocols/mdns-dns-sd.ts"], + "sample": "l\" ({{ndss-conf|NDSS}} 2014)** measured BAF up to ~10Γ— for mDNS. **CERT/CC VU#55062" + }, + { + "stem": "CERT/CC", + "count": 1, + "files": ["src/lib/data/protocols/mdns-dns-sd.ts"], + "sample": ")** measured BAF up to ~10Γ— for mDNS. **CERT/CC VU#550620 (March 2015)** and **Akamai (" + }, + { + "stem": "VU", + "count": 1, + "files": ["src/lib/data/protocols/mdns-dns-sd.ts"], + "sample": "ured BAF up to ~10Γ— for mDNS. **CERT/CC VU#550620 (March 2015)** and **Akamai (Dec" + }, + { + "stem": "BCP", + "count": 1, + "files": ["src/lib/data/protocols/mdns-dns-sd.ts"], + "sample": "cal {{unicast|unicast}} queries; deploy BCP 38 ingress filtering.' }, { t" + }, + { + "stem": "DSN", + "count": 1, + "files": ["src/lib/data/protocols/mptcp.ts"], + "sample": "ta {{sequence-number|Sequence Number}} (DSN) ensures correct ordering across all su" + }, + { + "stem": "TB", + "count": 1, + "files": ["src/lib/data/protocols/nat-traversal.ts"], + "sample": "5+ locations with $0.05/GB egress and 1 TB free per month β€” the first major price" + }, + { + "stem": "FINGERPRINT", + "count": 1, + "files": ["src/lib/data/protocols/nat-traversal.ts"], + "sample": "p-address|IP}} version field, but the **FINGERPRINT** attribute {{checksum|checksum}} is XO" + }, + { + "stem": "SOCKS", + "count": 1, + "files": ["src/lib/data/protocols/nat-traversal.ts"], + "sample": "l`/`Frida` and use the server as a free SOCKS-style proxy into your private network." + }, + { + "stem": "NFC-A/B/F", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "range is ≀10 cm for {{iso|ISO}} 14443 (NFC-A/B/F) and historically ≀1 m for {{iso|ISO}}" + }, + { + "stem": "ALM", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "e {{load-modulation|load modulation}}* (ALM) instead, generating a small reflected" + }, + { + "stem": "WUPA", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "adcasts a 7-bit {{reqa|REQA}} (0x26) or WUPA (0x52) short frame; the card responds w" + }, + { + "stem": "NVB", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "collision}}** loop with {{sel-iso|SEL}}+NVB frames ({{sel-iso|SEL}}=0x93 for cascad" + }, + { + "stem": "CL2", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "EL}}=0x93 for cascade level 1, 0x95 for CL2, 0x97 for CL3), converging on each byte" + }, + { + "stem": "CL3", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "cascade level 1, 0x95 for CL2, 0x97 for CL3), converging on each byte of the {{uid|" + }, + { + "stem": "FWI", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "negotiate frame size (FSCI) and timing (FWI). T2T cards skip {{rats|RATS}} and go s" + }, + { + "stem": "RECORD", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "ich files to read; {{read-record|READ}} RECORDs pull the {{pan-id|PAN}}, expiry, and pu" + }, + { + "stem": "MB/ME", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "cord begins with a 1-byte header β€” bits MB/ME (Message Begin/End), CF (Chunk Flag), S" + }, + { + "stem": "CF", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "eader β€” bits MB/ME (Message Begin/End), CF (Chunk Flag), SR (Short Record β€” 1-byte" + }, + { + "stem": "SR", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "E (Message Begin/End), CF (Chunk Flag), SR (Short Record β€” 1-byte length vs 4), IL" + }, + { + "stem": "IL", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "SR (Short Record β€” 1-byte length vs 4), IL ({{id-identifier|ID}} Length present)," + }, + { + "stem": "NFC-WLC", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "EC standard in **March 2026** alongside NFC-WLC.\" }, { title: 'Three transports," + }, + { + "stem": "FPAN", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "rdholder's real Funding {{pan-id|PAN}} (FPAN) is never stored on the device; instead" + }, + { + "stem": "EEA", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "eld-Detect. Available **only inside the EEA** (27 EU states + Iceland, Liechtenstei" + }, + { + "stem": "CMA", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "emplated and the watch-items are the UK CMA, Japan JFTC, and Australian ACCC.\"," + }, + { + "stem": "JFTC", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "d the watch-items are the UK CMA, Japan JFTC, and Australian ACCC.\", source: {" + }, + { + "stem": "ACCC", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "the UK CMA, Japan JFTC, and Australian ACCC.\", source: { url: 'https://ec.eu" + }, + { + "stem": "CR15", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "ting volume). Certification Release 15 (CR15) accepts applications by early 2026; fu" + }, + { + "stem": "DK3", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "line: *cross-version compatibility* β€” a DK3 phone unlocks a DK4 car and vice versa." + }, + { + "stem": "DK4", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "compatibility* β€” a DK3 phone unlocks a DK4 car and vice versa. **115 vehicle/modul" + }, + { + "stem": "ESPR", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "gn for Sustainable Products Regulation (ESPR).\", source: { url: 'https://nfc-" + }, + { + "stem": "CIPURSE", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "smart cards ({{mifare|MIFARE}}, FeliCa, CIPURSE), TfL bet on **bank-issued {{emv-crypto" + }, + { + "stem": "DG1", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "with a small {{icao|ICAO}} file system (DG1 {{mrz|MRZ}}, DG2 photo, EF.SOD signatur" + }, + { + "stem": "DG2", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "ao|ICAO}} file system (DG1 {{mrz|MRZ}}, DG2 photo, EF.SOD signature, EF.COM index," + }, + { + "stem": "EF.SOD", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "ile system (DG1 {{mrz|MRZ}}, DG2 photo, EF.SOD signature, EF.COM index, plus optional" + }, + { + "stem": "EF.COM", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "mrz|MRZ}}, DG2 photo, EF.SOD signature, EF.COM index, plus optional DG3 fingerprints /" + }, + { + "stem": "DG3", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "signature, EF.COM index, plus optional DG3 fingerprints / DG4 iris). The reader ca" + }, + { + "stem": "DG4", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "index, plus optional DG3 fingerprints / DG4 iris). The reader cannot get any data w" + }, + { + "stem": "BAC", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "he reader cannot get any data without **BAC** (legacy 3DES from MRZ) or **PACE** (m" + }, + { + "stem": "PACE", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "out **BAC** (legacy 3DES from MRZ) or **PACE** (modern {{ecdh|ECDH}} from MRZ or 6-d" + }, + { + "stem": "DTC-PC/VC", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "it CAN). The Digital Travel Credential (DTC-PC/VC) β€” passport on phone β€” is in airport pi" + }, + { + "stem": "EV1", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "e|MIFARE}} Classic in **1994**, DESFire EV1 in **2006**, {{mifare|MIFARE}} Plus in" + }, + { + "stem": "EV2", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "fare|MIFARE}} Plus in **2011**, DESFire EV2 in 2016, EV3 in the early 2020s. The Cl" + }, + { + "stem": "EAL5", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "nts β€” full {{aes|AES}}, Common Criteria EAL5+, side-channel hardened. Dutch OV-chipk" + }, + { + "stem": "ZEEKR", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": ", XPENG, Geely group β€” Volvo, Polestar, ZEEKR, Lynk & Co., smart, Lotus).\" } ]," + }, + { + "stem": "LC", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "PCD}} and {{picc|PICC}} each present an LC resonant tank around 13.56 MHz; small d" + }, + { + "stem": "PN553", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "lation}} in the controller ({{nxp|NXP}} PN553 onward). Q factor: lower Q broadens the" + }, + { + "stem": "CDA", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "am|EMV}} Mode** (normal 'fast tap' with CDA). The card returns an AIP byte that sig" + }, + { + "stem": "TU", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"], + "sample": "to a confederate's phone at a terminal. TU Darmstadt's **NFCGate** (2015+) made th" + }, + { + "stem": "T2-T1", + "count": 1, + "files": ["src/lib/data/protocols/ntp.ts"], + "sample": "description: '{{offset|Offset}} = ((T2-T1) + (T3-T4)) / 2. Delay = (T4-T1) - (T3-" + }, + { + "stem": "T3-T4", + "count": 1, + "files": ["src/lib/data/protocols/ntp.ts"], + "sample": "n: '{{offset|Offset}} = ((T2-T1) + (T3-T4)) / 2. Delay = (T4-T1) - (T3-T2). The c" + }, + { + "stem": "T4-T1", + "count": 1, + "files": ["src/lib/data/protocols/ntp.ts"], + "sample": "t}} = ((T2-T1) + (T3-T4)) / 2. Delay = (T4-T1) - (T3-T2). The clock is adjusted gradu" + }, + { + "stem": "T3-T2", + "count": 1, + "files": ["src/lib/data/protocols/ntp.ts"], + "sample": "-T1) + (T3-T4)) / 2. Delay = (T4-T1) - (T3-T2). The clock is adjusted gradually to av" + }, + { + "stem": "INITIAL", + "count": 1, + "files": ["src/lib/data/protocols/ospf.ts"], + "sample": "fc-doc|RFC}} 8405 {{spf|SPF}} back-off (INITIAL/SHORT_WAIT/LONG_WAIT) throttles {{spf|S" + }, + { + "stem": "TE", + "count": 1, + "files": ["src/lib/data/protocols/ospf.ts"], + "sample": "with its own metric ({{igp|IGP}} cost, TE cost, min-delay) and constraints (inclu" + }, + { + "stem": "SID", + "count": 1, + "files": ["src/lib/data/protocols/ospf.ts"], + "sample": "Rv6 Locator advertisement, and SRv6 End SID encoding to [[ospf|OSPFv3]]. Edited by" + }, + { + "stem": "FAD", + "count": 1, + "files": ["src/lib/data/protocols/ospf.ts"], + "sample": "-2}} keychain authentication, Flex-Algo FAD with {{srlg|SRLG}}-exclude, and link-de" + }, + { + "stem": "ACX/PTX", + "count": 1, + "files": ["src/lib/data/protocols/ospf.ts"], + "sample": "xclude, and link-delay normalisation on ACX/PTX hardware β€” bringing Flex-Algo from \"shi" + }, + { + "stem": "C0/S0", + "count": 1, + "files": ["src/lib/data/protocols/rtmp.ts"], + "sample": "[[rtmp|RTMP]] {{handshake|handshake}} (C0/S0, C1/S1, C2/S2) exchanging timestamps an" + }, + { + "stem": "C1/S1", + "count": 1, + "files": ["src/lib/data/protocols/rtmp.ts"], + "sample": "|RTMP]] {{handshake|handshake}} (C0/S0, C1/S1, C2/S2) exchanging timestamps and rando" + }, + { + "stem": "C2/S2", + "count": 1, + "files": ["src/lib/data/protocols/rtmp.ts"], + "sample": "{{handshake|handshake}} (C0/S0, C1/S1, C2/S2) exchanging timestamps and random bytes" + }, + { + "stem": "ECHO", + "count": 1, + "files": ["src/lib/data/protocols/sctp.ts"], + "sample": "k|INIT}}-{{ack|ACK}}, {{cookie|COOKIE}}-ECHO, {{cookie|COOKIE}}-{{ack|ACK}}) that pr" + }, + { + "stem": "SAVPF", + "count": 1, + "files": ["src/lib/data/protocols/sdp.ts"], + "sample": "video), transport protocol ([[rtp|RTP]]/SAVPF), port number, and list of supported {{" + }, + { + "stem": "CTS-3000", + "count": 1, + "files": ["src/lib/data/protocols/sdp.ts"], + "sample": "n: 'The {{cisco|Cisco}} TelePresence CTS-3000 prototype β€” the kind of immersive video" + }, + { + "stem": "PJSIP", + "count": 1, + "files": ["src/lib/data/protocols/sip.ts"], + "sample": "fg) # Sends SIP REGISTER`, caption: 'PJSIP registers with a [[sip|SIP]] server β€” t" + }, + { + "stem": "PLAIN", + "count": 1, + "files": ["src/lib/data/protocols/smtp.ts"], + "sample": "ogin-auth|LOGIN}} or {{smtp-auth|AUTH}} PLAIN.' }, { title: 'Envelope & messag" + }, + { + "stem": "USDA", + "count": 1, + "files": ["src/lib/data/protocols/soap.ts"], + "sample": ": 'The {{ibm|IBM}} System/360 at the USDA (1966). Mainframes like these laid the" + }, + { + "stem": "MESSAGE", + "count": 1, + "files": ["src/lib/data/protocols/stomp.ts"], + "sample": "ers matching messages to subscribers as MESSAGE frames. Client can {{ack|ACK}}/{{nack|N" + }, + { + "stem": "LDP", + "count": 1, + "files": ["src/lib/data/protocols/tcp.ts"], + "sample": "p|TCP]]-{{md5|MD5}} used by [[bgp|BGP]]/LDP. Same release added microsecond-resolut" + }, + { + "stem": "MSL", + "count": 1, + "files": ["src/lib/data/protocols/tcp.ts"], + "sample": "-wait|TIME_WAIT}}** for ~60 seconds (2Γ— MSL) on {{linux|Linux}}. Why? A delayed seg" + }, + { + "stem": "ACME", + "count": 1, + "files": ["src/lib/data/protocols/tls.ts"], + "sample": "or the web. All certificates issued via ACME. ~3M certificates renewed daily.' }" + }, + { + "stem": "IR-UWB", + "count": 1, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "d of modulating a continuous carrier, **IR-UWB** transmits sub-nanosecond Gaussian-mon" + }, + { + "stem": "BPM", + "count": 1, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "lses at one of two time-slot positions (BPM) with chosen polarity ({{bpsk|BPSK}}) β€”" + }, + { + "stem": "GAP", + "count": 1, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "liro|Aliro 1.0}}**: **(1)** {{ble|BLE}} GAP advertising with the application's serv" + }, + { + "stem": "TB/NTB", + "count": 1, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "10–30 cm. *Secure ranging:* Wi-Fi 11az TB/NTB with PASN vs. UWB {{sts|STS}}. *Infrast" + }, + { + "stem": "PASN", + "count": 1, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "Secure ranging:* Wi-Fi 11az TB/NTB with PASN vs. UWB {{sts|STS}}. *Infrastructure:*" + }, + { + "stem": "PSD", + "count": 1, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "\"{{fcc|FCC}} Part 15.519 caps average PSD at **βˆ’41.3 dBm/MHz** across 3.1–10.6 GH" + }, + { + "stem": "AV", + "count": 1, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "la Model 3 / Y phone-as-a-key (CVSS 6.8 AV:A/AC:H/PR:N/{{ui|UI}}:N/S:U/C:H/I:H/A:N" + }, + { + "stem": "AC", + "count": 1, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "del 3 / Y phone-as-a-key (CVSS 6.8 AV:A/AC:H/PR:N/{{ui|UI}}:N/S:U/C:H/I:H/A:N). ~$" + }, + { + "stem": "PIN", + "count": 1, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "Kwikset/Weiser Kevo. Tesla recommended PIN-to-Drive as a stopgap; the deeper indus" + }, + { + "stem": "D02", + "count": 1, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "sed to **Draft D03 in September 2025** (D02 March 2025), with ratification expected" + }, + { + "stem": "NCAP", + "count": 1, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "d-presence detection (driven by EU Euro NCAP rules from 2025); LRP+{{hrp-uwb|HRP}} d" + }, + { + "stem": "LRP", + "count": 1, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "riven by EU Euro NCAP rules from 2025); LRP+{{hrp-uwb|HRP}} dual-mode hardware supp" + }, + { + "stem": "ST64UWB", + "count": 1, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "ound {{sts|STS}}. STMicroelectronics' **ST64UWB** (announced Q1 2026, 18 nm FD-SOI) is" + }, + { + "stem": "FD-SOI", + "count": 1, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "' **ST64UWB** (announced Q1 2026, 18 nm FD-SOI) is the first commercial 4ab silicon, w" + }, + { + "stem": "VW", + "count": 1, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "edes, Hyundai/Kia, Audi (new for 2025), VW, Porsche, GM, Ford, and Chinese OEMs (N" + }, + { + "stem": "ASSA", + "count": 1, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "le|Apple}}, {{google|Google}}, Samsung, ASSA ABLOY, {{nxp|NXP}}, Infineon, STMicroel" + }, + { + "stem": "ABLOY", + "count": 1, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "ple}}, {{google|Google}}, Samsung, ASSA ABLOY, {{nxp|NXP}}, Infineon, STMicroelectron" + }, + { + "stem": "EQS", + "count": 1, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "on the Wallet-based Digital Key for the EQS and S-Class from 2022. **{{nxp|NXP}} SR" + }, + { + "stem": "S22/S23/S24", + "count": 1, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "laxy S21+ / S21 Ultra / Note 20 Ultra / S22/S23/S24 (UWB-equipped models) for AR-based dire" + }, + { + "stem": "U100", + "count": 1, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "ung's **Exynos {{mqtt-connect|Connect}} U100** in-house UWB silicon also shipped in" + }, + { + "stem": "PTP", + "count": 1, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "} over wired [[ethernet|Ethernet]] with PTP-grade clock distribution. **{{cisco|Cis" + }, + { + "stem": "L1", + "count": 1, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "d-won against {{gps|GPS}} (operating at L1=1575.42 MHz), avionics, and DoD interes" + }, + { + "stem": "EIRP", + "count": 1, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "-of-life systems. The **βˆ’41.3 dBm/MHz** EIRP limit is essentially the Β§15.209 backgr" + }, + { + "stem": "MB-OFDM", + "count": 1, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "After three years of deadlock between **MB-OFDM** ({{intel|Intel}} + WiMedia Alliance)" + }, + { + "stem": "DS-UWB", + "count": 1, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "intel|Intel}} + WiMedia Alliance) and **DS-UWB** (Freescale + UWB Forum), neither side" + }, + { + "stem": "HI", + "count": 1, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "ty required to ratify. At the Waikoloa, HI interim on **19 January 2006** the task" + }, + { + "stem": "DW1000", + "count": 1, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "Hz wide. Older silicon ({{qorvo|Qorvo}} DW1000) supports only Channel 5; everything fr" + }, + { + "stem": "PCB", + "count": 1, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "handle UWB anchors typically use planar PCB patches with carefully controlled groun" + }, + { + "stem": "BLE/UWB", + "count": 1, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "eeps the user in their car. **(d)** Log BLE/UWB transition failures separately for diag" + }, + { + "stem": "CIR", + "count": 1, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "rection using channel-impulse-response (CIR) features; recent Adaptive Kalman Filte" + }, + { + "stem": "LOS", + "count": 1, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "lace infrastructure anchors to maximise LOS to the working volume; ceiling mounts a" + }, + { + "stem": "PRF", + "count": 1, + "files": ["src/lib/data/protocols/uwb.ts"], + "sample": "**(b)** Use {{bprf|BPRF}} (~64 MHz mean PRF) for tag-side rather than HPRF. **(c)**" + }, + { + "stem": "EAPOL", + "count": 1, + "files": ["src/lib/data/protocols/wifi.ts"], + "sample": "{{access-point|AP}} perform a 4-message EAPOL {{handshake|handshake}} to derive per-s" + }, + { + "stem": "RA", + "count": 1, + "files": ["src/lib/data/protocols/wifi.ts"], + "sample": "AC}} addresses (three typically used) β€” RA, TA, and DA β€” and are encrypted with th" + }, + { + "stem": "TA", + "count": 1, + "files": ["src/lib/data/protocols/wifi.ts"], + "sample": "addresses (three typically used) β€” RA, TA, and DA β€” and are encrypted with the se" + }, + { + "stem": "DA", + "count": 1, + "files": ["src/lib/data/protocols/wifi.ts"], + "sample": "es (three typically used) β€” RA, TA, and DA β€” and are encrypted with the session ke" + }, + { + "stem": "BSSID", + "count": 1, + "files": ["src/lib/data/protocols/wifi.ts"], + "sample": "capy in monitor mode β€” revealing SSIDs, BSSIDs, and channels', alternatives: [ {" + }, + { + "stem": "MAC1", + "count": 1, + "files": ["src/lib/data/protocols/wireguard.ts"], + "sample": "a {{wg-tai64n|TAI64N timestamp}}. Plus MAC1 (proves the initiator knows the respond" + }, + { + "stem": "MAC2", + "count": 1, + "files": ["src/lib/data/protocols/wireguard.ts"], + "sample": "iator knows the responder's pubkey) and MAC2 ({{cookie|cookie}} under load, DoS shie" + }, + { + "stem": "H1", + "count": 1, + "files": ["src/lib/data/protocols/wireguard.ts"], + "sample": "et sizes, randomised header type bytes (H1–H4 ranges instead of fixed 1–4), random" + }, + { + "stem": "H4", + "count": 1, + "files": ["src/lib/data/protocols/wireguard.ts"], + "sample": "sizes, randomised header type bytes (H1–H4 ranges instead of fixed 1–4), random S1" + }, + { + "stem": "AWG", + "count": 1, + "files": ["src/lib/data/protocols/wireguard.ts"], + "sample": "ad of fixed 1–4), random S1/S2 padding. AWG 2.0 adds optional QUIC/{{dns-resolution" + }, + { + "stem": "XEP", + "count": 1, + "files": ["src/lib/data/protocols/xmpp.ts"], + "sample": "e base protocol is minimal. Hundreds of XEPs add features: multi-user chat, {{http-m" + }, + { + "stem": "QPSK", + "count": 1, + "files": ["src/lib/data/protocols/zigbee.ts"], + "sample": "The dominant {{phy|PHY}} is **2.4 GHz O-QPSK** with 16 channels (11–26), 5 MHz spaci" + }, + { + "stem": "NA", + "count": 1, + "files": ["src/lib/data/protocols/zigbee.ts"], + "sample": "kbit/s {{bpsk|BPSK}}) and 902–928 MHz (NA, 40 kbit/s {{bpsk|BPSK}}) give better w" + }, + { + "stem": "FSK", + "count": 1, + "files": ["src/lib/data/protocols/zigbee.ts"], + "sample": "terference at lower bit rates; R23 adds FSK PHYs in those same bands. {{frame|Frame" + }, + { + "stem": "PSDU", + "count": 1, + "files": ["src/lib/data/protocols/zigbee.ts"], + "sample": "me|Frames}} are bounded at **127 octets PSDU** with a **16-bit {{checksum|FCS}}**. T" + }, + { + "stem": "CSMA-CA", + "count": 1, + "files": ["src/lib/data/protocols/zigbee.ts"], + "sample": "The {{mac-address|MAC}} uses unslotted CSMA-CA in most deployments (FFDs as routers, R" + }, + { + "stem": "R20", + "count": 1, + "files": ["src/lib/data/protocols/zigbee.ts"], + "sample": "mesh {{routing-table|routing}}** (since R20, 2007). Every mains-powered router main" + }, + { + "stem": "TI", + "count": 1, + "files": ["src/lib/data/protocols/zigbee.ts"], + "sample": "t, dresden elektronik ConBee II, or any TI CC2652 stick β€” the radio is abstracted" + }, + { + "stem": "MMO-128", + "count": 1, + "files": ["src/lib/data/protocols/zigbee.ts"], + "sample": "urve25519|Curve25519}} with {{aes|AES}}-MMO-128 (kills the *ZigBeeAlliance09* default-k" + }, + { + "stem": "IR", + "count": 1, + "files": ["src/lib/data/protocols/zigbee.ts"], + "sample": "]], Power-over-Ethernet, {{usb|USB}}-C, IR blaster, **8 GB encrypted local storage" + }, + { + "stem": "BOM", + "count": 1, + "files": ["src/lib/data/protocols/zigbee.ts"], + "sample": "a Bluetooth Low Energy radio, reducing BOM cost for cheaper {{matter|Matter}}-brid" + }, + { + "stem": "ZLL", + "count": 1, + "files": ["src/lib/data/protocols/zigbee.ts"], + "sample": "sy that nudged Signify back to standard ZLL compatibility. IKEA remains an active {" + }, + { + "stem": "ROAM", + "count": 1, + "files": ["src/lib/data/protocols/zigbee.ts"], + "sample": "ns covering Atrius, nLight, nLight AIR, ROAM, SensorSwitch, Synergy, and XPoint Wire" + }, + { + "stem": "GPL", + "count": 1, + "files": ["src/lib/data/protocols/zigbee.ts"], + "sample": "s from 568 vendors', text: \"A single GPL-licensed Node.js project β€” maintained p" + }, + { + "stem": "NV", + "count": 1, + "files": ["src/lib/data/protocols/zigbee.ts"], + "sample": "ke regular backups of the coordinator's NV (zigbee2mqtt writes `coordinator_backup" + }, + { + "stem": "UPS", + "count": 1, + "files": ["src/lib/data/protocols/zigbee.ts"], + "sample": "cally); **(b)** keep the Coordinator on UPS or PoE; **(c)** use a {{usb|USB}} exten" + }, + { + "stem": "SSD", + "count": 1, + "files": ["src/lib/data/protocols/zigbee.ts"], + "sample": "gle away from {{usb|USB}} 3.0 ports and SSDs, which emit 2.4 GHz noise; **(d)** cons" + }, + { + "stem": "EFR32", + "count": 1, + "files": ["src/lib/data/protocols/zigbee.ts"], + "sample": "child-table size on a typical CC2652 / EFR32 firmware is **32**; the Sonoff ZBDongle" + } + ], + "concept": [ + { + "stem": "API", + "suggestedId": "api", + "count": 32, + "files": [ + "src/lib/data/book/parts/web-api.ts", + "src/lib/data/category-deep-dives.ts", + "src/lib/data/category-stories/web-api.ts", + "src/lib/data/comparison/pairs.ts", + "src/lib/data/diagram-definitions.ts", + "src/lib/data/journeys.ts", + "src/lib/data/protocols/graphql.ts", + "src/lib/data/protocols/oauth2.ts", + "src/lib/data/protocols/rest.ts", + "src/lib/data/protocols/tcp.ts" + ] + }, + { + "stem": "NAT", + "suggestedId": "nat", + "count": 13, + "files": [ + "src/lib/data/book/parts/patterns-failures.ts", + "src/lib/data/comparison/pairs.ts", + "src/lib/data/journeys.ts", + "src/lib/data/protocols/nat-traversal.ts" + ] + }, + { + "stem": "URL", + "suggestedId": "url", + "count": 11, + "files": [ + "src/lib/data/category-stories/web-api.ts", + "src/lib/data/comparison/pairs.ts", + "src/lib/data/diagram-definitions.ts", + "src/lib/data/journeys.ts", + "src/lib/data/protocols/dash.ts", + "src/lib/data/protocols/hls.ts", + "src/lib/data/protocols/nat-traversal.ts", + "src/lib/data/protocols/tls.ts" + ] + }, + { + "stem": "RFC", + "suggestedId": "rfc-doc", + "count": 10, + "files": [ + "src/lib/data/book/parts/how-to-learn-more.ts", + "src/lib/data/category-stories/utilities.ts", + "src/lib/data/protocols/nat-traversal.ts", + "src/lib/data/protocols/ospf.ts" + ] + }, + { + "stem": "CDN", + "suggestedId": "cdn-acr", + "count": 8, + "files": [ + "src/lib/data/category-stories/realtime-av.ts", + "src/lib/data/comparison/pairs.ts", + "src/lib/data/journeys.ts", + "src/lib/data/protocols/hls.ts", + "src/lib/data/protocols/quic.ts", + "src/lib/data/protocols/tls.ts" + ] + }, + { + "stem": "LSA", + "suggestedId": "lsa", + "count": 6, + "files": ["src/lib/data/protocols/ospf.ts"] + }, + { + "stem": "IMP", + "suggestedId": "imp", + "count": 4, + "files": [ + "src/lib/data/book/parts/story-of-the-internet.ts", + "src/lib/data/concept-foundations.ts", + "src/lib/data/outages.ts" + ] + }, + { + "stem": "AP", + "suggestedId": "ap-access-point", + "count": 4, + "files": [ + "src/lib/data/category-deep-dives.ts", + "src/lib/data/protocols/bluetooth.ts", + "src/lib/data/protocols/mdns-dns-sd.ts", + "src/lib/data/protocols/uwb.ts" + ] + }, + { + "stem": "MAC", + "suggestedId": "mac-media", + "count": 4, + "files": [ + "src/lib/data/comparison/pairs.ts", + "src/lib/data/journeys.ts", + "src/lib/data/protocols/ethernet.ts" + ] + }, + { + "stem": "ISP", + "suggestedId": "isp", + "count": 3, + "files": [ + "src/lib/data/diagram-definitions.ts", + "src/lib/data/journeys.ts", + "src/lib/data/outages.ts" + ] + }, + { + "stem": "ACK", + "suggestedId": "ack", + "count": 3, + "files": [ + "src/lib/data/outages.ts", + "src/lib/data/protocols/coap.ts", + "src/lib/data/protocols/tcp.ts" + ] + }, + { + "stem": "OEM", + "suggestedId": "oem", + "count": 3, + "files": ["src/lib/data/protocols/nfc.ts", "src/lib/data/protocols/uwb.ts"] + }, + { + "stem": "CLAT", + "suggestedId": "clat-acr", + "count": 2, + "files": ["src/lib/data/book/parts/frontier.ts"] + }, + { + "stem": "GPU", + "suggestedId": "gpu", + "count": 2, + "files": ["src/lib/data/book/parts/frontier.ts"] + }, + { + "stem": "ASK", + "suggestedId": "ask-modulation", + "count": 2, + "files": ["src/lib/data/book/parts/wireless.ts", "src/lib/data/protocols/nfc.ts"] + }, + { + "stem": "POP", + "suggestedId": "pop-acr", + "count": 2, + "files": ["src/lib/data/category-stories/utilities.ts", "src/lib/data/protocols/bgp.ts"] + }, + { + "stem": "LAN", + "suggestedId": "lan-acr", + "count": 2, + "files": ["src/lib/data/comparison/pairs.ts", "src/lib/data/journeys.ts"] + }, + { + "stem": "TLD", + "suggestedId": "tld", + "count": 2, + "files": ["src/lib/data/diagram-definitions.ts"] + }, + { + "stem": "URI", + "suggestedId": "uri", + "count": 2, + "files": ["src/lib/data/journeys.ts", "src/lib/data/protocols/coap.ts"] + }, + { + "stem": "SELECT", + "suggestedId": "imap-select", + "count": 2, + "files": ["src/lib/data/journeys.ts", "src/lib/data/protocols/nfc.ts"] + }, + { + "stem": "CPU", + "suggestedId": "cpu", + "count": 2, + "files": ["src/lib/data/outages.ts"] + }, + { + "stem": "KEM", + "suggestedId": "kem-acr", + "count": 2, + "files": ["src/lib/data/protocols/ipsec.ts"] + }, + { + "stem": "KDC", + "suggestedId": "kerberos-kdc", + "count": 2, + "files": ["src/lib/data/protocols/kerberos.ts"] + }, + { + "stem": "ID", + "suggestedId": "id-identifier", + "count": 2, + "files": ["src/lib/data/protocols/mdns-dns-sd.ts", "src/lib/data/protocols/wireguard.ts"] + }, + { + "stem": "SSID", + "suggestedId": "ssid", + "count": 2, + "files": ["src/lib/data/protocols/mdns-dns-sd.ts", "src/lib/data/protocols/wifi.ts"] + }, + { + "stem": "MRZ", + "suggestedId": "mrz", + "count": 2, + "files": ["src/lib/data/protocols/nfc.ts"] + }, + { + "stem": "DR", + "suggestedId": "ospf-dr", + "count": 2, + "files": ["src/lib/data/protocols/ospf.ts"] + }, + { + "stem": "FTM", + "suggestedId": "ftm", + "count": 2, + "files": ["src/lib/data/protocols/uwb.ts"] + }, + { + "stem": "PHY", + "suggestedId": "phy", + "count": 2, + "files": ["src/lib/data/protocols/zigbee.ts"] + }, + { + "stem": "ISN", + "suggestedId": "isn", + "count": 1, + "files": ["src/lib/data/book/parts/famous-outages.ts"] + }, + { + "stem": "X25519MLKEM768", + "suggestedId": "pq-ciphersuite", + "count": 1, + "files": ["src/lib/data/book/parts/frontier.ts"] + }, + { + "stem": "ROA", + "suggestedId": "roa", + "count": 1, + "files": ["src/lib/data/book/parts/frontier.ts"] + }, + { + "stem": "MED", + "suggestedId": "med", + "count": 1, + "files": ["src/lib/data/book/parts/layer-2-3.ts"] + }, + { + "stem": "SFU", + "suggestedId": "sfu", + "count": 1, + "files": ["src/lib/data/book/parts/realtime-av.ts"] + }, + { + "stem": "WAN", + "suggestedId": "wan-acr", + "count": 1, + "files": ["src/lib/data/book/parts/transport.ts"] + }, + { + "stem": "SCP", + "suggestedId": "scp-copy", + "count": 1, + "files": ["src/lib/data/book/parts/utilities-security.ts"] + }, + { + "stem": "CVE", + "suggestedId": "cve", + "count": 1, + "files": ["src/lib/data/book/parts/web-api.ts"] + }, + { + "stem": "VLAN", + "suggestedId": "vlan", + "count": 1, + "files": ["src/lib/data/category-deep-dives.ts"] + }, + { + "stem": "UI", + "suggestedId": "ui", + "count": 1, + "files": ["src/lib/data/journeys.ts"] + }, + { + "stem": "LLM", + "suggestedId": "llm", + "count": 1, + "files": ["src/lib/data/journeys.ts"] + }, + { + "stem": "KEEPALIVE", + "suggestedId": "bgp-keepalive", + "count": 1, + "files": ["src/lib/data/protocols/bgp.ts"] + }, + { + "stem": "UPDATE", + "suggestedId": "bgp-update", + "count": 1, + "files": ["src/lib/data/protocols/bgp.ts"] + }, + { + "stem": "UUID", + "suggestedId": "uuid", + "count": 1, + "files": ["src/lib/data/protocols/bluetooth.ts"] + }, + { + "stem": "DC", + "suggestedId": "dc-domain-controller", + "count": 1, + "files": ["src/lib/data/protocols/kerberos.ts"] + }, + { + "stem": "SPN", + "suggestedId": "spn", + "count": 1, + "files": ["src/lib/data/protocols/kerberos.ts"] + }, + { + "stem": "APDU", + "suggestedId": "apdu", + "count": 1, + "files": ["src/lib/data/protocols/nfc.ts"] + }, + { + "stem": "LSDB", + "suggestedId": "lsdb", + "count": 1, + "files": ["src/lib/data/protocols/ospf.ts"] + }, + { + "stem": "SRLG", + "suggestedId": "srlg", + "count": 1, + "files": ["src/lib/data/protocols/ospf.ts"] + }, + { + "stem": "TLV", + "suggestedId": "tlv", + "count": 1, + "files": ["src/lib/data/protocols/ospf.ts"] + }, + { + "stem": "NIC", + "suggestedId": "nic", + "count": 1, + "files": ["src/lib/data/protocols/quic.ts"] + }, + { + "stem": "BLE", + "suggestedId": "ble", + "count": 1, + "files": ["src/lib/data/protocols/uwb.ts"] + }, + { + "stem": "U2", + "suggestedId": "u2-chip", + "count": 1, + "files": ["src/lib/data/protocols/uwb.ts"] + }, + { + "stem": "U1", + "suggestedId": "u1-chip", + "count": 1, + "files": ["src/lib/data/protocols/uwb.ts"] + }, + { + "stem": "FFD", + "suggestedId": "ffd", + "count": 1, + "files": ["src/lib/data/protocols/zigbee.ts"] + }, + { + "stem": "RFD", + "suggestedId": "rfd", + "count": 1, + "files": ["src/lib/data/protocols/zigbee.ts"] + } + ], + "protocol": [ + { + "stem": "UWB", + "suggestedId": "uwb", + "count": 74 + }, + { + "stem": "NFC", + "suggestedId": "nfc", + "count": 37 + }, + { + "stem": "HTTPS", + "suggestedId": "http1", + "count": 19 + }, + { + "stem": "IP", + "suggestedId": "ip", + "count": 9 + }, + { + "stem": "UDP", + "suggestedId": "udp", + "count": 2 + }, + { + "stem": "QUIC", + "suggestedId": "quic", + "count": 2 + }, + { + "stem": "OAUTH2", + "suggestedId": "oauth2", + "count": 1 + } + ] +} diff --git a/scripts/output/acronym-audit.md b/scripts/output/acronym-audit.md index 5114474..2318c37 100644 --- a/scripts/output/acronym-audit.md +++ b/scripts/output/acronym-audit.md @@ -11,387 +11,386 @@ Total distinct bare acronyms: **574** ## Unknown β€” need new concept entries (508) -| Acronym | Count | Files | Suggested ID | Sample | -|---|---:|---:|---|---| -| `FF` | 12 | 2 | β€” | to the {{broadcast\|broadcast}} address (FF:FF:FF:FF:FF:FF) asking "Who has 192.168 | -| `BMW` | 9 | 4 | β€” | t bootstraps {{matter\|Matter}}, unlocks BMWs, and broadcasts public hearing-loops ac | -| `R23` | 9 | 3 | β€” | zigbee\|IEEE 802.15.4 mesh]], Zigbee PRO R23 ({{dynamic-link-key\|Dynamic Link Key}}, | -| `AIP` | 6 | 2 | β€” | After GET PROCESSING OPTIONS (returning AIP+{{afl\|AFL}}) and {{read-record\|READ REC | -| `GB` | 6 | 4 | β€” | -byte lifetime (default ~8 hours / ~100 GB). Before either limit is hit, peers run | -| `Q1` | 5 | 4 | β€” | he in-kernel push', text: 'As of Q1 2026, [[quic\|QUIC]] carries roughly **2 | -| `OV` | 5 | 2 | β€” | to seconds of cloning time. **The Dutch OV-chipkaart kept shipping affected cards | -| `M3` | 5 | 2 | β€” | atter}} devices* (Hue Bridge, Aqara Hub M3) translate {{matter\|Matter}} operations | -| `II` | 4 | 4 | β€” | 'The **[[ethernet\|Ethernet]] Type II frame format** β€” six bytes of destinati | -| `F1` | 4 | 4 | β€” | caption: '**{{nist\|NIST}}-F1**, the caesium fountain atomic clock th | -| `SPEKE` | 4 | 2 | β€” | amic-link-key\|Dynamic Link Key}}** with SPEKE-over-{{curve25519\|Curve25519}} removes | -| `MAI` | 4 | 1 | β€” | the upstream took it.", mistake: "MAI Network Services ({{autonomous-system\|A | -| `PCCW` | 4 | 1 | β€” | ocally. But Pakistan Telecom's upstream PCCW ({{autonomous-system\|AS}} 3491) had no | -| `IKEA` | 4 | 2 | β€” | azon, Samsung, Aqara, Eve, Philips Hue, IKEA, Schlage, Yale, and dozens more.' } | -| `MUST` | 3 | 2 | β€” | t of [[ip\|IP]]."** Every [[ip\|IP]] host MUST answer Echo Requests by spec. Dropping | -| `RS-232` | 3 | 2 | β€” | pposed to be the wire that replaced the RS-232 cable to a mobile-phone headset. Thirty | -| `S1` | 3 | 3 | β€” | ss network}} and the core (N2/N3 in 5G, S1 in {{lte\|LTE}}) is wrapped in [[ipsec\|I | -| `CONNECTED` | 3 | 3 | β€” | connection state machine β€” \`RRC_IDLE β†’ CONNECTED β†’ INACTIVE\` for 5G β€” and **{{nas\|NAS}} | -| `ET` | 3 | 2 | β€” | text: 'On **22 February 2024 at 03:30 ET**, AT&T Mobility customers across the U | -| `AST` | 3 | 2 | β€” | }}\'s Globalstar partnership and AT&T's AST SpaceMobile follow similar patterns. Re | -| `UDP/5353` | 3 | 2 | β€” | -local {{multicast\|multicast}} group on UDP/5353, with a probe/announce/respond/goodbye | -| `RX` | 3 | 1 | β€” | n. The car (multiple anchors typically) RX-timestamps at t2, delays by `T_reply1` | -| `PARTNER.COM` | 3 | 1 | β€” | XAMPLE.COM wants to access a service in PARTNER.COM, her {{kerberos-kdc\|KDC}} issues a **re | -| `PR` | 3 | 3 | β€” | ded-clients DoS in 0.9-rc2 was fixed in PR #808.', source: { url: 'https:// | -| `NIO` | 3 | 2 | β€” | lone, including the first Chinese OEMs (NIO, XPENG, Geely group brands). Devices mu | -| `XPENG` | 3 | 2 | β€” | including the first Chinese OEMs (NIO, XPENG, Geely group brands). Devices must supp | -| `T2` | 3 | 2 | β€” | Server records when the packet arrives (T2) and when it sends the reply (T3). Both | -| `SIZE` | 2 | 2 | β€” | he sentinel and uses an authoritative \`SIZE\` field. [[amqp\|AMQP]] itself adds no a | -| `GA` | 2 | 1 | β€” | protocol', text: '**RabbitMQ 4.0 GA (18 September 2024)** made [[amqp\|AMQP] | -| `KIP-1150` | 2 | 1 | β€” | ess Topics β€” KIP-1150', text: '**KIP-1150 "Diskless Topics"** was accepted by the | -| `S3` | 2 | 1 | β€” | less / Bufstream architecture that uses S3 as primary storage. Brokers become {{st | -| `MD` | 2 | 1 | β€” | lorado Springs, Philadelphia, Rockville MD, San Francisco), with {{apple\|Apple}}, | -| `VSX` | 2 | 2 | β€” | ', caption: 'A **Polycom VSX 7000** video-conferencing system β€” the | -| `IIS` | 2 | 2 | β€” | which was created in 1995 by Fraunhofer IIS for **WinPlay3** and popularised by **N | -| `TV` | 2 | 2 | β€” | y Netflix stream, every {{apple\|Apple}} TV {{broadcast\|broadcast}} β€” still starts | -| `EXT-X-PRELOAD-HINT` | 2 | 2 | β€” | ttp2\|HTTP/2]] push requirement with **\`EXT-X-PRELOAD-HINT\`** β€” a simpler, {{cdn\|CDN}}-friendly h | -| `UCLA` | 2 | 2 | β€” | -node network that became the internet. UCLA, SRI, UCSB, and Utah; one {{imp\|IMP}} p | -| `SRI` | 2 | 2 | β€” | network that became the internet. UCLA, SRI, UCSB, and Utah; one {{imp\|IMP}} per si | -| `ISI` | 2 | 2 | β€” | '[[pioneer:jon-postel\|Jon Postel]] at ISI. He edited [[rfc:791\|RFC 791]] ([[ip\|IP | -| `L7` | 2 | 2 | β€” | n the registry. The first genuinely new L7 protocol since [[websockets\|WebSockets] | -| `WS` | 2 | 2 | β€” | dern protocol history. His core line: *"WS-\* bad"* β€” shorthand among {{ietf\|IETF} | -| `INACTIVE` | 2 | 2 | β€” | tate machine β€” \`RRC_IDLE β†’ CONNECTED β†’ INACTIVE\` for 5G β€” and **{{nas\|NAS}}** carries | -| `AMPS` | 2 | 2 | β€” | [cellular\|cellular]]** β€” from 1G analog AMPS / TACS / NMT in the early 1980s through | -| `NFC-A` | 2 | 2 | β€” | e flavours on the air', text: '**NFC-A** ({{iso\|ISO}} 14443-A): {{pcd\|PCD}}β†’{{ | -| `OOK` | 2 | 2 | β€” | ed-Miller; {{picc\|PICC}}β†’{{pcd\|PCD}} is OOK Manchester on the 847.5 kHz subcarrier. | -| `NFC-B` | 2 | 2 | β€” | Base rate 106 kbit/s, scaling to 848. **NFC-B** ({{iso\|ISO}} 14443-B): {{pcd\|PCD}}β†’{{ | -| `NRZ-L` | 2 | 2 | β€” | cc\|PICC}} is 10% {{ask-modulation\|ASK}} NRZ-L; {{picc\|PICC}}β†’{{pcd\|PCD}} is {{bpsk\|BP | -| `JIS` | 2 | 2 | β€” | assports. **{{nfc-f\|NFC-F}}** (FeliCa / JIS X 6319-4): 212/424 kbit/s Manchester-co | -| `PASMO` | 2 | 2 | β€” | nt in Japan {{transit\|transit}} (Suica, PASMO) and Hong Kong (Octopus). **{{nfc-v\|NFC | -| `ETH` | 2 | 2 | β€” | u, Giovanni Camurati, and colleagues at ETH ZΓΌrich published **Ghost Peak** β€” an at | -| `D03` | 2 | 2 | β€” | eee-802-15-4\|IEEE}} 802.15.4ab** (Draft D03 September 2025, ratification expected e | -| `ABI` | 2 | 2 | β€” | eness of [[uwb\|UWB]] into one purchase. ABI projects [[uwb\|UWB]] phone penetration | -| `PRO` | 2 | 2 | β€” | '[[zigbee\|IEEE 802.15.4 mesh]], Zigbee PRO R23 ({{dynamic-link-key\|Dynamic Link Ke | -| `RTSP` | 2 | 2 | β€” | mber 2025)**, with camera streaming via RTSP, removing the last category that previo | -| `OASIS` | 2 | 2 | β€” | ce the protocol and shepherd it through OASIS standardization.', imagePath: | -| `CEO` | 2 | 2 | β€” | oyed [[amqp\|AMQP]] broker. Later became CEO of Weaveworks, bringing messaging patte | -| `TIBCO` | 2 | 2 | β€” | rneyed from Wall Street trading floors (TIBCO) to IoT sensors ([[mqtt\|MQTT]]) to clou | -| `DIX` | 2 | 1 | β€” | c\|Xerox PARC}} in 1973, co-authored the DIX [[ethernet\|Ethernet]] standard (1980), | -| `DEC` | 2 | 2 | β€” | t infrastructure', caption: "The DEC PDP-11 β€” machines like these ran early | -| `BIND` | 2 | 2 | β€” | urity', contribution: 'Wrote BIND, the most widely deployed [[dns\|DNS]] s | -| `HTML5` | 2 | 2 | β€” | sse\|Server-Sent Events]] as part of the HTML5 specification, enabling simple server-t | -| `CMOS` | 2 | 2 | β€” | sh engineer who owned the analog RF and CMOS implementation work that paired with Ja | -| `IC` | 2 | 2 | β€” | Jaap Haartsen\'s digital baseband. The IC-level decisions that made [[bluetooth\|B | -| `FR2` | 2 | 2 | β€” | flexible numerology, {{mmwave\|mmWave}} (FR2) support, network slicing. First commer | -| `RTT` | 2 | 2 | β€” | Adopted 3 September 2024. Phase-based + RTT distance measurement on a new {{le-audi | -| `H1/H2` | 2 | 2 | β€” | m\|Broadcom}}, Qualcomm, {{apple\|Apple}} H1/H2) uses **time-division arbitration** at | -| `SMTPS` | 2 | 1 | β€” | ication protocols transparently (HTTPS, SMTPS); [[ssh\|SSH]] provides an encrypted cha | -| `RTMPS` | 2 | 2 | β€” | aps [[rtmp\|RTMP]] connections to create RTMPS, encrypting live stream ingest traffic | -| `MB` | 2 | 2 | β€” | r packet is **1460 bytes**. Sending a 1 MB file means roughly 685 packets. {{path- | -| `NSFNET` | 2 | 2 | β€” | 1986 the same architecture was carrying NSFNET traffic across the country β€” and the bu | -| `UC` | 2 | 2 | β€” | ffers between Lawrence Berkeley Lab and UC Berkeley, three hops apart, were where | -| `RACK-TLP` | 2 | 2 | β€” | ubic\|CUBIC}}, {{bbr\|BBR}}, {{l4s\|L4S}}, RACK-TLP β€” are each refinements of the same cons | -| `HPC` | 2 | 2 | β€” | rnet\|Ethernet]]+[[ip\|IP]] for {{ai\|AI}}/HPC scale-out: {{connectionless\|connectionl | -| `CBC` | 2 | 2 | β€” | }} key {{exchange\|exchange}}, and every CBC-mode cipher β€” keeping only {{chacha20-p | -| `BEAST` | 2 | 2 | β€” | been weaponised in a published attack (BEAST, CRIME, BREACH, Lucky 13, FREAK, Logjam | -| `CRIME` | 2 | 2 | β€” | eaponised in a published attack (BEAST, CRIME, BREACH, Lucky 13, FREAK, Logjam, ROBOT | -| `BREACH` | 2 | 2 | β€” | ed in a published attack (BEAST, CRIME, BREACH, Lucky 13, FREAK, Logjam, ROBOT, …). [[ | -| `FREAK` | 2 | 2 | β€” | attack (BEAST, CRIME, BREACH, Lucky 13, FREAK, Logjam, ROBOT, …). [[tls\|TLS]] 1.3 als | -| `ROBOT` | 2 | 2 | β€” | CRIME, BREACH, Lucky 13, FREAK, Logjam, ROBOT, …). [[tls\|TLS]] 1.3 also reduced the { | -| `OBS` | 2 | 2 | β€” | eam ingest}}** protocol β€” your encoder (OBS, Wirecast) pushes a long-lived [[tcp\|TC | -| `STD` | 2 | 2 | β€” | tra\|Dijkstra]] ([[rfc:2328\|RFC 2328]] / STD 54).', steps: { 0: '{{ospf-hello\|H | -| `CTR` | 2 | 2 | β€” | t}}; **{{sts\|STS}}** is the {{aes\|AES}}-CTR-generated pulse pattern that makes the | -| `WHERE` | 2 | 1 | β€” | transition: 'The browser now knows WHERE the server lives β€” but packets on the i | -| `FSCI` | 2 | 2 | β€” | TS}}** declaring its frame-size budget (FSCI=5 = 64 bytes max). Both ends now know h | -| `FCI` | 2 | 2 | β€” | } `2PAY.SYS.DDF01`). The eSE returns an FCI Template listing every payment {{aid\|AI | -| `PROCESSING` | 2 | 2 | β€” | gram', description: "After GET PROCESSING OPTIONS (returning AIP+{{afl\|AFL}}) and | -| `CDOL1` | 2 | 2 | β€” | nerate-ac\|GENERATE AC}} with the filled CDOL1 data. The eSE composes the inputs (amou | -| `QR` | 2 | 2 | β€” | e}} (printed on the Hue bulb's box as a QR code), that link key is unique and an e | -| `CVSS` | 2 | 2 | β€” | on the public internet were vulnerable. CVSS 7.5 (high). Operators scrambled to patc | -| `CID` | 2 | 1 | β€” | att-mtu\|ATT}}) lives on {{l2cap\|L2CAP}} CID 0x0004 and provides read/write/notify/i | -| `LTK` | 2 | 1 | β€” | Curve P-256 to derive a Long-Term Key (LTK); the link is then {{encryption\|encrypt | -| `CIS` | 2 | 1 | β€” | nels** β€” Connected Isochronous Streams (CIS) for {{unicast\|unicast}} earbuds/hearin | -| `LL` | 2 | 1 | β€” | scription: 'Two devices in a normal LL connection schedule **{{channel-soundin | -| `NCC` | 2 | 2 | β€” | s the protocol-level answer to the 2022 NCC Group {{ble\|BLE}} relay attack that ope | -| `GFSK` | 2 | 1 | β€” | s over the air**. Different modulation (GFSK + DPSK for Classic, GFSK only for {{ble | -| `PB` | 2 | 1 | β€” | }} by Q3 2025; the network averages 6.5 PB/day. The first proof that a hyperscale | -| `NR` | 2 | 1 | β€” | ecified in Release 17 (2022), the first NR-{{ntn\|NTN}} deployments shipped in late | -| `USA` | 2 | 1 | β€” | numbering plan: 234/235 = UK, 310–316 = USA, 460 = China, 405 = India, 440–441 = Ja | -| `X2` | 2 | 2 | β€” | *mandate** [[ipsec\|IPsec]] on every S1, X2, N2, N3, Xn, F1, and E1 interface. Forg | -| `N2` | 2 | 2 | β€” | date** [[ipsec\|IPsec]] on every S1, X2, N2, N3, Xn, F1, and E1 interface. Forgetti | -| `N3` | 2 | 2 | β€” | ** [[ipsec\|IPsec]] on every S1, X2, N2, N3, Xn, F1, and E1 interface. Forgetting t | -| `E1` | 2 | 2 | β€” | ]] on every S1, X2, N2, N3, Xn, F1, and E1 interface. Forgetting this in a private | -| `SOA` | 2 | 1 | β€” | pex must also have {{ns-record\|NS}} and SOA records. Some [[dns\|DNS]] providers off | -| `NXDOMAIN` | 2 | 1 | β€” | g can hurt', text: 'Resolvers cache NXDOMAIN responses based on the SOA minimum fiel | -| `UDP/4500` | 2 | 1 | β€” | {{security-association\|SA}} switches to UDP/4500 {{encapsulation\|encapsulation}}. Two me | -| `MOBIKE` | 2 | 1 | β€” | me routers don\'t corrupt the packet. **MOBIKE** ([[rfc:4555\|RFC 4555]]) lets a roadwa | -| `SKU` | 2 | 2 | β€” | (10 Gbps aggregate on the AZ-redundant SKU), {{gcp\|GCP}} Cloud {{vpn\|VPN}}, OCI Si | -| `AS-REQ` | 2 | 1 | β€” | description: 'Client sends an **AS-REQ** to the {{kerberos-kdc\|KDC}}\'s Authen | -| `TGS-REP` | 2 | 1 | β€” | ion key for Alice↔web1, and returns a **TGS-REP** with a **service ticket** encrypted u | -| `GSS` | 2 | 1 | β€” | y speak Kerberos directly. They speak **GSS-{{api\|API}}** (Generic Security Service | -| `SPNEGO` | 2 | 1 | β€” | ntext\` / \`gss_accept_sec_context\`. **SPNEGO** ([[rfc:4178\|RFC 4178]]) is the protoc | -| `PKINIT` | 2 | 1 | β€” | gust 2025 release. Headline features: **PKINIT {{ecdh\|ECDH}}/EC certs** (smart-card au | -| `DES` | 2 | 1 | β€” | IT}}-internal for years because it used DES β€” and DES exports required State Depart | -| `FF02` | 2 | 2 | β€” | s* on \`224.0.0.251\` ([[ipv6\|IPv6]]: \`FF02::FB\`). Two flag bits get repurposed: t | -| `SD` | 2 | 2 | β€” | cription: "A {{dns-resolution\|DNS}}-SD client looking for printers sends a {{p | -| `SRP` | 2 | 1 | β€” | col) published', description: '**SRP** ({{rfc-doc\|RFC}} 9665, Lemon + [[pion | -| `LLMNR` | 2 | 1 | β€” | th [[mdns-dns-sd\|mDNS]] **enabled** and LLMNR **disabled** in the security baseline. | -| `IGMP` | 2 | 1 | β€” | e (often 6 Mbps); managed switches with IGMP snooping enabled drop frames whose list | -| `WLC` | 2 | 2 | β€” | -dns-sd\|mDNS]] gateway ({{cisco\|Cisco}} WLC `mdns-sd` profile, Aruba AirGroup, Aero | -| `DERP` | 2 | 2 | β€” | path between peers; their proprietary **DERP** relays absorb the rest as a {{turn\|TU | -| `CTO` | 2 | 2 | β€” | turn\|TURN}}, and {{ice\|ICE}}. Currently CTO + Head of {{ai\|AI}} at Five9.' } ], | -| `T2T` | 2 | 1 | β€” | ate frame size (FSCI) and timing (FWI). T2T cards skip {{rats\|RATS}} and go straigh | -| `TC` | 2 | 2 | β€” | } β€” either an {{arqc\|ARQC}} (online) or TC (offline). The cryptogram is signed in | -| `TNF` | 2 | 1 | β€” | ifier\|ID}} Length present), and a 3-bit TNF (Type Name Format: 0=Empty, 1=Well-Know | -| `IEC` | 2 | 1 | β€” | {ndef\|NDEF}} was formally adopted as an IEC standard in **March 2026** alongside NF | -| `HID` | 2 | 2 | β€” | }}, Allegion, Aqara, {{google\|Google}}, HID, Kastle, Kwikset, Last Lock, Nordic, Nu | -| `EV3` | 2 | 1 | β€” | Plus in **2011**, DESFire EV2 in 2016, EV3 in the early 2020s. The Classic Crypto1 | -| `GM` | 2 | 2 | β€” | is, Audi (new in 2025), Volvo, Porsche, GM, Ford, plus a wave of Chinese OEMs (NIO | -| `DDA/CDA` | 2 | 1 | β€” | eturns an AIP byte that signals whether DDA/CDA is supported. A common custom-{{hce\|HCE | -| `RRP` | 2 | 1 | β€” | gram\|EMV}} **Relay Resistance Protocol (RRP)** in Kernel 2 v2.6+ binds round-trip t | -| `T1` | 2 | 1 | β€” | DP]] packet with its current timestamp (T1). The packet is tiny β€” 48 bytes.' }, | -| `T3` | 2 | 1 | β€” | rives (T2) and when it sends the reply (T3). Both timestamps are included in the r | -| `T4` | 2 | 1 | β€” | ient records when the response arrives (T4). Now it has four timestamps: T1 (sent) | -| `NBMA` | 2 | 1 | β€” | default 10 s on point-to-point, 30 s on NBMA). Hellos carry the router\'s {{id-ident | -| `HPRF` | 2 | 1 | β€” | Hz** in the default 802.15.4z mode or **HPRF 124.8 / 249.6 MHz** in higher-power mod | -| `RTLS` | 2 | 1 | β€” | f arrival β€” used for warehouse/hospital RTLS where anchors are wired. **AoA / PDoA:* | -| `EN` | 2 | 1 | β€” | Hz** across 3.1–10.6 GHz. {{etsi\|ETSI}} EN 302 065 in Europe is similar with stric | -| `AR` | 2 | 1 | β€” | ision Finding, BMW Digital Key, and the AR experiences in {{apple\|Apple}} Vision P | -| `T2024` | 2 | 1 | β€” | 1-chip\|U1}}'s 16 nm), internal codename T2024, part number 339M00298. **1.5Γ— longer P | -| `U400` | 2 | 1 | β€” | amsung wallets. First products: **Aqara U400** (first smart lock with UWB; {{aliro\|A | -| `S21` | 2 | 1 | β€” | \|Apple}} UWB tracker. Works with Galaxy S21+ / S21 Ultra / Note 20 Ultra / S22/S23/ | -| `DW3000` | 2 | 1 | β€” | upports only Channel 5; everything from DW3000 / {{nxp\|NXP}} SR150 / {{apple\|Apple}} { | -| `SR150` | 2 | 1 | β€” | 5; everything from DW3000 / {{nxp\|NXP}} SR150 / {{apple\|Apple}} {{u1-chip\|U1}} onward | -| `NLOS` | 2 | 1 | β€” | ns = 30 cm, but in **non-line-of-sight (NLOS)** conditions through walls/people/meta | -| `ACL` | 2 | 1 | β€” | r which destination prefix) **and** the ACL (inbound: only accept packets from this | -| `TSPU` | 2 | 1 | β€” | mimicry', description: "Russia's TSPU boxes learned to fingerprint and drop s | -| `S1/S2` | 2 | 1 | β€” | H4 ranges instead of fixed 1–4), random S1/S2 padding. AWG 2.0 adds optional QUIC/{{d | -| `WARP` | 2 | 1 | β€” | are}}'s consumer {{vpn\|VPN}} (1.1.1.1 + WARP app) runs on **BoringTun**, {{cloudflar | -| `OTA` | 2 | 1 | β€” | ntrol = 0x0008, Color Control = 0x0300, OTA Upgrade = 0x0019), and an **APSCounter* | -| `FOSS` | 2 | 1 | β€” | and *no* microphone or camera. For the FOSS path the answer is **zigbee2mqtt** by K | -| `PSU` | 2 | 1 | β€” | ble Zigbee β€” the router's switched-mode PSU emits broadband 2.4 GHz noise." } ], | -| `CC2652` | 2 | 1 | β€” | dresden elektronik ConBee II, or any TI CC2652 stick β€” the radio is abstracted behind | -| `SES` | 2 | 1 | β€” | 3 December 2024** VusionGroup (formerly SES-imagotag) announced acceleration of dig | -| `ESL` | 2 | 1 | β€” | 500 stores. Vusion shipped 350 million ESLs in 2023 alone; the EdgeSense platform r | -| `AIR` | 2 | 1 | β€” | ', description: "Acuity's nLight AIR and Atrius lines are the dominant Zigbe | -| `SUN` | 2 | 1 | β€” | and later directed standards at the Wi-SUN Alliance. Almost every low-power 802.15 | -| `VSAT` | 1 | 1 | β€” | llips 66 oil pipelines over a brand-new VSAT satellite link. The 2-byte fixed header | -| `PINGREQ` | 1 | 1 | β€” | ixed header**, smallest control packet (PINGREQ) is 2 bytes total. Designed in 1999 by | -| `JMS` | 1 | 1 | β€” | sia is removed. RabbitMQ 4.3 also added JMS-style queues with {{sql\|SQL}} message s | -| `NETSCOUT` | 1 | 1 | β€” | { kind: 'pull-quote', text: 'NETSCOUT\'s January 2019 scan found 388,344 publ | -| `QLC` | 1 | 1 | β€” | ey were Chinese smartphones running the QLC Chain {{peer-to-peer\|peer-to-peer}} cry | -| `EDHOC` | 1 | 1 | β€” | messages, ~100 bytes', text: '**EDHOC ([[rfc:9000\|RFC 9528]], March 2024)** β€” | -| `DH` | 1 | 1 | β€” | sages totalling ~100 bytes** for static-DH credentials, vs **~700+ bytes for a {{d | -| `OSCORE` | 1 | 1 | β€” | years* of additional life. Companion: **OSCORE ([[rfc:8613\|RFC 8613]])** wraps the [[c | -| `DNA` | 1 | 1 | β€” | g router carries the same architectural DNA: a control plane that builds the {{rout | -| `PREF64` | 1 | 1 | β€” | clients "skip [[ip\|IPv4]] entirely," **PREF64 in Router Advertisements ([[rfc:8781\|RF | -| `RIR` | 1 | 1 | β€” | {{roa\|ROA}} set. Lesson: enforce 2FA on RIR portals.', attribution: 'Author' | -| `OTC` | 1 | 1 | β€” | fc:9234\|RFC 9234]] ([[bgp\|BGP]] Roles + OTC) ate its lunch. The lesson: a security | -| `MW` | 1 | 1 | β€” | nal pluggable optics would consume ~180 MW of power for the optics alone. That is | -| `X1600` | 1 | 1 | β€” | AI}} workloads. **{{spectrum\|Spectrum}}-X1600 (102.4 Tbps)** is expected 2H 2026.' | -| `GB200` | 1 | 1 | β€” | ption: 'The **{{nvidia\|NVIDIA}} GB200 NVL72** Blackwell-architecture rack on | -| `NVL72` | 1 | 1 | β€” | 'The **{{nvidia\|NVIDIA}} GB200 NVL72** Blackwell-architecture rack on displa | -| `COMPUTEX` | 1 | 1 | β€” | ackwell-architecture rack on display at COMPUTEX 2024 β€” the kind of {{ai\|AI}}-training e | -| `WECA` | 1 | 1 | β€” | as a tagline retrofitted briefly by the WECA board and dropped. The yin-yang logo is | -| `OET` | 1 | 1 | β€” | on **23 February 2024** the {{fcc\|FCC}} OET approved **seven {{afc\|AFC}} system ope | -| `RUCKUS` | 1 | 1 | β€” | d [[wifi\|Wi-Fi]] 7 {{access-point\|AP}} (RUCKUS R770) was certified 16 April 2024.** Bu | -| `R770` | 1 | 1 | β€” | i\|Wi-Fi]] 7 {{access-point\|AP}} (RUCKUS R770) was certified 16 April 2024.** But on | -| `SINR` | 1 | 1 | β€” | squeezes for **+25% throughput at given SINR, βˆ’25% 95th-percentile {{latency\|latency | -| `MPDU` | 1 | 1 | β€” | th-percentile {{latency\|latency}}, βˆ’25% MPDU loss across {{bss-coloring\|BSS}} transi | -| `CS168` | 1 | 1 | β€” | P]] stack), {{mit\|MIT}} 6.829, Berkeley CS168.', slots: [ { kind: 'prose' | -| `PARC` | 1 | 1 | β€” | still runs the original spec. The 1973 PARC sketch and a 2025 Ultra [[ethernet\|Ethe | -| `KU` | 1 | 1 | β€” | , text: '**Mathy Vanhoef and the KU Leuven team have broken [[wifi\|Wi-Fi]] | -| `DCP` | 1 | 1 | β€” | rote [[rfc:826\|RFC 826]] from address \`DCP@{{mit\|MIT}}-MC\` in November 1982. **ST | -| `MC` | 1 | 1 | β€” | FC 826]] from address \`DCP@{{mit\|MIT}}-MC\` in November 1982. **STD 37 has never | -| `L2` | 1 | 1 | β€” | xt: '[[arp\|ARP]] relies entirely on the L2 {{checksum\|frame check sequence}} β€” no | -| `BRL` | 1 | 1 | β€” | rote {{ping\|ping}} in a single night at BRL Aberdeen in December 1983, named after | -| `TOPS-20` | 1 | 1 | β€” | st server was named *Jeeves* and ran on TOPS-20.', credit: 'Image: Wikimedia Com | -| `KEX` | 1 | 1 | β€” | llo\|ServerHello}}/Finished, [[ssh\|SSH]] KEX, [[mqtt\|MQTT]] {{mqtt-connect\|CONNECT}} | -| `CONNACK` | 1 | 1 | β€” | [[mqtt\|MQTT]] {{mqtt-connect\|CONNECT}}/CONNACK, [[sctp\|SCTP]]\'s four-way {{cookie\|Coo | -| `DAVE` | 1 | 1 | β€” | on a whiteboard in 2018." Discord\'s **DAVE protocol** (deployed 1 March 2026) laye | -| `MLS` | 1 | 1 | β€” | otocol** (deployed 1 March 2026) layers MLS keys + SFrame on top of [[rtp\|RTP]]/{{s | -| `E2EE` | 1 | 1 | β€” | on top of [[rtp\|RTP]]/{{srtp\|SRTP}} for E2EE voice across **2.5 million concurrent u | -| `M120` | 1 | 1 | β€” | AV1}} hardware encode shipped in Chrome M120 (Dec 2023). Firefox 125 added {{av1\|AV1 | -| `EME` | 1 | 1 | β€” | ec 2023). Firefox 125 added {{av1\|AV1}}+EME in April 2024. But the royalty-free cla | -| `CMAF` | 1 | 1 | β€” | ate ladders of small .ts (or now .mp4 / CMAF) segments; a {{cdn\|CDN}} serves them ov | -| `ISDN` | 1 | 1 | β€” | four wholesale rewrites later (analog β†’ ISDN β†’ [[rtp\|RTP]]/H.323 β†’ [[webrtc\|WebRTC]] | -| `PRNET/SATNET` | 1 | 1 | β€” | et\|ARPANET}}), and unreliable wireless (PRNET/SATNET) each forced different design pressures | -| `UCSB` | 1 | 1 | β€” | rk that became the internet. UCLA, SRI, UCSB, and Utah; one {{imp\|IMP}} per site.', | -| `EDGE` | 1 | 1 | β€” | d on 29 June 2007 with [[wifi\|Wi-Fi]] + EDGE; the App Store followed in July 2008; { | -| `GIGA` | 1 | 1 | β€” | ple}} {{os\|OS}} services, Korea Telecom GIGA Path, some specialised enterprise WANs) | -| `CA` | 1 | 1 | β€” | te-authority\|CA}} signs an intermediate CA, which signs the end-entity {{certifica | -| `SIGALRM` | 1 | 1 | β€” | {{linux\|Linux}}. Signal-handler race: \`SIGALRM\` handler calls \`syslog()\` (not async | -| `UNIX` | 1 | 1 | β€” | er than {{arpanet\|ARPANET}}, older than UNIX, older than every other timestamp stand | -| `Y2036` | 1 | 1 | β€” | it and will need fixes before 2036. The Y2036 work has been quietly underway since 20 | -| `SNDMSG` | 1 | 1 | β€” | picked the **@** sign in 1971 modifying SNDMSG. [[pioneer:jon-postel\|Jon Postel]] publ | -| `DCE` | 1 | 1 | β€” | a 40-year lineage of Sun {{rpc\|RPC}} / DCE / CORBA / Thrift. The client *stub* ser | -| `CORBA` | 1 | 1 | β€” | year lineage of Sun {{rpc\|RPC}} / DCE / CORBA / Thrift. The client *stub* serialises | -| `NTIA` | 1 | 1 | β€” | d States Frequency Allocations Chart**, NTIA. Every coloured stripe is a *service* β€” | -| `WPA` | 1 | 1 | β€” | \|OOB}} key or the Wi-Fi {{ssid\|SSID}} + WPA key in an {{ndef\|NDEF}} record. **[[zig | -| `MIMO` | 1 | 1 | β€” | 11]] β€” {{csma-ca\|CSMA/CA}} in practice, MIMO β†’ {{ofdma\|OFDMA}} β†’ {{mlo\|MLO}}, and th | -| `DIFS` | 1 | 1 | β€” | of the {{airtime\|airtime}} is spent on DIFS gaps, {{ack\|ACK}} frames, beacons, and | -| `NB` | 1 | 1 | β€” | volte\|VoLTE}} / [[wifi\|Wi-Fi]] calling, NB-IoT / {{lte\|LTE}}-M, satellite {{direct | -| `N2/N3` | 1 | 1 | β€” | an\|radio access network}} and the core (N2/N3 in 5G, S1 in {{lte\|LTE}}) is wrapped in | -| `IOS` | 1 | 1 | β€” | teffen]]\'s strongSwan, {{cisco\|Cisco}} IOS, and Juniper {{junos\|Junos}} run more [ | -| `TACS` | 1 | 1 | β€” | ar\|cellular]]** β€” from 1G analog AMPS / TACS / NMT in the early 1980s through 2G {{g | -| `NMT` | 1 | 1 | β€” | ular]]** β€” from 1G analog AMPS / TACS / NMT in the early 1980s through 2G {{gsm\|GSM | -| `IS-95` | 1 | 1 | β€” | he early 1980s through 2G {{gsm\|GSM}} / IS-95, 3G {{wcdma\|WCDMA}} / CDMA2000, 4G {{lt | -| `CDMA2000` | 1 | 1 | β€” | gsm\|GSM}} / IS-95, 3G {{wcdma\|WCDMA}} / CDMA2000, 4G {{lte\|LTE}}, and {{5g-nr\|5G NR}}. E | -| `SYS.DDF01` | 1 | 1 | β€” | t System Environment {{aid\|AID}} \`2PAY.SYS.DDF01\` β€” and the card returns an FCI listing | -| `A0000000041010` | 1 | 1 | β€” | The reader picks one (e.g. Mastercard \`A0000000041010\`), SELECTs it, gets back a {{pdol\|PDOL | -| `TX` | 1 | 1 | β€” | *can* be cheated β€” a relay with enough TX power makes a distant device look near. | -| `PAL` | 1 | 1 | β€” | iority), **Priority Access Licensees** (PALs, auctioned in 2020 for ~$4.5B), and **G | -| `PMSE` | 1 | 1 | β€” | has experimented with similar concepts (PMSE in the UK, {{lsa\|LSA}} in some EU pilot | -| `PIE` | 1 | 1 | β€” | {{aqm\|Active Queue Management}} (CoDel, PIE, fq_codel) and algorithms like {{bbr\|BB | -| `SCADA` | 1 | 1 | β€” | on: "Brought embedded systems and SCADA expertise to [[mqtt\|MQTT]]'s design. Co | -| `CBOR` | 1 | 1 | β€” | oap\|CoAP]] specification and co-created CBOR, the efficient binary {{serialization\|s | -| `NATS` | 1 | 1 | β€” | o cloud-native microservices ([[amqp]], NATS, [[kafka]]). Today, it's one of the mos | -| `P802` | 1 | 1 | β€” | on 100 G lanes). The 1.6 TbE follow-up (P802.3dj, 200 G/lane) targets July 2026 β€” dr | -| `LO` | 1 | 1 | β€” | two months before the first successful "LO" transmission to SRI.', credit: 'Pho | -| `PDP-11` | 1 | 1 | β€” | frastructure', caption: "The DEC PDP-11 β€” machines like these ran early [[ntp\|N | -| `POWER` | 1 | 1 | β€” | reads "This machine is a server. DO NOT POWER IT DOWN!!"', credit: 'Photo: Coolcae | -| `DOWN` | 1 | 1 | β€” | is machine is a server. DO NOT POWER IT DOWN!!"', credit: 'Photo: Coolcaesar / CC | -| `AAIF` | 1 | 1 | β€” | es to the Agentic {{ai\|AI}} Foundation (AAIF) and [[a2a\|A2A]] launches as a {{linux\| | -| `RF` | 1 | 1 | β€” | 'Swedish engineer who owned the analog RF and CMOS implementation work that paire | -| `COMDEX` | 1 | 1 | β€” | product (a hands-free headset) ships at COMDEX 1999.', protocolId: 'bluetooth' | -| `SC-FDMA` | 1 | 1 | β€” | preading codes for an {{ofdma\|OFDMA}} + SC-FDMA air interface β€” the clean-sheet radio d | -| `IQ` | 1 | 1 | β€” | ble delivery of presence, messages, and IQ queries.', howTheyWork: 'An [[xmpp | -| `AMQPS` | 1 | 1 | β€” | aps [[amqp\|AMQP]] connections to create AMQPS, encrypting all {{broker\|message broker | -| `MQTTS` | 1 | 1 | β€” | aps [[mqtt\|MQTT]] connections to create MQTTS, encrypting all pub/sub messaging betwe | -| `SIPS` | 1 | 1 | β€” | SIP]] {{signaling\|signaling}} to create SIPS, encrypting call setup, authentication, | -| `WSS` | 1 | 1 | β€” | ckets\|WebSocket]] connections to create WSS (wss://), encrypting the {{full-duplex\| | -| `M3U8` | 1 | 1 | β€” | LS]] delivers adaptive video by serving M3U8 playlists and media segments as standar | -| `BOSH` | 1 | 1 | β€” | network without long-polling hacks like BOSH.', howTheyWork: 'The browser opens | -| `PROXY` | 1 | 1 | β€” | ess you explicitly forward it via the **PROXY protocol** or an {{header\|HTTP header}} | -| `ARPA` | 1 | 1 | β€” | down in 1986.', caption: 'The ARPA Network in September 1973, a few dozen | -| `DHT` | 1 | 1 | β€” | Torrent uses centralised trackers (or a DHT, which is a decentralised tracker) to b | -| `SHA384` | 1 | 1 | β€” | DigiCert [[tls\|TLS]] Hybrid {{ecc\|ECC}} SHA384 β†’ DigiCert Global Root G3\`. Only the b | -| `G3` | 1 | 1 | β€” | ecc\|ECC}} SHA384 β†’ DigiCert Global Root G3\`. Only the bottom (root) {{certificate | -| `SIGTRAN` | 1 | 1 | β€” | under telecom {{signaling\|signaling}} (SIGTRAN) and [[webrtc\|WebRTC]] data channels ([ | -| `WHATWG` | 1 | 1 | β€” | only need {{server-push\|server push}} (WHATWG).', steps: { 0: 'Standard [[http1\| | -| `OMA` | 1 | 1 | β€” | App, and the {{matter\|Matter}}-adjacent OMA-LwM2M IoT stack. Encrypted via {{startt | -| `CQRS` | 1 | 1 | β€” | tream processing}}, event sourcing, and CQRS. **{{exactly-once-delivery\|Exactly-once | -| `T1/T2/T3/T4` | 1 | 1 | β€” | timestamps per {{exchange\|exchange}}** (T1/T2/T3/T4) which cancel out network {{latency\|lat | -| `TGS` | 1 | 1 | β€” | ey Distribution Center, split into AS + TGS), and Service. Two {{encryption\|encrypt | -| `SEND` | 1 | 1 | β€” | ONNECT}}, {{mqtt-subscribe\|SUBSCRIBE}}, SEND, and {{ack\|ACK}} are self-explanatory, | -| `ERP` | 1 | 1 | β€” | ing queue, maintenance data goes to the ERP integration queue, and raw telemetry go | -| `VP8` | 1 | 1 | β€” | round rules: which codecs they support (VP8, H.264, Opus), what transport addresses | -| `DANE` | 1 | 1 | β€” | d [[dns\|DNS]]-based authentication like DANE which allows domain owners to {{mqtt-pu | -| `TVR` | 1 | 1 | β€” | the inputs (amount, currency, country, TVR, {{atc\|ATC}}, Unpredictable Number, AIP | -| `POS` | 1 | 1 | β€” | description: "Modern wireless POS terminals (Square, Stripe, Verifone Eng | -| `APPROVED` | 1 | 1 | β€” | sufficient balance + no fraud flag = **APPROVED**. The issuer returns an **ARPC** (Auth | -| `ARPC` | 1 | 1 | β€” | = **APPROVED**. The issuer returns an **ARPC** (Authorisation Response Cryptogram) o | -| `RFRAME` | 1 | 1 | β€” | n: "The phone transmits a **Poll** RFRAME on [[uwb\|UWB]] Channel 9 (7987.2 MHz, 4 | -| `LQI` | 1 | 1 | β€” | icks the best parent by {{rssi\|RSSI}} + LQI. This is the slowest step β€” beacon scan | -| `WITHDRAWAL` | 1 | 1 | β€” | -system\|AS}} 32934 β€” and then a wave of WITHDRAWALs of the [[ip\|IPv4]] and [[ipv6\|IPv6]] pr | -| `SERVFAIL` | 1 | 1 | β€” | ike 1.1.1.1 and 8.8.8.8 start returning SERVFAIL for facebook.com. Apps and humans retry | -| `NANOG` | 1 | 1 | β€” | tion: "Vince Bono's apology email to NANOG that day is preserved in the archives β€” | -| `RIS` | 1 | 1 | β€” | ally for hours. {{ripe-ncc\|RIPE NCC}}'s RIS data became the canonical post-mortem s | -| `LBL` | 1 | 1 | β€” | delivery less likely. Throughput on the LBL-to-UCB path collapsed from 32 kbps to 4 | -| `UCB` | 1 | 1 | β€” | y less likely. Throughput on the LBL-to-UCB path collapsed from 32 kbps to 40 bps β€” | -| `LBL-UCB` | 1 | 1 | β€” | uplicates. Goodput approaches zero. The LBL-UCB path measures 40 bps where it had measu | -| `CT` | 1 | 1 | β€” | limit damage.", mistake: "At 02:42 CT, a network change with an equipment con | -| `GSO` | 1 | 1 | β€” | ff could be split into more than 65,535 GSO segments. The 16-bit counter overflowed | -| `OPEN` | 1 | 1 | β€” | 'Both routers {{exchange\|exchange}} OPEN messages containing their {{autonomous- | -| `NLRI` | 1 | 1 | β€” | messages containing reachable prefixes (NLRI) with path attributes: {{as-path\|AS_PAT | -| `EGP` | 1 | 1 | β€” | Austin. The previous routing protocol (EGP) was unmanageable. They sketched a repl | -| `GTSM` | 1 | 1 | β€” | tcha', text: 'Some operators enable GTSM (Generalised {{ttl\|TTL}} Security Mecha | -| `SBC` | 1 | 1 | β€” | he mandatory {{codec\|codec}} (replacing SBC and saving ~50% battery vs A2DP). **{{a | -| `A2DP` | 1 | 1 | β€” | eplacing SBC and saving ~50% battery vs A2DP). **{{auracast\|Auracast}}** is the {{si | -| `ISOAL` | 1 | 1 | β€” | privacy against long-term tracking) and ISOAL improvements for {{le-audio\|LE Audio}} | -| `EURECOM` | 1 | 1 | β€” | mes', text: "Daniele Antonioli (then EURECOM, now PostDoc-and-faculty) is the lead a | -| `DPSK` | 1 | 1 | β€” | the air**. Different modulation (GFSK + DPSK for Classic, GFSK only for {{ble\|BLE}} | -| `FR1` | 1 | 1 | β€” | two very different deployment regimes (FR1 sub-6 GHz, FR2 {{mmwave\|mmWave}} 24–52 | -| `LLR` | 1 | 1 | β€” | ion}}. The receiver stores soft-decoded LLRs from failed transmissions and combines | -| `RLC` | 1 | 1 | β€” | er compression', description: '**RLC** runs in TM (transparent), UM (unackno | -| `TM` | 1 | 1 | β€” | ', description: '**RLC** runs in TM (transparent), UM (unacknowledged), or | -| `UM` | 1 | 1 | β€” | '**RLC** runs in TM (transparent), UM (unacknowledged), or AM (acknowledged) | -| `AM` | 1 | 1 | β€” | (transparent), UM (unacknowledged), or AM (acknowledged) mode with 10- or 16-bit | -| `PDCP` | 1 | 1 | β€” | ce numbers}} ({{ts-3gpp\|TS}} 38.322). **PDCP** above it ({{ts-3gpp\|TS}} 38.323) does | -| `ROHC` | 1 | 1 | β€” | * above it ({{ts-3gpp\|TS}} 38.323) does ROHC {{header\|header compression}} (squashin | -| `USIM` | 1 | 1 | β€” | hentication vector, and the {{ue\|UE}}'s USIM verifies AUTN and computes RES*. After | -| `AUTN` | 1 | 1 | β€” | ctor, and the {{ue\|UE}}'s USIM verifies AUTN and computes RES*. After Security Mode | -| `RES` | 1 | 1 | β€” | \|UE}}'s USIM verifies AUTN and computes RES*. After Security Mode Command, {{nas\|NA | -| `PCF` | 1 | 1 | β€” | {upf\|UPF}}, {{ausf\|AUSF}}, {{udm\|UDM}}, PCF, NRF, NEF, NSSF, AF β€” each is a **netwo | -| `NRF` | 1 | 1 | β€” | UPF}}, {{ausf\|AUSF}}, {{udm\|UDM}}, PCF, NRF, NEF, NSSF, AF β€” each is a **network fu | -| `NEF` | 1 | 1 | β€” | , {{ausf\|AUSF}}, {{udm\|UDM}}, PCF, NRF, NEF, NSSF, AF β€” each is a **network functio | -| `NSSF` | 1 | 1 | β€” | usf\|AUSF}}, {{udm\|UDM}}, PCF, NRF, NEF, NSSF, AF β€” each is a **network function** wi | -| `AF` | 1 | 1 | β€” | SF}}, {{udm\|UDM}}, PCF, NRF, NEF, NSSF, AF β€” each is a **network function** with a | -| `GPRS` | 1 | 1 | β€” | \|UPF}} travel over **{{gtp-u\|GTP-U}}** (GPRS Tunnelling Protocol β€” User plane) on [[ | -| `ML` | 1 | 1 | β€” | vanced release. New features: {{ai\|AI}}/ML in the air interface (CSI feedback comp | +| Acronym | Count | Files | Suggested ID | Sample | +| -------------------- | ----: | ----: | ------------ | ---------------------------------------------------------------------------------------------------- | +| `FF` | 12 | 2 | β€” | to the {{broadcast\|broadcast}} address (FF:FF:FF:FF:FF:FF) asking "Who has 192.168 | +| `BMW` | 9 | 4 | β€” | t bootstraps {{matter\|Matter}}, unlocks BMWs, and broadcasts public hearing-loops ac | +| `R23` | 9 | 3 | β€” | zigbee\|IEEE 802.15.4 mesh]], Zigbee PRO R23 ({{dynamic-link-key\|Dynamic Link Key}}, | +| `AIP` | 6 | 2 | β€” | After GET PROCESSING OPTIONS (returning AIP+{{afl\|AFL}}) and {{read-record\|READ REC | +| `GB` | 6 | 4 | β€” | -byte lifetime (default ~8 hours / ~100 GB). Before either limit is hit, peers run | +| `Q1` | 5 | 4 | β€” | he in-kernel push', text: 'As of Q1 2026, [[quic\|QUIC]] carries roughly \*\*2 | +| `OV` | 5 | 2 | β€” | to seconds of cloning time. \*\*The Dutch OV-chipkaart kept shipping affected cards | +| `M3` | 5 | 2 | β€” | atter}} devices\* (Hue Bridge, Aqara Hub M3) translate {{matter\|Matter}} operations | +| `II` | 4 | 4 | β€” | 'The **[[ethernet\|Ethernet]] Type II frame format** β€” six bytes of destinati | +| `F1` | 4 | 4 | β€” | caption: '**{{nist\|NIST}}-F1**, the caesium fountain atomic clock th | +| `SPEKE` | 4 | 2 | β€” | amic-link-key\|Dynamic Link Key}}\*\* with SPEKE-over-{{curve25519\|Curve25519}} removes | +| `MAI` | 4 | 1 | β€” | the upstream took it.", mistake: "MAI Network Services ({{autonomous-system\|A | +| `PCCW` | 4 | 1 | β€” | ocally. But Pakistan Telecom's upstream PCCW ({{autonomous-system\|AS}} 3491) had no | +| `IKEA` | 4 | 2 | β€” | azon, Samsung, Aqara, Eve, Philips Hue, IKEA, Schlage, Yale, and dozens more.' } | +| `MUST` | 3 | 2 | β€” | t of [[ip\|IP]]."\*\* Every [[ip\|IP]] host MUST answer Echo Requests by spec. Dropping | +| `RS-232` | 3 | 2 | β€” | pposed to be the wire that replaced the RS-232 cable to a mobile-phone headset. Thirty | +| `S1` | 3 | 3 | β€” | ss network}} and the core (N2/N3 in 5G, S1 in {{lte\|LTE}}) is wrapped in [[ipsec\|I | +| `CONNECTED` | 3 | 3 | β€” | connection state machine β€” \`RRC_IDLE β†’ CONNECTED β†’ INACTIVE\` for 5G β€” and \*\*{{nas\|NAS}} | +| `ET` | 3 | 2 | β€” | text: 'On **22 February 2024 at 03:30 ET**, AT&T Mobility customers across the U | +| `AST` | 3 | 2 | β€” | }}\'s Globalstar partnership and AT&T's AST SpaceMobile follow similar patterns. Re | +| `UDP/5353` | 3 | 2 | β€” | -local {{multicast\|multicast}} group on UDP/5353, with a probe/announce/respond/goodbye | +| `RX` | 3 | 1 | β€” | n. The car (multiple anchors typically) RX-timestamps at t2, delays by `T_reply1` | +| `PARTNER.COM` | 3 | 1 | β€” | XAMPLE.COM wants to access a service in PARTNER.COM, her {{kerberos-kdc\|KDC}} issues a \*\*re | +| `PR` | 3 | 3 | β€” | ded-clients DoS in 0.9-rc2 was fixed in PR #808.', source: { url: 'https:// | +| `NIO` | 3 | 2 | β€” | lone, including the first Chinese OEMs (NIO, XPENG, Geely group brands). Devices mu | +| `XPENG` | 3 | 2 | β€” | including the first Chinese OEMs (NIO, XPENG, Geely group brands). Devices must supp | +| `T2` | 3 | 2 | β€” | Server records when the packet arrives (T2) and when it sends the reply (T3). Both | +| `SIZE` | 2 | 2 | β€” | he sentinel and uses an authoritative \`SIZE\` field. [[amqp\|AMQP]] itself adds no a | +| `GA` | 2 | 1 | β€” | protocol', text: '**RabbitMQ 4.0 GA (18 September 2024)** made [[amqp\|AMQP] | +| `KIP-1150` | 2 | 1 | β€” | ess Topics β€” KIP-1150', text: '**KIP-1150 "Diskless Topics"** was accepted by the | +| `S3` | 2 | 1 | β€” | less / Bufstream architecture that uses S3 as primary storage. Brokers become {{st | +| `MD` | 2 | 1 | β€” | lorado Springs, Philadelphia, Rockville MD, San Francisco), with {{apple\|Apple}}, | +| `VSX` | 2 | 2 | β€” | ', caption: 'A **Polycom VSX 7000** video-conferencing system β€” the | +| `IIS` | 2 | 2 | β€” | which was created in 1995 by Fraunhofer IIS for **WinPlay3** and popularised by \*\*N | +| `TV` | 2 | 2 | β€” | y Netflix stream, every {{apple\|Apple}} TV {{broadcast\|broadcast}} β€” still starts | +| `EXT-X-PRELOAD-HINT` | 2 | 2 | β€” | ttp2\|HTTP/2]] push requirement with **\`EXT-X-PRELOAD-HINT\`** β€” a simpler, {{cdn\|CDN}}-friendly h | +| `UCLA` | 2 | 2 | β€” | -node network that became the internet. UCLA, SRI, UCSB, and Utah; one {{imp\|IMP}} p | +| `SRI` | 2 | 2 | β€” | network that became the internet. UCLA, SRI, UCSB, and Utah; one {{imp\|IMP}} per si | +| `ISI` | 2 | 2 | β€” | '[[pioneer:jon-postel\|Jon Postel]] at ISI. He edited [[rfc:791\|RFC 791]] ([[ip\|IP | +| `L7` | 2 | 2 | β€” | n the registry. The first genuinely new L7 protocol since [[websockets\|WebSockets] | +| `WS` | 2 | 2 | β€” | dern protocol history. His core line: _"WS-\* bad"_ β€” shorthand among {{ietf\|IETF} | +| `INACTIVE` | 2 | 2 | β€” | tate machine β€” \`RRC_IDLE β†’ CONNECTED β†’ INACTIVE\` for 5G β€” and **{{nas\|NAS}}** carries | +| `AMPS` | 2 | 2 | β€” | [cellular\|cellular]]\*\* β€” from 1G analog AMPS / TACS / NMT in the early 1980s through | +| `NFC-A` | 2 | 2 | β€” | e flavours on the air', text: '**NFC-A** ({{iso\|ISO}} 14443-A): {{pcd\|PCD}}β†’{{ | +| `OOK` | 2 | 2 | β€” | ed-Miller; {{picc\|PICC}}β†’{{pcd\|PCD}} is OOK Manchester on the 847.5 kHz subcarrier. | +| `NFC-B` | 2 | 2 | β€” | Base rate 106 kbit/s, scaling to 848. **NFC-B** ({{iso\|ISO}} 14443-B): {{pcd\|PCD}}β†’{{ | +| `NRZ-L` | 2 | 2 | β€” | cc\|PICC}} is 10% {{ask-modulation\|ASK}} NRZ-L; {{picc\|PICC}}β†’{{pcd\|PCD}} is {{bpsk\|BP | +| `JIS` | 2 | 2 | β€” | assports. **{{nfc-f\|NFC-F}}** (FeliCa / JIS X 6319-4): 212/424 kbit/s Manchester-co | +| `PASMO` | 2 | 2 | β€” | nt in Japan {{transit\|transit}} (Suica, PASMO) and Hong Kong (Octopus). \*\*{{nfc-v\|NFC | +| `ETH` | 2 | 2 | β€” | u, Giovanni Camurati, and colleagues at ETH ZΓΌrich published **Ghost Peak** β€” an at | +| `D03` | 2 | 2 | β€” | eee-802-15-4\|IEEE}} 802.15.4ab\*\* (Draft D03 September 2025, ratification expected e | +| `ABI` | 2 | 2 | β€” | eness of [[uwb\|UWB]] into one purchase. ABI projects [[uwb\|UWB]] phone penetration | +| `PRO` | 2 | 2 | β€” | '[[zigbee\|IEEE 802.15.4 mesh]], Zigbee PRO R23 ({{dynamic-link-key\|Dynamic Link Ke | +| `RTSP` | 2 | 2 | β€” | mber 2025)\*\*, with camera streaming via RTSP, removing the last category that previo | +| `OASIS` | 2 | 2 | β€” | ce the protocol and shepherd it through OASIS standardization.', imagePath: | +| `CEO` | 2 | 2 | β€” | oyed [[amqp\|AMQP]] broker. Later became CEO of Weaveworks, bringing messaging patte | +| `TIBCO` | 2 | 2 | β€” | rneyed from Wall Street trading floors (TIBCO) to IoT sensors ([[mqtt\|MQTT]]) to clou | +| `DIX` | 2 | 1 | β€” | c\|Xerox PARC}} in 1973, co-authored the DIX [[ethernet\|Ethernet]] standard (1980), | +| `DEC` | 2 | 2 | β€” | t infrastructure', caption: "The DEC PDP-11 β€” machines like these ran early | +| `BIND` | 2 | 2 | β€” | urity', contribution: 'Wrote BIND, the most widely deployed [[dns\|DNS]] s | +| `HTML5` | 2 | 2 | β€” | sse\|Server-Sent Events]] as part of the HTML5 specification, enabling simple server-t | +| `CMOS` | 2 | 2 | β€” | sh engineer who owned the analog RF and CMOS implementation work that paired with Ja | +| `IC` | 2 | 2 | β€” | Jaap Haartsen\'s digital baseband. The IC-level decisions that made [[bluetooth\|B | +| `FR2` | 2 | 2 | β€” | flexible numerology, {{mmwave\|mmWave}} (FR2) support, network slicing. First commer | +| `RTT` | 2 | 2 | β€” | Adopted 3 September 2024. Phase-based + RTT distance measurement on a new {{le-audi | +| `H1/H2` | 2 | 2 | β€” | m\|Broadcom}}, Qualcomm, {{apple\|Apple}} H1/H2) uses **time-division arbitration** at | +| `SMTPS` | 2 | 1 | β€” | ication protocols transparently (HTTPS, SMTPS); [[ssh\|SSH]] provides an encrypted cha | +| `RTMPS` | 2 | 2 | β€” | aps [[rtmp\|RTMP]] connections to create RTMPS, encrypting live stream ingest traffic | +| `MB` | 2 | 2 | β€” | r packet is **1460 bytes**. Sending a 1 MB file means roughly 685 packets. {{path- | +| `NSFNET` | 2 | 2 | β€” | 1986 the same architecture was carrying NSFNET traffic across the country β€” and the bu | +| `UC` | 2 | 2 | β€” | ffers between Lawrence Berkeley Lab and UC Berkeley, three hops apart, were where | +| `RACK-TLP` | 2 | 2 | β€” | ubic\|CUBIC}}, {{bbr\|BBR}}, {{l4s\|L4S}}, RACK-TLP β€” are each refinements of the same cons | +| `HPC` | 2 | 2 | β€” | rnet\|Ethernet]]+[[ip\|IP]] for {{ai\|AI}}/HPC scale-out: {{connectionless\|connectionl | +| `CBC` | 2 | 2 | β€” | }} key {{exchange\|exchange}}, and every CBC-mode cipher β€” keeping only {{chacha20-p | +| `BEAST` | 2 | 2 | β€” | been weaponised in a published attack (BEAST, CRIME, BREACH, Lucky 13, FREAK, Logjam | +| `CRIME` | 2 | 2 | β€” | eaponised in a published attack (BEAST, CRIME, BREACH, Lucky 13, FREAK, Logjam, ROBOT | +| `BREACH` | 2 | 2 | β€” | ed in a published attack (BEAST, CRIME, BREACH, Lucky 13, FREAK, Logjam, ROBOT, …). [[ | +| `FREAK` | 2 | 2 | β€” | attack (BEAST, CRIME, BREACH, Lucky 13, FREAK, Logjam, ROBOT, …). [[tls\|TLS]] 1.3 als | +| `ROBOT` | 2 | 2 | β€” | CRIME, BREACH, Lucky 13, FREAK, Logjam, ROBOT, …). [[tls\|TLS]] 1.3 also reduced the { | +| `OBS` | 2 | 2 | β€” | eam ingest}}\*\* protocol β€” your encoder (OBS, Wirecast) pushes a long-lived [[tcp\|TC | +| `STD` | 2 | 2 | β€” | tra\|Dijkstra]] ([[rfc:2328\|RFC 2328]] / STD 54).', steps: { 0: '{{ospf-hello\|H | +| `CTR` | 2 | 2 | β€” | t}}; **{{sts\|STS}}** is the {{aes\|AES}}-CTR-generated pulse pattern that makes the | +| `WHERE` | 2 | 1 | β€” | transition: 'The browser now knows WHERE the server lives β€” but packets on the i | +| `FSCI` | 2 | 2 | β€” | TS}}\*\* declaring its frame-size budget (FSCI=5 = 64 bytes max). Both ends now know h | +| `FCI` | 2 | 2 | β€” | } `2PAY.SYS.DDF01`). The eSE returns an FCI Template listing every payment {{aid\|AI | +| `PROCESSING` | 2 | 2 | β€” | gram', description: "After GET PROCESSING OPTIONS (returning AIP+{{afl\|AFL}}) and | +| `CDOL1` | 2 | 2 | β€” | nerate-ac\|GENERATE AC}} with the filled CDOL1 data. The eSE composes the inputs (amou | +| `QR` | 2 | 2 | β€” | e}} (printed on the Hue bulb's box as a QR code), that link key is unique and an e | +| `CVSS` | 2 | 2 | β€” | on the public internet were vulnerable. CVSS 7.5 (high). Operators scrambled to patc | +| `CID` | 2 | 1 | β€” | att-mtu\|ATT}}) lives on {{l2cap\|L2CAP}} CID 0x0004 and provides read/write/notify/i | +| `LTK` | 2 | 1 | β€” | Curve P-256 to derive a Long-Term Key (LTK); the link is then {{encryption\|encrypt | +| `CIS` | 2 | 1 | β€” | nels\*\* β€” Connected Isochronous Streams (CIS) for {{unicast\|unicast}} earbuds/hearin | +| `LL` | 2 | 1 | β€” | scription: 'Two devices in a normal LL connection schedule \*\*{{channel-soundin | +| `NCC` | 2 | 2 | β€” | s the protocol-level answer to the 2022 NCC Group {{ble\|BLE}} relay attack that ope | +| `GFSK` | 2 | 1 | β€” | s over the air\*\*. Different modulation (GFSK + DPSK for Classic, GFSK only for {{ble | +| `PB` | 2 | 1 | β€” | }} by Q3 2025; the network averages 6.5 PB/day. The first proof that a hyperscale | +| `NR` | 2 | 1 | β€” | ecified in Release 17 (2022), the first NR-{{ntn\|NTN}} deployments shipped in late | +| `USA` | 2 | 1 | β€” | numbering plan: 234/235 = UK, 310–316 = USA, 460 = China, 405 = India, 440–441 = Ja | +| `X2` | 2 | 2 | β€” | \*mandate\*\* [[ipsec\|IPsec]] on every S1, X2, N2, N3, Xn, F1, and E1 interface. Forg | +| `N2` | 2 | 2 | β€” | date\*\* [[ipsec\|IPsec]] on every S1, X2, N2, N3, Xn, F1, and E1 interface. Forgetti | +| `N3` | 2 | 2 | β€” | \*\* [[ipsec\|IPsec]] on every S1, X2, N2, N3, Xn, F1, and E1 interface. Forgetting t | +| `E1` | 2 | 2 | β€” | ]] on every S1, X2, N2, N3, Xn, F1, and E1 interface. Forgetting this in a private | +| `SOA` | 2 | 1 | β€” | pex must also have {{ns-record\|NS}} and SOA records. Some [[dns\|DNS]] providers off | +| `NXDOMAIN` | 2 | 1 | β€” | g can hurt', text: 'Resolvers cache NXDOMAIN responses based on the SOA minimum fiel | +| `UDP/4500` | 2 | 1 | β€” | {{security-association\|SA}} switches to UDP/4500 {{encapsulation\|encapsulation}}. Two me | +| `MOBIKE` | 2 | 1 | β€” | me routers don\'t corrupt the packet. **MOBIKE** ([[rfc:4555\|RFC 4555]]) lets a roadwa | +| `SKU` | 2 | 2 | β€” | (10 Gbps aggregate on the AZ-redundant SKU), {{gcp\|GCP}} Cloud {{vpn\|VPN}}, OCI Si | +| `AS-REQ` | 2 | 1 | β€” | description: 'Client sends an **AS-REQ** to the {{kerberos-kdc\|KDC}}\'s Authen | +| `TGS-REP` | 2 | 1 | β€” | ion key for Alice↔web1, and returns a **TGS-REP** with a **service ticket** encrypted u | +| `GSS` | 2 | 1 | β€” | y speak Kerberos directly. They speak **GSS-{{api\|API}}** (Generic Security Service | +| `SPNEGO` | 2 | 1 | β€” | ntext\` / \`gss_accept_sec_context\`. **SPNEGO** ([[rfc:4178\|RFC 4178]]) is the protoc | +| `PKINIT` | 2 | 1 | β€” | gust 2025 release. Headline features: **PKINIT {{ecdh\|ECDH}}/EC certs** (smart-card au | +| `DES` | 2 | 1 | β€” | IT}}-internal for years because it used DES β€” and DES exports required State Depart | +| `FF02` | 2 | 2 | β€” | s\* on \`224.0.0.251\` ([[ipv6\|IPv6]]: \`FF02::FB\`). Two flag bits get repurposed: t | +| `SD` | 2 | 2 | β€” | cription: "A {{dns-resolution\|DNS}}-SD client looking for printers sends a {{p | +| `SRP` | 2 | 1 | β€” | col) published', description: '**SRP** ({{rfc-doc\|RFC}} 9665, Lemon + [[pion | +| `LLMNR` | 2 | 1 | β€” | th [[mdns-dns-sd\|mDNS]] **enabled** and LLMNR **disabled** in the security baseline. | +| `IGMP` | 2 | 1 | β€” | e (often 6 Mbps); managed switches with IGMP snooping enabled drop frames whose list | +| `WLC` | 2 | 2 | β€” | -dns-sd\|mDNS]] gateway ({{cisco\|Cisco}} WLC `mdns-sd` profile, Aruba AirGroup, Aero | +| `DERP` | 2 | 2 | β€” | path between peers; their proprietary **DERP** relays absorb the rest as a {{turn\|TU | +| `CTO` | 2 | 2 | β€” | turn\|TURN}}, and {{ice\|ICE}}. Currently CTO + Head of {{ai\|AI}} at Five9.' } ], | +| `T2T` | 2 | 1 | β€” | ate frame size (FSCI) and timing (FWI). T2T cards skip {{rats\|RATS}} and go straigh | +| `TC` | 2 | 2 | β€” | } β€” either an {{arqc\|ARQC}} (online) or TC (offline). The cryptogram is signed in | +| `TNF` | 2 | 1 | β€” | ifier\|ID}} Length present), and a 3-bit TNF (Type Name Format: 0=Empty, 1=Well-Know | +| `IEC` | 2 | 1 | β€” | {ndef\|NDEF}} was formally adopted as an IEC standard in **March 2026** alongside NF | +| `HID` | 2 | 2 | β€” | }}, Allegion, Aqara, {{google\|Google}}, HID, Kastle, Kwikset, Last Lock, Nordic, Nu | +| `EV3` | 2 | 1 | β€” | Plus in **2011**, DESFire EV2 in 2016, EV3 in the early 2020s. The Classic Crypto1 | +| `GM` | 2 | 2 | β€” | is, Audi (new in 2025), Volvo, Porsche, GM, Ford, plus a wave of Chinese OEMs (NIO | +| `DDA/CDA` | 2 | 1 | β€” | eturns an AIP byte that signals whether DDA/CDA is supported. A common custom-{{hce\|HCE | +| `RRP` | 2 | 1 | β€” | gram\|EMV}} **Relay Resistance Protocol (RRP)** in Kernel 2 v2.6+ binds round-trip t | +| `T1` | 2 | 1 | β€” | DP]] packet with its current timestamp (T1). The packet is tiny β€” 48 bytes.' }, | +| `T3` | 2 | 1 | β€” | rives (T2) and when it sends the reply (T3). Both timestamps are included in the r | +| `T4` | 2 | 1 | β€” | ient records when the response arrives (T4). Now it has four timestamps: T1 (sent) | +| `NBMA` | 2 | 1 | β€” | default 10 s on point-to-point, 30 s on NBMA). Hellos carry the router\'s {{id-ident | +| `HPRF` | 2 | 1 | β€” | Hz** in the default 802.15.4z mode or **HPRF 124.8 / 249.6 MHz\*\* in higher-power mod | +| `RTLS` | 2 | 1 | β€” | f arrival β€” used for warehouse/hospital RTLS where anchors are wired. \*_AoA / PDoA:_ | +| `EN` | 2 | 1 | β€” | Hz\*\* across 3.1–10.6 GHz. {{etsi\|ETSI}} EN 302 065 in Europe is similar with stric | +| `AR` | 2 | 1 | β€” | ision Finding, BMW Digital Key, and the AR experiences in {{apple\|Apple}} Vision P | +| `T2024` | 2 | 1 | β€” | 1-chip\|U1}}'s 16 nm), internal codename T2024, part number 339M00298. \*\*1.5Γ— longer P | +| `U400` | 2 | 1 | β€” | amsung wallets. First products: **Aqara U400** (first smart lock with UWB; {{aliro\|A | +| `S21` | 2 | 1 | β€” | \|Apple}} UWB tracker. Works with Galaxy S21+ / S21 Ultra / Note 20 Ultra / S22/S23/ | +| `DW3000` | 2 | 1 | β€” | upports only Channel 5; everything from DW3000 / {{nxp\|NXP}} SR150 / {{apple\|Apple}} { | +| `SR150` | 2 | 1 | β€” | 5; everything from DW3000 / {{nxp\|NXP}} SR150 / {{apple\|Apple}} {{u1-chip\|U1}} onward | +| `NLOS` | 2 | 1 | β€” | ns = 30 cm, but in **non-line-of-sight (NLOS)** conditions through walls/people/meta | +| `ACL` | 2 | 1 | β€” | r which destination prefix) **and** the ACL (inbound: only accept packets from this | +| `TSPU` | 2 | 1 | β€” | mimicry', description: "Russia's TSPU boxes learned to fingerprint and drop s | +| `S1/S2` | 2 | 1 | β€” | H4 ranges instead of fixed 1–4), random S1/S2 padding. AWG 2.0 adds optional QUIC/{{d | +| `WARP` | 2 | 1 | β€” | are}}'s consumer {{vpn\|VPN}} (1.1.1.1 + WARP app) runs on **BoringTun**, {{cloudflar | +| `OTA` | 2 | 1 | β€” | ntrol = 0x0008, Color Control = 0x0300, OTA Upgrade = 0x0019), and an \*_APSCounter_ | +| `FOSS` | 2 | 1 | β€” | and _no_ microphone or camera. For the FOSS path the answer is **zigbee2mqtt** by K | +| `PSU` | 2 | 1 | β€” | ble Zigbee β€” the router's switched-mode PSU emits broadband 2.4 GHz noise." } ], | +| `CC2652` | 2 | 1 | β€” | dresden elektronik ConBee II, or any TI CC2652 stick β€” the radio is abstracted behind | +| `SES` | 2 | 1 | β€” | 3 December 2024\*\* VusionGroup (formerly SES-imagotag) announced acceleration of dig | +| `ESL` | 2 | 1 | β€” | 500 stores. Vusion shipped 350 million ESLs in 2023 alone; the EdgeSense platform r | +| `AIR` | 2 | 1 | β€” | ', description: "Acuity's nLight AIR and Atrius lines are the dominant Zigbe | +| `SUN` | 2 | 1 | β€” | and later directed standards at the Wi-SUN Alliance. Almost every low-power 802.15 | +| `VSAT` | 1 | 1 | β€” | llips 66 oil pipelines over a brand-new VSAT satellite link. The 2-byte fixed header | +| `PINGREQ` | 1 | 1 | β€” | ixed header\*\*, smallest control packet (PINGREQ) is 2 bytes total. Designed in 1999 by | +| `JMS` | 1 | 1 | β€” | sia is removed. RabbitMQ 4.3 also added JMS-style queues with {{sql\|SQL}} message s | +| `NETSCOUT` | 1 | 1 | β€” | { kind: 'pull-quote', text: 'NETSCOUT\'s January 2019 scan found 388,344 publ | +| `QLC` | 1 | 1 | β€” | ey were Chinese smartphones running the QLC Chain {{peer-to-peer\|peer-to-peer}} cry | +| `EDHOC` | 1 | 1 | β€” | messages, ~100 bytes', text: '**EDHOC ([[rfc:9000\|RFC 9528]], March 2024)** β€” | +| `DH` | 1 | 1 | β€” | sages totalling ~100 bytes** for static-DH credentials, vs **~700+ bytes for a {{d | +| `OSCORE` | 1 | 1 | β€” | years\* of additional life. Companion: **OSCORE ([[rfc:8613\|RFC 8613]])** wraps the [[c | +| `DNA` | 1 | 1 | β€” | g router carries the same architectural DNA: a control plane that builds the {{rout | +| `PREF64` | 1 | 1 | β€” | clients "skip [[ip\|IPv4]] entirely," \*\*PREF64 in Router Advertisements ([[rfc:8781\|RF | +| `RIR` | 1 | 1 | β€” | {{roa\|ROA}} set. Lesson: enforce 2FA on RIR portals.', attribution: 'Author' | +| `OTC` | 1 | 1 | β€” | fc:9234\|RFC 9234]] ([[bgp\|BGP]] Roles + OTC) ate its lunch. The lesson: a security | +| `MW` | 1 | 1 | β€” | nal pluggable optics would consume ~180 MW of power for the optics alone. That is | +| `X1600` | 1 | 1 | β€” | AI}} workloads. **{{spectrum\|Spectrum}}-X1600 (102.4 Tbps)** is expected 2H 2026.' | +| `GB200` | 1 | 1 | β€” | ption: 'The **{{nvidia\|NVIDIA}} GB200 NVL72** Blackwell-architecture rack on | +| `NVL72` | 1 | 1 | β€” | 'The **{{nvidia\|NVIDIA}} GB200 NVL72** Blackwell-architecture rack on displa | +| `COMPUTEX` | 1 | 1 | β€” | ackwell-architecture rack on display at COMPUTEX 2024 β€” the kind of {{ai\|AI}}-training e | +| `WECA` | 1 | 1 | β€” | as a tagline retrofitted briefly by the WECA board and dropped. The yin-yang logo is | +| `OET` | 1 | 1 | β€” | on **23 February 2024** the {{fcc\|FCC}} OET approved \*\*seven {{afc\|AFC}} system ope | +| `RUCKUS` | 1 | 1 | β€” | d [[wifi\|Wi-Fi]] 7 {{access-point\|AP}} (RUCKUS R770) was certified 16 April 2024.\*\* Bu | +| `R770` | 1 | 1 | β€” | i\|Wi-Fi]] 7 {{access-point\|AP}} (RUCKUS R770) was certified 16 April 2024.\*\* But on | +| `SINR` | 1 | 1 | β€” | squeezes for \*\*+25% throughput at given SINR, βˆ’25% 95th-percentile {{latency\|latency | +| `MPDU` | 1 | 1 | β€” | th-percentile {{latency\|latency}}, βˆ’25% MPDU loss across {{bss-coloring\|BSS}} transi | +| `CS168` | 1 | 1 | β€” | P]] stack), {{mit\|MIT}} 6.829, Berkeley CS168.', slots: [ { kind: 'prose' | +| `PARC` | 1 | 1 | β€” | still runs the original spec. The 1973 PARC sketch and a 2025 Ultra [[ethernet\|Ethe | +| `KU` | 1 | 1 | β€” | , text: '\*\*Mathy Vanhoef and the KU Leuven team have broken [[wifi\|Wi-Fi]] | +| `DCP` | 1 | 1 | β€” | rote [[rfc:826\|RFC 826]] from address \`DCP@{{mit\|MIT}}-MC\` in November 1982. \*\*ST | +| `MC` | 1 | 1 | β€” | FC 826]] from address \`DCP@{{mit\|MIT}}-MC\` in November 1982. \*\*STD 37 has never | +| `L2` | 1 | 1 | β€” | xt: '[[arp\|ARP]] relies entirely on the L2 {{checksum\|frame check sequence}} β€” no | +| `BRL` | 1 | 1 | β€” | rote {{ping\|ping}} in a single night at BRL Aberdeen in December 1983, named after | +| `TOPS-20` | 1 | 1 | β€” | st server was named _Jeeves_ and ran on TOPS-20.', credit: 'Image: Wikimedia Com | +| `KEX` | 1 | 1 | β€” | llo\|ServerHello}}/Finished, [[ssh\|SSH]] KEX, [[mqtt\|MQTT]] {{mqtt-connect\|CONNECT}} | +| `CONNACK` | 1 | 1 | β€” | [[mqtt\|MQTT]] {{mqtt-connect\|CONNECT}}/CONNACK, [[sctp\|SCTP]]\'s four-way {{cookie\|Coo | +| `DAVE` | 1 | 1 | β€” | on a whiteboard in 2018." Discord\'s **DAVE protocol** (deployed 1 March 2026) laye | +| `MLS` | 1 | 1 | β€” | otocol\*\* (deployed 1 March 2026) layers MLS keys + SFrame on top of [[rtp\|RTP]]/{{s | +| `E2EE` | 1 | 1 | β€” | on top of [[rtp\|RTP]]/{{srtp\|SRTP}} for E2EE voice across \*\*2.5 million concurrent u | +| `M120` | 1 | 1 | β€” | AV1}} hardware encode shipped in Chrome M120 (Dec 2023). Firefox 125 added {{av1\|AV1 | +| `EME` | 1 | 1 | β€” | ec 2023). Firefox 125 added {{av1\|AV1}}+EME in April 2024. But the royalty-free cla | +| `CMAF` | 1 | 1 | β€” | ate ladders of small .ts (or now .mp4 / CMAF) segments; a {{cdn\|CDN}} serves them ov | +| `ISDN` | 1 | 1 | β€” | four wholesale rewrites later (analog β†’ ISDN β†’ [[rtp\|RTP]]/H.323 β†’ [[webrtc\|WebRTC]] | +| `PRNET/SATNET` | 1 | 1 | β€” | et\|ARPANET}}), and unreliable wireless (PRNET/SATNET) each forced different design pressures | +| `UCSB` | 1 | 1 | β€” | rk that became the internet. UCLA, SRI, UCSB, and Utah; one {{imp\|IMP}} per site.', | +| `EDGE` | 1 | 1 | β€” | d on 29 June 2007 with [[wifi\|Wi-Fi]] + EDGE; the App Store followed in July 2008; { | +| `GIGA` | 1 | 1 | β€” | ple}} {{os\|OS}} services, Korea Telecom GIGA Path, some specialised enterprise WANs) | +| `CA` | 1 | 1 | β€” | te-authority\|CA}} signs an intermediate CA, which signs the end-entity {{certifica | +| `SIGALRM` | 1 | 1 | β€” | {{linux\|Linux}}. Signal-handler race: \`SIGALRM\` handler calls \`syslog()\` (not async | +| `UNIX` | 1 | 1 | β€” | er than {{arpanet\|ARPANET}}, older than UNIX, older than every other timestamp stand | +| `Y2036` | 1 | 1 | β€” | it and will need fixes before 2036. The Y2036 work has been quietly underway since 20 | +| `SNDMSG` | 1 | 1 | β€” | picked the **@** sign in 1971 modifying SNDMSG. [[pioneer:jon-postel\|Jon Postel]] publ | +| `DCE` | 1 | 1 | β€” | a 40-year lineage of Sun {{rpc\|RPC}} / DCE / CORBA / Thrift. The client _stub_ ser | +| `CORBA` | 1 | 1 | β€” | year lineage of Sun {{rpc\|RPC}} / DCE / CORBA / Thrift. The client _stub_ serialises | +| `NTIA` | 1 | 1 | β€” | d States Frequency Allocations Chart\**, NTIA. Every coloured stripe is a *service\* β€” | +| `WPA` | 1 | 1 | β€” | \|OOB}} key or the Wi-Fi {{ssid\|SSID}} + WPA key in an {{ndef\|NDEF}} record. \*\*[[zig | +| `MIMO` | 1 | 1 | β€” | 11]] β€” {{csma-ca\|CSMA/CA}} in practice, MIMO β†’ {{ofdma\|OFDMA}} β†’ {{mlo\|MLO}}, and th | +| `DIFS` | 1 | 1 | β€” | of the {{airtime\|airtime}} is spent on DIFS gaps, {{ack\|ACK}} frames, beacons, and | +| `NB` | 1 | 1 | β€” | volte\|VoLTE}} / [[wifi\|Wi-Fi]] calling, NB-IoT / {{lte\|LTE}}-M, satellite {{direct | +| `N2/N3` | 1 | 1 | β€” | an\|radio access network}} and the core (N2/N3 in 5G, S1 in {{lte\|LTE}}) is wrapped in | +| `IOS` | 1 | 1 | β€” | teffen]]\'s strongSwan, {{cisco\|Cisco}} IOS, and Juniper {{junos\|Junos}} run more [ | +| `TACS` | 1 | 1 | β€” | ar\|cellular]]\*\* β€” from 1G analog AMPS / TACS / NMT in the early 1980s through 2G {{g | +| `NMT` | 1 | 1 | β€” | ular]]\*\* β€” from 1G analog AMPS / TACS / NMT in the early 1980s through 2G {{gsm\|GSM | +| `IS-95` | 1 | 1 | β€” | he early 1980s through 2G {{gsm\|GSM}} / IS-95, 3G {{wcdma\|WCDMA}} / CDMA2000, 4G {{lt | +| `CDMA2000` | 1 | 1 | β€” | gsm\|GSM}} / IS-95, 3G {{wcdma\|WCDMA}} / CDMA2000, 4G {{lte\|LTE}}, and {{5g-nr\|5G NR}}. E | +| `SYS.DDF01` | 1 | 1 | β€” | t System Environment {{aid\|AID}} \`2PAY.SYS.DDF01\` β€” and the card returns an FCI listing | +| `A0000000041010` | 1 | 1 | β€” | The reader picks one (e.g. Mastercard \`A0000000041010\`), SELECTs it, gets back a {{pdol\|PDOL | +| `TX` | 1 | 1 | β€” | _can_ be cheated β€” a relay with enough TX power makes a distant device look near. | +| `PAL` | 1 | 1 | β€” | iority), **Priority Access Licensees** (PALs, auctioned in 2020 for ~$4.5B), and \*\*G | +| `PMSE` | 1 | 1 | β€” | has experimented with similar concepts (PMSE in the UK, {{lsa\|LSA}} in some EU pilot | +| `PIE` | 1 | 1 | β€” | {{aqm\|Active Queue Management}} (CoDel, PIE, fq_codel) and algorithms like {{bbr\|BB | +| `SCADA` | 1 | 1 | β€” | on: "Brought embedded systems and SCADA expertise to [[mqtt\|MQTT]]'s design. Co | +| `CBOR` | 1 | 1 | β€” | oap\|CoAP]] specification and co-created CBOR, the efficient binary {{serialization\|s | +| `NATS` | 1 | 1 | β€” | o cloud-native microservices ([[amqp]], NATS, [[kafka]]). Today, it's one of the mos | +| `P802` | 1 | 1 | β€” | on 100 G lanes). The 1.6 TbE follow-up (P802.3dj, 200 G/lane) targets July 2026 β€” dr | +| `LO` | 1 | 1 | β€” | two months before the first successful "LO" transmission to SRI.', credit: 'Pho | +| `PDP-11` | 1 | 1 | β€” | frastructure', caption: "The DEC PDP-11 β€” machines like these ran early [[ntp\|N | +| `POWER` | 1 | 1 | β€” | reads "This machine is a server. DO NOT POWER IT DOWN!!"', credit: 'Photo: Coolcae | +| `DOWN` | 1 | 1 | β€” | is machine is a server. DO NOT POWER IT DOWN!!"', credit: 'Photo: Coolcaesar / CC | +| `AAIF` | 1 | 1 | β€” | es to the Agentic {{ai\|AI}} Foundation (AAIF) and [[a2a\|A2A]] launches as a {{linux\| | +| `RF` | 1 | 1 | β€” | 'Swedish engineer who owned the analog RF and CMOS implementation work that paire | +| `COMDEX` | 1 | 1 | β€” | product (a hands-free headset) ships at COMDEX 1999.', protocolId: 'bluetooth' | +| `SC-FDMA` | 1 | 1 | β€” | preading codes for an {{ofdma\|OFDMA}} + SC-FDMA air interface β€” the clean-sheet radio d | +| `IQ` | 1 | 1 | β€” | ble delivery of presence, messages, and IQ queries.', howTheyWork: 'An [[xmpp | +| `AMQPS` | 1 | 1 | β€” | aps [[amqp\|AMQP]] connections to create AMQPS, encrypting all {{broker\|message broker | +| `MQTTS` | 1 | 1 | β€” | aps [[mqtt\|MQTT]] connections to create MQTTS, encrypting all pub/sub messaging betwe | +| `SIPS` | 1 | 1 | β€” | SIP]] {{signaling\|signaling}} to create SIPS, encrypting call setup, authentication, | +| `WSS` | 1 | 1 | β€” | ckets\|WebSocket]] connections to create WSS (wss://), encrypting the {{full-duplex\| | +| `M3U8` | 1 | 1 | β€” | LS]] delivers adaptive video by serving M3U8 playlists and media segments as standar | +| `BOSH` | 1 | 1 | β€” | network without long-polling hacks like BOSH.', howTheyWork: 'The browser opens | +| `PROXY` | 1 | 1 | β€” | ess you explicitly forward it via the **PROXY protocol** or an {{header\|HTTP header}} | +| `ARPA` | 1 | 1 | β€” | down in 1986.', caption: 'The ARPA Network in September 1973, a few dozen | +| `DHT` | 1 | 1 | β€” | Torrent uses centralised trackers (or a DHT, which is a decentralised tracker) to b | +| `SHA384` | 1 | 1 | β€” | DigiCert [[tls\|TLS]] Hybrid {{ecc\|ECC}} SHA384 β†’ DigiCert Global Root G3\`. Only the b | +| `G3` | 1 | 1 | β€” | ecc\|ECC}} SHA384 β†’ DigiCert Global Root G3\`. Only the bottom (root) {{certificate | +| `SIGTRAN` | 1 | 1 | β€” | under telecom {{signaling\|signaling}} (SIGTRAN) and [[webrtc\|WebRTC]] data channels ([ | +| `WHATWG` | 1 | 1 | β€” | only need {{server-push\|server push}} (WHATWG).', steps: { 0: 'Standard [[http1\| | +| `OMA` | 1 | 1 | β€” | App, and the {{matter\|Matter}}-adjacent OMA-LwM2M IoT stack. Encrypted via {{startt | +| `CQRS` | 1 | 1 | β€” | tream processing}}, event sourcing, and CQRS. \*\*{{exactly-once-delivery\|Exactly-once | +| `T1/T2/T3/T4` | 1 | 1 | β€” | timestamps per {{exchange\|exchange}}\*\* (T1/T2/T3/T4) which cancel out network {{latency\|lat | +| `TGS` | 1 | 1 | β€” | ey Distribution Center, split into AS + TGS), and Service. Two {{encryption\|encrypt | +| `SEND` | 1 | 1 | β€” | ONNECT}}, {{mqtt-subscribe\|SUBSCRIBE}}, SEND, and {{ack\|ACK}} are self-explanatory, | +| `ERP` | 1 | 1 | β€” | ing queue, maintenance data goes to the ERP integration queue, and raw telemetry go | +| `VP8` | 1 | 1 | β€” | round rules: which codecs they support (VP8, H.264, Opus), what transport addresses | +| `DANE` | 1 | 1 | β€” | d [[dns\|DNS]]-based authentication like DANE which allows domain owners to {{mqtt-pu | +| `TVR` | 1 | 1 | β€” | the inputs (amount, currency, country, TVR, {{atc\|ATC}}, Unpredictable Number, AIP | +| `POS` | 1 | 1 | β€” | description: "Modern wireless POS terminals (Square, Stripe, Verifone Eng | +| `APPROVED` | 1 | 1 | β€” | sufficient balance + no fraud flag = **APPROVED**. The issuer returns an **ARPC** (Auth | +| `ARPC` | 1 | 1 | β€” | = **APPROVED**. The issuer returns an **ARPC** (Authorisation Response Cryptogram) o | +| `RFRAME` | 1 | 1 | β€” | n: "The phone transmits a **Poll** RFRAME on [[uwb\|UWB]] Channel 9 (7987.2 MHz, 4 | +| `LQI` | 1 | 1 | β€” | icks the best parent by {{rssi\|RSSI}} + LQI. This is the slowest step β€” beacon scan | +| `WITHDRAWAL` | 1 | 1 | β€” | -system\|AS}} 32934 β€” and then a wave of WITHDRAWALs of the [[ip\|IPv4]] and [[ipv6\|IPv6]] pr | +| `SERVFAIL` | 1 | 1 | β€” | ike 1.1.1.1 and 8.8.8.8 start returning SERVFAIL for facebook.com. Apps and humans retry | +| `NANOG` | 1 | 1 | β€” | tion: "Vince Bono's apology email to NANOG that day is preserved in the archives β€” | +| `RIS` | 1 | 1 | β€” | ally for hours. {{ripe-ncc\|RIPE NCC}}'s RIS data became the canonical post-mortem s | +| `LBL` | 1 | 1 | β€” | delivery less likely. Throughput on the LBL-to-UCB path collapsed from 32 kbps to 4 | +| `UCB` | 1 | 1 | β€” | y less likely. Throughput on the LBL-to-UCB path collapsed from 32 kbps to 40 bps β€” | +| `LBL-UCB` | 1 | 1 | β€” | uplicates. Goodput approaches zero. The LBL-UCB path measures 40 bps where it had measu | +| `CT` | 1 | 1 | β€” | limit damage.", mistake: "At 02:42 CT, a network change with an equipment con | +| `GSO` | 1 | 1 | β€” | ff could be split into more than 65,535 GSO segments. The 16-bit counter overflowed | +| `OPEN` | 1 | 1 | β€” | 'Both routers {{exchange\|exchange}} OPEN messages containing their {{autonomous- | +| `NLRI` | 1 | 1 | β€” | messages containing reachable prefixes (NLRI) with path attributes: {{as-path\|AS_PAT | +| `EGP` | 1 | 1 | β€” | Austin. The previous routing protocol (EGP) was unmanageable. They sketched a repl | +| `GTSM` | 1 | 1 | β€” | tcha', text: 'Some operators enable GTSM (Generalised {{ttl\|TTL}} Security Mecha | +| `SBC` | 1 | 1 | β€” | he mandatory {{codec\|codec}} (replacing SBC and saving ~50% battery vs A2DP). \*\*{{a | +| `A2DP` | 1 | 1 | β€” | eplacing SBC and saving ~50% battery vs A2DP). **{{auracast\|Auracast}}** is the {{si | +| `ISOAL` | 1 | 1 | β€” | privacy against long-term tracking) and ISOAL improvements for {{le-audio\|LE Audio}} | +| `EURECOM` | 1 | 1 | β€” | mes', text: "Daniele Antonioli (then EURECOM, now PostDoc-and-faculty) is the lead a | +| `DPSK` | 1 | 1 | β€” | the air\*\*. Different modulation (GFSK + DPSK for Classic, GFSK only for {{ble\|BLE}} | +| `FR1` | 1 | 1 | β€” | two very different deployment regimes (FR1 sub-6 GHz, FR2 {{mmwave\|mmWave}} 24–52 | +| `LLR` | 1 | 1 | β€” | ion}}. The receiver stores soft-decoded LLRs from failed transmissions and combines | +| `RLC` | 1 | 1 | β€” | er compression', description: '**RLC** runs in TM (transparent), UM (unackno | +| `TM` | 1 | 1 | β€” | ', description: '**RLC** runs in TM (transparent), UM (unacknowledged), or | +| `UM` | 1 | 1 | β€” | '**RLC** runs in TM (transparent), UM (unacknowledged), or AM (acknowledged) | +| `AM` | 1 | 1 | β€” | (transparent), UM (unacknowledged), or AM (acknowledged) mode with 10- or 16-bit | +| `PDCP` | 1 | 1 | β€” | ce numbers}} ({{ts-3gpp\|TS}} 38.322). **PDCP** above it ({{ts-3gpp\|TS}} 38.323) does | +| `ROHC` | 1 | 1 | β€” | \* above it ({{ts-3gpp\|TS}} 38.323) does ROHC {{header\|header compression}} (squashin | +| `USIM` | 1 | 1 | β€” | hentication vector, and the {{ue\|UE}}'s USIM verifies AUTN and computes RES\*. After | +| `AUTN` | 1 | 1 | β€” | ctor, and the {{ue\|UE}}'s USIM verifies AUTN and computes RES\*. After Security Mode | +| `RES` | 1 | 1 | β€” | \|UE}}'s USIM verifies AUTN and computes RES\*. After Security Mode Command, {{nas\|NA | +| `PCF` | 1 | 1 | β€” | {upf\|UPF}}, {{ausf\|AUSF}}, {{udm\|UDM}}, PCF, NRF, NEF, NSSF, AF β€” each is a \*\*netwo | +| `NRF` | 1 | 1 | β€” | UPF}}, {{ausf\|AUSF}}, {{udm\|UDM}}, PCF, NRF, NEF, NSSF, AF β€” each is a \*\*network fu | +| `NEF` | 1 | 1 | β€” | , {{ausf\|AUSF}}, {{udm\|UDM}}, PCF, NRF, NEF, NSSF, AF β€” each is a \*\*network functio | +| `NSSF` | 1 | 1 | β€” | usf\|AUSF}}, {{udm\|UDM}}, PCF, NRF, NEF, NSSF, AF β€” each is a **network function** wi | +| `AF` | 1 | 1 | β€” | SF}}, {{udm\|UDM}}, PCF, NRF, NEF, NSSF, AF β€” each is a **network function** with a | +| `GPRS` | 1 | 1 | β€” | \|UPF}} travel over **{{gtp-u\|GTP-U}}** (GPRS Tunnelling Protocol β€” User plane) on [[ | +| `ML` | 1 | 1 | β€” | vanced release. New features: {{ai\|AI}}/ML in the air interface (CSI feedback comp | ## Known concept (just needs wrapping) (55) -| Acronym | Count | Files | Suggested ID | Sample | -|---|---:|---:|---|---| -| `API` | 32 | 10 | api | hat the vast majority of "[[rest\|REST]] APIs" are not RESTful in his strict sense β€” | -| `NAT` | 13 | 4 | nat | CTP]], [[mptcp\|MPTCP]]) cannot traverse NATs that do not understand them; [[quic\|QUI | -| `URL` | 11 | 8 | url | {http-method\|HTTP}}, {{html\|HTML}}, and URLs \u2014 the three pillars of the web. Bu | -| `RFC` | 10 | 4 | rfc-doc | 'Curated reading lists per area β€” the RFCs, books, courses, blogs, and tools worth | -| `CDN` | 8 | 6 | cdn-acr | , use ordinary {{http-method\|HTTP}} and CDNs.', protocolId: 'hls' }, { | -| `LSA` | 6 | 1 | lsa | ({{lsr\|LSR}})** packets asking for the LSAs they don\'t have, and receive them in * | -| `IMP` | 4 | 3 | imp | t router. The protocol that ran between IMPs is what [[tcp\|TCP]]/[[ip\|IP]] would lat | -| `AP` | 4 | 4 | ap-access-point | rable 2.4 GHz collapse β€” when 20+ Wi-Fi APs share three non-overlapping channels, t | -| `MAC` | 4 | 3 | mac-media | [[arp\|ARP]] resolves those addresses to MACs. Together they bootstrap a device onto | -| `ISP` | 3 | 3 | isp | tonomous-system\|Autonomous Systems}}** (ISPs, big companies) tell each other which { | -| `ACK` | 3 | 3 | ack | 1) replacing the older 'three duplicate ACKs' loss-detection rule.", sources: [ | -| `OEM` | 3 | 2 | oem | 2025 alone, including the first Chinese OEMs (NIO, XPENG, Geely group brands). Devic | -| `CLAT` | 2 | 1 | clat-acr | ]]. **Fedora/NetworkManager auto-enable CLAT for [[ipv6\|IPv6]]-mostly networks (2024 | -| `GPU` | 2 | 1 | gpu | d: 'pull-quote', text: 'Scaling 1M GPUs with traditional pluggable optics would | -| `ASK` | 2 | 2 | ask-modulation | 319-4): 212/424 kbit/s Manchester-coded ASK, *no subcarrier* β€” dominant in Japan {{ | -| `POP` | 2 | 2 | pop-acr | nternet Message Access Protocol. Unlike POP, mail stays on the server β€” a radical i | -| `LAN` | 2 | 2 | lan-acr | s [[ip\|IP]]\'s Layer 2 carrier on wired LANs.', howTheyWork: 'When an [[ip\|IP]] | -| `TLD` | 2 | 1 | tld | rchical: 13 **Root** servers know the **TLDs** (`.com`, `.org`...), TLDs know the ** | -| `URI` | 2 | 2 | uri | , and DELETE on resources identified by URIs β€” familiar patterns for web developers, | -| `SELECT` | 2 | 2 | imap-select | inal picks the highest-priority one and SELECTs it; the card returns its **{{pdol\|PDOL} | -| `CPU` | 2 | 1 | cpu | f\|OSPF]] β€” overwhelming the core router CPUs and crashing the entire network.", ca | -| `KEM` | 2 | 1 | kem-acr | 370]] multiple-KE β€” meaning two or more KEMs (e.g. classical ecp384 + post-quantum { | -| `KDC` | 2 | 1 | kerberos-kdc | default)', description: "Modern KDCs reject an unauthenticated AS-REQ. The c | -| `ID` | 2 | 2 | id-identifier | ugh 38473) plus predictable transaction IDs ({{cve\|CVE}}-2024-52616) in **Avahi**, | -| `SSID` | 2 | 2 | ssid | st}}/{{multicast\|multicast}} on stadium SSIDs entirely, or deploy [[mdns-dns-sd\|mDNS] | -| `MRZ` | 2 | 1 | mrz | data without **BAC** (legacy 3DES from MRZ) or **PACE** (modern {{ecdh\|ECDH}} from | -| `DR` | 2 | 1 | ospf-dr | ed Router ({{ospf-dr\|DR}})** and Backup DR β€” the DR is the only neighbour every ro | -| `FTM` | 2 | 1 | ftm | icated UWB anchors. **Honest verdict:** FTM is *good enough* for room-level indoor | -| `PHY` | 2 | 1 | phy | spacing, 250 kbit/s data rate. Sub-GHz PHYs at 868 MHz (Europe, 20 kbit/s {{bpsk\|BP | -| `ISN` | 1 | 1 | isn | 48]]** and the cryptographically-random ISNs every modern stack uses.', credi | -| `X25519MLKEM768` | 1 | 1 | pq-ciphersuite | OpenSSL 3.5's default keyshare is now \`X25519MLKEM768 + {{x25519\|X25519}}\`.` }, | -| `ROA` | 1 | 1 | roa | in to {{ripe-ncc\|RIPE NCC}} and edited ROAs to make legitimate prefixes {{rpki\|RPKI | -| `MED` | 1 | 1 | med | r {{autonomous-system\|AS}}.** Comparing MEDs cross-{{autonomous-system\|AS}} is meani | -| `SFU` | 1 | 1 | sfu | ption\|encryption}} that travels through SFUs without decryption. [[pioneer:justin-ub | -| `WAN` | 1 | 1 | wan-acr | GIGA Path, some specialised enterprise WANs) it works well. Where it does not work | -| `SCP` | 1 | 1 | scp-copy | e protocol that was supposed to replace SCP is finally replacing it.' }, | -| `CVE` | 1 | 1 | cve | s not changed. The ecosystem has. Major CVEs in major implementations: **{{cve\|CVE}} | -| `VLAN` | 1 | 1 | vlan | agline: 'Advanced Layer 2-3 topics β€” VLANs, spanning tree, IPv6 migration, {{arp-c | -| `UI` | 1 | 1 | ui | because of its simplicity, but complex UIs with deeply nested data often outgrow i | -| `LLM` | 1 | 1 | llm | s {{json\|JSON}} Schema definitions that LLMs can understand), resource access (files | -| `KEEPALIVE` | 1 | 1 | bgp-keepalive | ion', description: 'Routers send KEEPALIVEs every ~30 seconds to prove liveness. UP | -| `UPDATE` | 1 | 1 | bgp-update | Es every ~30 seconds to prove liveness. UPDATEs flow whenever routes change. {{notifica | -| `UUID` | 1 | 1 | uuid | sig\|SIG}}-assigned) or 128-bit (vendor) UUIDs. Default {{att-mtu\|ATT}} {{mtu\|MTU}} is | -| `DC` | 1 | 1 | dc-domain-controller | r this date, {{ad-active-directory\|AD}} DCs refuse Kerberos PKINIT with weakly-boun | -| `SPN` | 1 | 1 | spn | **Cure:** register both short and FQDN SPNs in the keytab; set `dns_canonicalize_ho | -| `APDU` | 1 | 1 | apdu | the reader speaks **{{iso\|ISO}} 7816-4 APDUs**: 4-byte header `CLA INS P1 P2` + opti | -| `LSDB` | 1 | 1 | lsdb | le. Areas (Area 0 is the backbone) keep LSDBs scoped so the {{spf\|SPF}} computation s | -| `SRLG` | 1 | 1 | srlg | (include/exclude admin groups, exclude SRLGs). Carried in the new Flexible Algorithm | -| `TLV` | 1 | 1 | tlv | ough Opaque LSAs and Router Information TLVs.' }, { title: 'OSPF has reliable | -| `NIC` | 1 | 1 | nic | DNs offload to [[tls\|TLS]]-acceleration NICs (kTLS); plain servers should expect hig | -| `BLE` | 1 | 1 | ble | reshold *and* the credential is valid β†’ BLE returns Unlock granted/denied. [[nfc\|NF | -| `U2` | 1 | 1 | u2-chip | ng. AirTag 2 (January 2026) carries the U2 alongside the anti-stalking hardware up | -| `U1` | 1 | 1 | u1-chip | {{u1-chip\|U1}} ⇄ {{u1-chip\|U1}}** and **U1 ⇄ {{nxp\|NXP}} / {{qorvo\|Qorvo}}** combi | -| `FFD` | 1 | 1 | ffd | unslotted CSMA-CA in most deployments (FFDs as routers, RFDs as end-devices), with | -| `RFD` | 1 | 1 | rfd | A in most deployments (FFDs as routers, RFDs as end-devices), with optional beacon-m | +| Acronym | Count | Files | Suggested ID | Sample | +| ---------------- | ----: | ----: | -------------------- | ------------------------------------------------------------------------------------------ | +| `API` | 32 | 10 | api | hat the vast majority of "[[rest\|REST]] APIs" are not RESTful in his strict sense β€” | +| `NAT` | 13 | 4 | nat | CTP]], [[mptcp\|MPTCP]]) cannot traverse NATs that do not understand them; [[quic\|QUI | +| `URL` | 11 | 8 | url | {http-method\|HTTP}}, {{html\|HTML}}, and URLs \u2014 the three pillars of the web. Bu | +| `RFC` | 10 | 4 | rfc-doc | 'Curated reading lists per area β€” the RFCs, books, courses, blogs, and tools worth | +| `CDN` | 8 | 6 | cdn-acr | , use ordinary {{http-method\|HTTP}} and CDNs.', protocolId: 'hls' }, { | +| `LSA` | 6 | 1 | lsa | ({{lsr\|LSR}})\*_ packets asking for the LSAs they don\'t have, and receive them in _ | +| `IMP` | 4 | 3 | imp | t router. The protocol that ran between IMPs is what [[tcp\|TCP]]/[[ip\|IP]] would lat | +| `AP` | 4 | 4 | ap-access-point | rable 2.4 GHz collapse β€” when 20+ Wi-Fi APs share three non-overlapping channels, t | +| `MAC` | 4 | 3 | mac-media | [[arp\|ARP]] resolves those addresses to MACs. Together they bootstrap a device onto | +| `ISP` | 3 | 3 | isp | tonomous-system\|Autonomous Systems}}\*\* (ISPs, big companies) tell each other which { | +| `ACK` | 3 | 3 | ack | 1) replacing the older 'three duplicate ACKs' loss-detection rule.", sources: [ | +| `OEM` | 3 | 2 | oem | 2025 alone, including the first Chinese OEMs (NIO, XPENG, Geely group brands). Devic | +| `CLAT` | 2 | 1 | clat-acr | ]]. \*\*Fedora/NetworkManager auto-enable CLAT for [[ipv6\|IPv6]]-mostly networks (2024 | +| `GPU` | 2 | 1 | gpu | d: 'pull-quote', text: 'Scaling 1M GPUs with traditional pluggable optics would | +| `ASK` | 2 | 2 | ask-modulation | 319-4): 212/424 kbit/s Manchester-coded ASK, _no subcarrier_ β€” dominant in Japan {{ | +| `POP` | 2 | 2 | pop-acr | nternet Message Access Protocol. Unlike POP, mail stays on the server β€” a radical i | +| `LAN` | 2 | 2 | lan-acr | s [[ip\|IP]]\'s Layer 2 carrier on wired LANs.', howTheyWork: 'When an [[ip\|IP]] | +| `TLD` | 2 | 1 | tld | rchical: 13 **Root** servers know the **TLDs** (`.com`, `.org`...), TLDs know the \*\* | +| `URI` | 2 | 2 | uri | , and DELETE on resources identified by URIs β€” familiar patterns for web developers, | +| `SELECT` | 2 | 2 | imap-select | inal picks the highest-priority one and SELECTs it; the card returns its \*\*{{pdol\|PDOL} | +| `CPU` | 2 | 1 | cpu | f\|OSPF]] β€” overwhelming the core router CPUs and crashing the entire network.", ca | +| `KEM` | 2 | 1 | kem-acr | 370]] multiple-KE β€” meaning two or more KEMs (e.g. classical ecp384 + post-quantum { | +| `KDC` | 2 | 1 | kerberos-kdc | default)', description: "Modern KDCs reject an unauthenticated AS-REQ. The c | +| `ID` | 2 | 2 | id-identifier | ugh 38473) plus predictable transaction IDs ({{cve\|CVE}}-2024-52616) in **Avahi**, | +| `SSID` | 2 | 2 | ssid | st}}/{{multicast\|multicast}} on stadium SSIDs entirely, or deploy [[mdns-dns-sd\|mDNS] | +| `MRZ` | 2 | 1 | mrz | data without **BAC** (legacy 3DES from MRZ) or **PACE** (modern {{ecdh\|ECDH}} from | +| `DR` | 2 | 1 | ospf-dr | ed Router ({{ospf-dr\|DR}})\*\* and Backup DR β€” the DR is the only neighbour every ro | +| `FTM` | 2 | 1 | ftm | icated UWB anchors. **Honest verdict:** FTM is _good enough_ for room-level indoor | +| `PHY` | 2 | 1 | phy | spacing, 250 kbit/s data rate. Sub-GHz PHYs at 868 MHz (Europe, 20 kbit/s {{bpsk\|BP | +| `ISN` | 1 | 1 | isn | 48]]\*\* and the cryptographically-random ISNs every modern stack uses.', credi | +| `X25519MLKEM768` | 1 | 1 | pq-ciphersuite | OpenSSL 3.5's default keyshare is now \`X25519MLKEM768 + {{x25519\|X25519}}\`.` }, | +| `ROA` | 1 | 1 | roa | in to {{ripe-ncc\|RIPE NCC}} and edited ROAs to make legitimate prefixes {{rpki\|RPKI | +| `MED` | 1 | 1 | med | r {{autonomous-system\|AS}}.\*\* Comparing MEDs cross-{{autonomous-system\|AS}} is meani | +| `SFU` | 1 | 1 | sfu | ption\|encryption}} that travels through SFUs without decryption. [[pioneer:justin-ub | +| `WAN` | 1 | 1 | wan-acr | GIGA Path, some specialised enterprise WANs) it works well. Where it does not work | +| `SCP` | 1 | 1 | scp-copy | e protocol that was supposed to replace SCP is finally replacing it.' }, | +| `CVE` | 1 | 1 | cve | s not changed. The ecosystem has. Major CVEs in major implementations: \*\*{{cve\|CVE}} | +| `VLAN` | 1 | 1 | vlan | agline: 'Advanced Layer 2-3 topics β€” VLANs, spanning tree, IPv6 migration, {{arp-c | +| `UI` | 1 | 1 | ui | because of its simplicity, but complex UIs with deeply nested data often outgrow i | +| `LLM` | 1 | 1 | llm | s {{json\|JSON}} Schema definitions that LLMs can understand), resource access (files | +| `KEEPALIVE` | 1 | 1 | bgp-keepalive | ion', description: 'Routers send KEEPALIVEs every ~30 seconds to prove liveness. UP | +| `UPDATE` | 1 | 1 | bgp-update | Es every ~30 seconds to prove liveness. UPDATEs flow whenever routes change. {{notifica | +| `UUID` | 1 | 1 | uuid | sig\|SIG}}-assigned) or 128-bit (vendor) UUIDs. Default {{att-mtu\|ATT}} {{mtu\|MTU}} is | +| `DC` | 1 | 1 | dc-domain-controller | r this date, {{ad-active-directory\|AD}} DCs refuse Kerberos PKINIT with weakly-boun | +| `SPN` | 1 | 1 | spn | **Cure:** register both short and FQDN SPNs in the keytab; set `dns_canonicalize_ho | +| `APDU` | 1 | 1 | apdu | the reader speaks **{{iso\|ISO}} 7816-4 APDUs**: 4-byte header `CLA INS P1 P2` + opti | +| `LSDB` | 1 | 1 | lsdb | le. Areas (Area 0 is the backbone) keep LSDBs scoped so the {{spf\|SPF}} computation s | +| `SRLG` | 1 | 1 | srlg | (include/exclude admin groups, exclude SRLGs). Carried in the new Flexible Algorithm | +| `TLV` | 1 | 1 | tlv | ough Opaque LSAs and Router Information TLVs.' }, { title: 'OSPF has reliable | +| `NIC` | 1 | 1 | nic | DNs offload to [[tls\|TLS]]-acceleration NICs (kTLS); plain servers should expect hig | +| `BLE` | 1 | 1 | ble | reshold _and_ the credential is valid β†’ BLE returns Unlock granted/denied. [[nfc\|NF | +| `U2` | 1 | 1 | u2-chip | ng. AirTag 2 (January 2026) carries the U2 alongside the anti-stalking hardware up | +| `U1` | 1 | 1 | u1-chip | {{u1-chip\|U1}} ⇄ {{u1-chip\|U1}}** and **U1 ⇄ {{nxp\|NXP}} / {{qorvo\|Qorvo}}\*\* combi | +| `FFD` | 1 | 1 | ffd | unslotted CSMA-CA in most deployments (FFDs as routers, RFDs as end-devices), with | +| `RFD` | 1 | 1 | rfd | A in most deployments (FFDs as routers, RFDs as end-devices), with optional beacon-m | ## Known protocol (needs link) (7) -| Acronym | Count | Files | Suggested ID | Sample | -|---|---:|---:|---|---| -| `UWB` | 74 | 2 | uwb | s + {{ble\|BLE}} proximity + {{ble\|BLE}}/UWB ranged β€” three transports, one credenti | -| `NFC` | 37 | 2 | nfc | the ISM band', description: "All NFC variants operate at a carrier of 13.56 | -| `HTTPS` | 19 | 9 | http1 | he proximate cause of the industry-wide HTTPS-everywhere push.' }, { | -| `IP` | 9 | 6 | ip | groups efficiently and to hide users\' IPs from each other. BitTorrent uses centra | -| `UDP` | 2 | 1 | udp | e 40-byte [[ipv6\|IPv6]]+{{tcp-rst\|TCP}}/UDP header to 1–4 bytes), {{aes\|AES}}-CTR { | -| `QUIC` | 2 | 1 | quic | om S1/S2 padding. AWG 2.0 adds optional QUIC/{{dns-resolution\|DNS}} protocol mimicry | -| `OAUTH2` | 1 | 1 | oauth2 | GIN}} or a {{sasl\|SASL}} mechanism like OAUTH2. The server grants access to the user's | +| Acronym | Count | Files | Suggested ID | Sample | +| -------- | ----: | ----: | ------------ | --------------------------------------------------------------------------------------- | +| `UWB` | 74 | 2 | uwb | s + {{ble\|BLE}} proximity + {{ble\|BLE}}/UWB ranged β€” three transports, one credenti | +| `NFC` | 37 | 2 | nfc | the ISM band', description: "All NFC variants operate at a carrier of 13.56 | +| `HTTPS` | 19 | 9 | http1 | he proximate cause of the industry-wide HTTPS-everywhere push.' }, { | +| `IP` | 9 | 6 | ip | groups efficiently and to hide users\' IPs from each other. BitTorrent uses centra | +| `UDP` | 2 | 1 | udp | e 40-byte [[ipv6\|IPv6]]+{{tcp-rst\|TCP}}/UDP header to 1–4 bytes), {{aes\|AES}}-CTR { | +| `QUIC` | 2 | 1 | quic | om S1/S2 padding. AWG 2.0 adds optional QUIC/{{dns-resolution\|DNS}} protocol mimicry | +| `OAUTH2` | 1 | 1 | oauth2 | GIN}} or a {{sasl\|SASL}} mechanism like OAUTH2. The server grants access to the user's | ## HTTP verbs (4) -| Acronym | Count | Files | Suggested ID | Sample | -|---|---:|---:|---|---| -| `POST` | 22 | 10 | β€” | supports only GET \u2014 no headers, no POST, no status codes.' }, { ye | -| `DELETE` | 8 | 5 | β€” | 1]], using its methods (GET, POST, PUT, DELETE), status codes, and headers to implemen | -| `OPTIONS` | 2 | 2 | β€” | description: "After GET PROCESSING OPTIONS (returning AIP+{{afl\|AFL}}) and {{read- | -| `PATCH` | 1 | 1 | β€” | T (read), POST (create), PUT (replace), PATCH (partial {{bgp-update\|update}}), DELETE | - +| Acronym | Count | Files | Suggested ID | Sample | +| --------- | ----: | ----: | ------------ | -------------------------------------------------------------------------------------- | +| `POST` | 22 | 10 | β€” | supports only GET \u2014 no headers, no POST, no status codes.' }, { ye | +| `DELETE` | 8 | 5 | β€” | 1]], using its methods (GET, POST, PUT, DELETE), status codes, and headers to implemen | +| `OPTIONS` | 2 | 2 | β€” | description: "After GET PROCESSING OPTIONS (returning AIP+{{afl\|AFL}}) and {{read- | +| `PATCH` | 1 | 1 | β€” | T (read), POST (create), PUT (replace), PATCH (partial {{bgp-update\|update}}), DELETE | diff --git a/scripts/output/term-audit.md b/scripts/output/term-audit.md index af68dfa..1b41feb 100644 --- a/scripts/output/term-audit.md +++ b/scripts/output/term-audit.md @@ -11,940 +11,1043 @@ Generated: 2026-05-21T14:48:17.867Z Add these to `src/lib/data/rfcs.ts`. Sorted by how many files mention them. -| RFC | Files | Sample mention | -|---|---:|---| -| RFC 1631 | 1 | ion, ([[rfc:1918\|RFC 1918]] + RFC 1631) β€” the middlebox that bought | -| RFC 8899 | 1 | ocols must implement PLPMTUD (RFC 8899)." }, { title: 'IPs | -| RFC 1827 | 1 | rtly thereafter contribute to RFC 1827 (ESP).' }, { title: 'F | -| RFC 7619 | 1 | perating networks (null-auth, RFC 7619)' ], codeExample: { langu | -| RFC 8229 | 1 | rvive Wi-Fi-to-LTE handoff. **RFC 8229 (IKE/ESP over [[tcp\|TCP]])** | -| RFC 9347 | 1 | date: '2023-08', title: 'RFC 9347 β€” IP-TFS (Traffic Flow Securi | -| RFC 4120 | 1 | port: 88, year: 1988, rfc: 'RFC 4120', oneLiner: 'The three-hea | -| RFC 6761 | 1 | iction over ICANN', text: 'RFC 6761 (February 2013) uses {{iana\|I | -| RFC 9665 | 1 | date: '2025-06', title: 'RFC 9665 β€” SRP (Service Registration P | -| RFC 3264 | 1 | ]), [[sdp\|SDP]] offer/answer (RFC 3264), and **every** revision of { | -| RFC 4577 | 1 | ', 'MPLS-VPN PE-CE peering (RFC 4577)', 'Mid-tier ISP IGP (tier- | -| RFC 5709 | 1 | C}}-SHA-256** authentication (RFC 5709 for v2, RFC 7166 Authenticati | -| RFC 7166 | 1 | hentication (RFC 5709 for v2, RFC 7166 Authentication Trailer for v3 | -| RFC 7938 | 1 | erlay where pure-[[bgp\|BGP]] (RFC 7938) is unjustified', 'SD-WAN o | -| RFC 8405 | 1 | hem out at `MaxAge = 3600 s`. RFC 8405 SPF back-off (INITIAL/SHORT_W | -| RFC 8665 | 1 | ler for v3). Segment Routing (RFC 8665/8666) and SRv6 (RFC 9513) rid | -| RFC 9355 | 1 | r sub-second loss detection β€” RFC 9355 Strict-Mode requires BFD up b | -| RFC 9513 | 1 | ing (RFC 8665/8666) and SRv6 (RFC 9513) ride on top via Opaque LSAs; | -| RFC 9667 | 1 | { date: '2024', title: 'RFC 9667 β€” Dynamic Flooding on Dense G | -| RFC 8922 | 1 | β€” that\'s not good enough."* RFC 8922 (2020) mentions WireGuard for | +| RFC | Files | Sample mention | +| -------- | ----: | ---------------------------------------------------------------------- | +| RFC 1631 | 1 | ion, ([[rfc:1918\|RFC 1918]] + RFC 1631) β€” the middlebox that bought | +| RFC 8899 | 1 | ocols must implement PLPMTUD (RFC 8899)." }, { title: 'IPs | +| RFC 1827 | 1 | rtly thereafter contribute to RFC 1827 (ESP).' }, { title: 'F | +| RFC 7619 | 1 | perating networks (null-auth, RFC 7619)' ], codeExample: { langu | +| RFC 8229 | 1 | rvive Wi-Fi-to-LTE handoff. **RFC 8229 (IKE/ESP over [[tcp\|TCP]])** | +| RFC 9347 | 1 | date: '2023-08', title: 'RFC 9347 β€” IP-TFS (Traffic Flow Securi | +| RFC 4120 | 1 | port: 88, year: 1988, rfc: 'RFC 4120', oneLiner: 'The three-hea | +| RFC 6761 | 1 | iction over ICANN', text: 'RFC 6761 (February 2013) uses {{iana\|I | +| RFC 9665 | 1 | date: '2025-06', title: 'RFC 9665 β€” SRP (Service Registration P | +| RFC 3264 | 1 | ]), [[sdp\|SDP]] offer/answer (RFC 3264), and **every** revision of { | +| RFC 4577 | 1 | ', 'MPLS-VPN PE-CE peering (RFC 4577)', 'Mid-tier ISP IGP (tier- | +| RFC 5709 | 1 | C}}-SHA-256\*\* authentication (RFC 5709 for v2, RFC 7166 Authenticati | +| RFC 7166 | 1 | hentication (RFC 5709 for v2, RFC 7166 Authentication Trailer for v3 | +| RFC 7938 | 1 | erlay where pure-[[bgp\|BGP]] (RFC 7938) is unjustified', 'SD-WAN o | +| RFC 8405 | 1 | hem out at `MaxAge = 3600 s`. RFC 8405 SPF back-off (INITIAL/SHORT_W | +| RFC 8665 | 1 | ler for v3). Segment Routing (RFC 8665/8666) and SRv6 (RFC 9513) rid | +| RFC 9355 | 1 | r sub-second loss detection β€” RFC 9355 Strict-Mode requires BFD up b | +| RFC 9513 | 1 | ing (RFC 8665/8666) and SRv6 (RFC 9513) ride on top via Opaque LSAs; | +| RFC 9667 | 1 | { date: '2024', title: 'RFC 9667 β€” Dynamic Flooding on Dense G | +| RFC 8922 | 1 | β€” that\'s not good enough."\* RFC 8922 (2020) mentions WireGuard for | ## 2. Pioneers named without `[[pioneer:…]]` Each row is the first unwrapped mention in a file. Apply once per section, not every occurrence. -| Pioneer | Files | -|---|---:| -| Vint Cerf | 5 | -| Jon Postel | 4 | -| Van Jacobson | 4 | -| Tim Berners-Lee | 2 | -| Henning Schulzrinne | 2 | -| Jonathan Rosenberg | 2 | -| Justin Uberti | 2 | -| Ian Hickson | 2 | -| Jim Kardach | 2 | -| Marty Cooper | 2 | -| Andrew Viterbi | 2 | -| Ray Tomlinson | 1 | -| Bob Metcalfe | 1 | -| Yakov Rekhter | 1 | -| Steve Deering | 1 | -| Bob Kahn | 1 | -| Jim Roskind | 1 | -| Paul Mockapetris | 1 | -| Eric Rescorla | 1 | -| Taher Elgamal | 1 | -| Roy Fielding | 1 | -| Mike Belshe | 1 | -| Jaap Haartsen | 1 | -| Sven Mattisson | 1 | -| Irwin Jacobs | 1 | -| Phil Karn | 1 | -| Stuart Cheshire | 1 | -| Charles Walton | 1 | -| Radia Perlman | 1 | -| Bob Heile | 1 | +| Pioneer | Files | +| ------------------- | ----: | +| Vint Cerf | 5 | +| Jon Postel | 4 | +| Van Jacobson | 4 | +| Tim Berners-Lee | 2 | +| Henning Schulzrinne | 2 | +| Jonathan Rosenberg | 2 | +| Justin Uberti | 2 | +| Ian Hickson | 2 | +| Jim Kardach | 2 | +| Marty Cooper | 2 | +| Andrew Viterbi | 2 | +| Ray Tomlinson | 1 | +| Bob Metcalfe | 1 | +| Yakov Rekhter | 1 | +| Steve Deering | 1 | +| Bob Kahn | 1 | +| Jim Roskind | 1 | +| Paul Mockapetris | 1 | +| Eric Rescorla | 1 | +| Taher Elgamal | 1 | +| Roy Fielding | 1 | +| Mike Belshe | 1 | +| Jaap Haartsen | 1 | +| Sven Mattisson | 1 | +| Irwin Jacobs | 1 | +| Phil Karn | 1 | +| Stuart Cheshire | 1 | +| Charles Walton | 1 | +| Radia Perlman | 1 | +| Bob Heile | 1 | ### Per-file pioneer hits **`src/lib/data/book/parts/layer-2-3.ts`** -- L226:20 β€” `[[pioneer:vint-cerf|Vint Cerf]]` Β· _eriment.', attribution: 'Vint Cerf, Linux.conf.au 2011' },_ + +- L226:20 β€” `[[pioneer:vint-cerf|Vint Cerf]]` Β· _eriment.', attribution: 'Vint Cerf, Linux.conf.au 2011' },_ **`src/lib/data/book/parts/story-of-the-internet.ts`** -- L106:14 β€” `[[pioneer:jon-postel|Jon Postel]]` Β· _Jon_Postel.jpg', alt: 'Jon Postel β€” editor of RFC 791, 792, and_ -- L244:14 β€” `[[pioneer:tim-berners-lee|Tim Berners-Lee]]` Β· _Web_Server.jpg', alt: 'Tim Berners-Lee\'s NeXTcube β€” the world\'s fi_ -- L154:14 β€” `[[pioneer:van-jacobson|Van Jacobson]]` Β· _n_Jacobson.jpg', alt: 'Van Jacobson β€” co-author of the 1988 paper_ + +- L106:14 β€” `[[pioneer:jon-postel|Jon Postel]]` Β· _Jon_Postel.jpg', alt: 'Jon Postel β€” editor of RFC 791, 792, and_ +- L244:14 β€” `[[pioneer:tim-berners-lee|Tim Berners-Lee]]` Β· _Web_Server.jpg', alt: 'Tim Berners-Lee\'s NeXTcube β€” the world\'s fi_ +- L154:14 β€” `[[pioneer:van-jacobson|Van Jacobson]]` Β· _n_Jacobson.jpg', alt: 'Van Jacobson β€” co-author of the 1988 paper_ **`src/lib/data/book/parts/utilities-security.ts`** -- L236:20 β€” `[[pioneer:vint-cerf|Vint Cerf]]` Β· _ry 2024.', attribution: 'Vint Cerf, Internet History list obitua_ -- L391:16 β€” `[[pioneer:ray-tomlinson|Ray Tomlinson]]` Β· _: 'narrative', title: 'Ray Tomlinson Picked the @', text: `_ + +- L236:20 β€” `[[pioneer:vint-cerf|Vint Cerf]]` Β· _ry 2024.', attribution: 'Vint Cerf, Internet History list obitua_ +- L391:16 β€” `[[pioneer:ray-tomlinson|Ray Tomlinson]]` Β· _: 'narrative', title: 'Ray Tomlinson Picked the @', text: `_ **`src/lib/data/category-stories/network-foundations.ts`** -- L74:13 β€” `[[pioneer:vint-cerf|Vint Cerf]]` Β· _jpg' }, { name: 'Vint Cerf', years: '1943–', t_ -- L64:13 β€” `[[pioneer:bob-metcalfe|Bob Metcalfe]]` Β· _people: [ { name: 'Bob Metcalfe', years: '1946–', t_ -- L92:13 β€” `[[pioneer:yakov-rekhter|Yakov Rekhter]]` Β· _ks.' }, { name: 'Yakov Rekhter', years: 'c. 1950–',_ -- L100:13 β€” `[[pioneer:steve-deering|Steve Deering]]` Β· _et.' }, { name: 'Steve Deering', years: '1951–', t_ + +- L74:13 β€” `[[pioneer:vint-cerf|Vint Cerf]]` Β· _jpg' }, { name: 'Vint Cerf', years: '1943–', t_ +- L64:13 β€” `[[pioneer:bob-metcalfe|Bob Metcalfe]]` Β· _people: [ { name: 'Bob Metcalfe', years: '1946–', t_ +- L92:13 β€” `[[pioneer:yakov-rekhter|Yakov Rekhter]]` Β· _ks.' }, { name: 'Yakov Rekhter', years: 'c. 1950–',_ +- L100:13 β€” `[[pioneer:steve-deering|Steve Deering]]` Β· _et.' }, { name: 'Steve Deering', years: '1951–', t_ **`src/lib/data/category-stories/realtime-av.ts`** -- L35:13 β€” `[[pioneer:van-jacobson|Van Jacobson]]` Β· _jpg' }, { name: 'Van Jacobson', years: '1950\u2013',_ -- L25:13 β€” `[[pioneer:henning-schulzrinne|Henning Schulzrinne]]` Β· _people: [ { name: 'Henning Schulzrinne', years: 'c. 1962\u2013'_ -- L116:13 β€” `[[pioneer:jonathan-rosenberg|Jonathan Rosenberg]]` Β· _ng.' }, { name: 'Jonathan Rosenberg', years: '', title:_ -- L221:13 β€” `[[pioneer:justin-uberti|Justin Uberti]]` Β· _people: [ { name: 'Justin Uberti', years: '', title:_ + +- L35:13 β€” `[[pioneer:van-jacobson|Van Jacobson]]` Β· _jpg' }, { name: 'Van Jacobson', years: '1950\u2013',_ +- L25:13 β€” `[[pioneer:henning-schulzrinne|Henning Schulzrinne]]` Β· _people: [ { name: 'Henning Schulzrinne', years: 'c. 1962\u2013'_ +- L116:13 β€” `[[pioneer:jonathan-rosenberg|Jonathan Rosenberg]]` Β· _ng.' }, { name: 'Jonathan Rosenberg', years: '', title:_ +- L221:13 β€” `[[pioneer:justin-uberti|Justin Uberti]]` Β· _people: [ { name: 'Justin Uberti', years: '', title:_ **`src/lib/data/category-stories/transport.ts`** -- L25:13 β€” `[[pioneer:vint-cerf|Vint Cerf]]` Β· _people: [ { name: 'Vint Cerf', years: '1943\u2013',_ -- L35:13 β€” `[[pioneer:bob-kahn|Bob Kahn]]` Β· _jpg' }, { name: 'Bob Kahn', years: '1938\u2013',_ -- L45:13 β€” `[[pioneer:jon-postel|Jon Postel]]` Β· _jpg' }, { name: 'Jon Postel', years: '1943\u20131998_ -- L193:13 β€” `[[pioneer:jim-roskind|Jim Roskind]]` Β· _people: [ { name: 'Jim Roskind', years: '1960s\u2013',_ + +- L25:13 β€” `[[pioneer:vint-cerf|Vint Cerf]]` Β· _people: [ { name: 'Vint Cerf', years: '1943\u2013',_ +- L35:13 β€” `[[pioneer:bob-kahn|Bob Kahn]]` Β· _jpg' }, { name: 'Bob Kahn', years: '1938\u2013',_ +- L45:13 β€” `[[pioneer:jon-postel|Jon Postel]]` Β· _jpg' }, { name: 'Jon Postel', years: '1943\u20131998_ +- L193:13 β€” `[[pioneer:jim-roskind|Jim Roskind]]` Β· _people: [ { name: 'Jim Roskind', years: '1960s\u2013',_ **`src/lib/data/category-stories/utilities.ts`** -- L25:13 β€” `[[pioneer:jon-postel|Jon Postel]]` Β· _es." }, { name: 'Jon Postel', years: '1943–1998',_ -- L129:13 β€” `[[pioneer:paul-mockapetris|Paul Mockapetris]]` Β· _people: [ { name: 'Paul Mockapetris', years: '1948–', t_ -- L281:13 β€” `[[pioneer:eric-rescorla|Eric Rescorla]]` Β· _et.' }, { name: 'Eric Rescorla', years: '', title:_ -- L263:13 β€” `[[pioneer:taher-elgamal|Taher Elgamal]]` Β· _people: [ { name: 'Taher Elgamal', years: '1955–', t_ + +- L25:13 β€” `[[pioneer:jon-postel|Jon Postel]]` Β· _es." }, { name: 'Jon Postel', years: '1943–1998',_ +- L129:13 β€” `[[pioneer:paul-mockapetris|Paul Mockapetris]]` Β· _people: [ { name: 'Paul Mockapetris', years: '1948–', t_ +- L281:13 β€” `[[pioneer:eric-rescorla|Eric Rescorla]]` Β· _et.' }, { name: 'Eric Rescorla', years: '', title:_ +- L263:13 β€” `[[pioneer:taher-elgamal|Taher Elgamal]]` Β· _people: [ { name: 'Taher Elgamal', years: '1955–', t_ **`src/lib/data/category-stories/web-api.ts`** -- L17:36 β€” `[[pioneer:tim-berners-lee|Tim Berners-Lee]]` Β· _t: 'The NeXT computer used by Tim Berners-Lee at CERN, the world\'s first w_ -- L37:13 β€” `[[pioneer:roy-fielding|Roy Fielding]]` Β· _jpg' }, { name: 'Roy Fielding', years: '1965\u2013',_ -- L129:13 β€” `[[pioneer:mike-belshe|Mike Belshe]]` Β· _people: [ { name: 'Mike Belshe', years: '', title:_ -- L245:13 β€” `[[pioneer:ian-hickson|Ian Hickson]]` Β· _ns." }, { name: 'Ian Hickson', years: '1976\u2013',_ + +- L17:36 β€” `[[pioneer:tim-berners-lee|Tim Berners-Lee]]` Β· _t: 'The NeXT computer used by Tim Berners-Lee at CERN, the world\'s first w_ +- L37:13 β€” `[[pioneer:roy-fielding|Roy Fielding]]` Β· _jpg' }, { name: 'Roy Fielding', years: '1965\u2013',_ +- L129:13 β€” `[[pioneer:mike-belshe|Mike Belshe]]` Β· _people: [ { name: 'Mike Belshe', years: '', title:_ +- L245:13 β€” `[[pioneer:ian-hickson|Ian Hickson]]` Β· _ns." }, { name: 'Ian Hickson', years: '1976\u2013',_ **`src/lib/data/category-stories/wireless.ts`** -- L50:13 β€” `[[pioneer:jaap-haartsen|Jaap Haartsen]]` Β· _em.' }, { name: 'Jaap Haartsen', years: '1963–', t_ -- L58:13 β€” `[[pioneer:sven-mattisson|Sven Mattisson]]` Β· _5)." }, { name: 'Sven Mattisson', years: '1956–', t_ -- L66:13 β€” `[[pioneer:jim-kardach|Jim Kardach]]` Β· _ts.' }, { name: 'Jim Kardach', years: '1958–', t_ -- L26:13 β€” `[[pioneer:marty-cooper|Marty Cooper]]` Β· _people: [ { name: 'Marty Cooper', years: '1928–', t_ -- L34:13 β€” `[[pioneer:andrew-viterbi|Andrew Viterbi]]` Β· _e*.' }, { name: 'Andrew Viterbi', years: '1935–', t_ + +- L50:13 β€” `[[pioneer:jaap-haartsen|Jaap Haartsen]]` Β· _em.' }, { name: 'Jaap Haartsen', years: '1963–', t_ +- L58:13 β€” `[[pioneer:sven-mattisson|Sven Mattisson]]` Β· _5)." }, { name: 'Sven Mattisson', years: '1956–', t_ +- L66:13 β€” `[[pioneer:jim-kardach|Jim Kardach]]` Β· _ts.' }, { name: 'Jim Kardach', years: '1958–', t_ +- L26:13 β€” `[[pioneer:marty-cooper|Marty Cooper]]` Β· _people: [ { name: 'Marty Cooper', years: '1928–', t_ +- L34:13 β€” `[[pioneer:andrew-viterbi|Andrew Viterbi]]` Β· _e\*.' }, { name: 'Andrew Viterbi', years: '1935–', t_ **`src/lib/data/concept-foundations.ts`** -- L72:14 β€” `[[pioneer:vint-cerf|Vint Cerf]]` Β· _people: [ { name: 'Vint Cerf', years: '1943 –',_ -- L82:14 β€” `[[pioneer:jon-postel|Jon Postel]]` Β· _' }, { name: 'Jon Postel', years: '1943 – 1998',_ -- L479:11 β€” `[[pioneer:van-jacobson|Van Jacobson]]` Β· _-Van_Jacobson.jpg', alt: 'Van Jacobson β€” co-author of the 1988 paper_ + +- L72:14 β€” `[[pioneer:vint-cerf|Vint Cerf]]` Β· _people: [ { name: 'Vint Cerf', years: '1943 –',_ +- L82:14 β€” `[[pioneer:jon-postel|Jon Postel]]` Β· _' }, { name: 'Jon Postel', years: '1943 – 1998',_ +- L479:11 β€” `[[pioneer:van-jacobson|Van Jacobson]]` Β· _-Van_Jacobson.jpg', alt: 'Van Jacobson β€” co-author of the 1988 paper_ **`src/lib/data/outages.ts`** -- L339:13 β€” `[[pioneer:van-jacobson|Van Jacobson]]` Β· _'tcp'], cast: [ { name: 'Van Jacobson (LBL)', role: "Co-author of t_ + +- L339:13 β€” `[[pioneer:van-jacobson|Van Jacobson]]` Β· _'tcp'], cast: [ { name: 'Van Jacobson (LBL)', role: "Co-author of t_ **`src/lib/data/protocols/bluetooth.ts`** -- L215:180 β€” `[[pioneer:jim-kardach|Jim Kardach]]` Β· _ho united Denmark and Norway. Jim Kardach at {{intel\|Intel}} proposed t_ + +- L215:180 β€” `[[pioneer:jim-kardach|Jim Kardach]]` Β· _ho united Denmark and Norway. Jim Kardach at {{intel\|Intel}} proposed t_ **`src/lib/data/protocols/cellular.ts`** -- L366:54 β€” `[[pioneer:marty-cooper|Marty Cooper]]` Β· _3, Sixth Avenue, Manhattan.** Marty Cooper of Motorola dialed Joel Engel_ -- L370:276 β€” `[[pioneer:andrew-viterbi|Andrew Viterbi]]` Β· _cognizer. It made nothing for Andrew Viterbi directly; it made Qualcomm ev_ -- L378:71 β€” `[[pioneer:irwin-jacobs|Irwin Jacobs]]` Β· _ted for TDMA; later that year Irwin Jacobs presented CDMA and *"no one f_ + +- L366:54 β€” `[[pioneer:marty-cooper|Marty Cooper]]` Β· _3, Sixth Avenue, Manhattan.\*\* Marty Cooper of Motorola dialed Joel Engel_ +- L370:276 β€” `[[pioneer:andrew-viterbi|Andrew Viterbi]]` Β· _cognizer. It made nothing for Andrew Viterbi directly; it made Qualcomm ev_ +- L378:71 β€” `[[pioneer:irwin-jacobs|Irwin Jacobs]]` Β· _ted for TDMA; later that year Irwin Jacobs presented CDMA and \*"no one f_ **`src/lib/data/protocols/ipsec.ts`** -- L313:12 β€” `[[pioneer:phil-karn|Phil Karn]]` Β· _funFacts: [ { title: 'Phil Karn sued the US State Department_ + +- L313:12 β€” `[[pioneer:phil-karn|Phil Karn]]` Β· _funFacts: [ { title: 'Phil Karn sued the US State Department_ **`src/lib/data/protocols/mdns-dns-sd.ts`** -- L303:12 β€” `[[pioneer:stuart-cheshire|Stuart Cheshire]]` Β· _1 years.' }, { title: 'Stuart Cheshire also wrote a tank game', t_ + +- L303:12 β€” `[[pioneer:stuart-cheshire|Stuart Cheshire]]` Β· _1 years.' }, { title: 'Stuart Cheshire also wrote a tank game', t_ **`src/lib/data/protocols/nat-traversal.ts`** -- L297:12 β€” `[[pioneer:jonathan-rosenberg|Jonathan Rosenberg]]` Β· _relays.' }, { title: 'Jonathan Rosenberg is a top-10 RFC author of all_ -- L226:12 β€” `[[pioneer:justin-uberti|Justin Uberti]]` Β· _date: '2024-11', title: 'Justin Uberti joins OpenAI to lead Real-Tim_ + +- L297:12 β€” `[[pioneer:jonathan-rosenberg|Jonathan Rosenberg]]` Β· _relays.' }, { title: 'Jonathan Rosenberg is a top-10 RFC author of all_ +- L226:12 β€” `[[pioneer:justin-uberti|Justin Uberti]]` Β· _date: '2024-11', title: 'Justin Uberti joins OpenAI to lead Real-Tim_ **`src/lib/data/protocols/nfc.ts`** -- L401:12 β€” `[[pioneer:charles-walton|Charles Walton]]` Β· _funFacts: [ { title: 'Charles Walton died the same year Google Wal_ + +- L401:12 β€” `[[pioneer:charles-walton|Charles Walton]]` Β· _funFacts: [ { title: 'Charles Walton died the same year Google Wal_ **`src/lib/data/protocols/ospf.ts`** -- L285:12 β€” `[[pioneer:radia-perlman|Radia Perlman]]` Β· _ip\|IP]].' }, { title: 'Radia Perlman designed the competitor, not_ + +- L285:12 β€” `[[pioneer:radia-perlman|Radia Perlman]]` Β· _ip\|IP]].' }, { title: 'Radia Perlman designed the competitor, not_ **`src/lib/data/protocols/rtp.ts`** -- L167:9 β€” `[[pioneer:henning-schulzrinne|Henning Schulzrinne]]` Β· _287838924022%29.jpg', alt: 'Henning Schulzrinne, co-creator of RTP, speaking_ + +- L167:9 β€” `[[pioneer:henning-schulzrinne|Henning Schulzrinne]]` Β· _287838924022%29.jpg', alt: 'Henning Schulzrinne, co-creator of RTP, speaking_ **`src/lib/data/protocols/sse.ts`** -- L128:9 β€” `[[pioneer:ian-hickson|Ian Hickson]]` Β· _ting_Day_Three.jpeg', alt: 'Ian Hickson at a CSS Working Group meetin_ + +- L128:9 β€” `[[pioneer:ian-hickson|Ian Hickson]]` Β· _ting_Day_Three.jpeg', alt: 'Ian Hickson at a CSS Working Group meetin_ **`src/lib/data/protocols/zigbee.ts`** -- L384:12 β€” `[[pioneer:bob-heile|Bob Heile]]` Β· _rmarket." }, { title: 'Bob Heile was a founding member of IEEE_ + +- L384:12 β€” `[[pioneer:bob-heile|Bob Heile]]` Β· _rmarket." }, { title: 'Bob Heile was a founding member of IEEE_ ## 3. Concepts in `concepts.ts` mentioned without `{{…}}` Editorial rule: wrap on first appearance per section, not every time. `low` priority terms are common English words and should only be wrapped where the technical sense is the focus. -| Term | Files | -|---|---:| -| Protocol | 86 | -| Port | 63 | -| Latency | 61 | -| Packet | 43 | -| Frame | 26 | -| Google | 24 | -| Stream | 22 | -| Apple | 21 | -| Handshake | 20 | -| Segment | 17 | -| Hop | 17 | -| Linux | 14 | -| Encryption | 13 | -| Payload | 12 | -| Cloudflare | 11 | -| Socket | 9 | -| Certificate | 9 | -| Bandwidth | 9 | -| Cisco | 9 | -| Matter | 8 | -| ARPANET | 8 | -| DARPA | 8 | -| Meta | 7 | -| Datagram | 7 | -| Multipath | 7 | -| Checksum | 6 | -| Signaling | 6 | -| Topic | 5 | -| Peering | 5 | -| Congestion Control | 5 | -| Encapsulation | 5 | -| Microsoft | 5 | -| Public Key | 4 | -| Bufferbloat | 4 | -| RSA | 4 | -| ping | 4 | -| Multi-homing | 4 | -| DNS Resolution | 4 | -| SFTP | 4 | -| Stateless | 4 | -| CCC Digital Key | 4 | -| Anycast | 4 | -| Fragmentation | 4 | -| Failover | 4 | -| BBRv3 | 3 | -| Three-Way Handshake | 3 | -| SYN-ACK | 3 | -| AV1 | 3 | -| Multiplexing | 3 | -| Pipelining | 3 | -| Spectrum | 3 | -| WPA3 | 3 | -| Auracast | 3 | -| Channel Sounding | 3 | -| Thread | 3 | -| Direct-to-Cell | 3 | -| Codec | 3 | -| HPACK | 3 | -| CUBIC | 3 | -| QPACK | 3 | -| _…133 more_ | | +| Term | Files | +| ------------------- | ----: | +| Protocol | 86 | +| Port | 63 | +| Latency | 61 | +| Packet | 43 | +| Frame | 26 | +| Google | 24 | +| Stream | 22 | +| Apple | 21 | +| Handshake | 20 | +| Segment | 17 | +| Hop | 17 | +| Linux | 14 | +| Encryption | 13 | +| Payload | 12 | +| Cloudflare | 11 | +| Socket | 9 | +| Certificate | 9 | +| Bandwidth | 9 | +| Cisco | 9 | +| Matter | 8 | +| ARPANET | 8 | +| DARPA | 8 | +| Meta | 7 | +| Datagram | 7 | +| Multipath | 7 | +| Checksum | 6 | +| Signaling | 6 | +| Topic | 5 | +| Peering | 5 | +| Congestion Control | 5 | +| Encapsulation | 5 | +| Microsoft | 5 | +| Public Key | 4 | +| Bufferbloat | 4 | +| RSA | 4 | +| ping | 4 | +| Multi-homing | 4 | +| DNS Resolution | 4 | +| SFTP | 4 | +| Stateless | 4 | +| CCC Digital Key | 4 | +| Anycast | 4 | +| Fragmentation | 4 | +| Failover | 4 | +| BBRv3 | 3 | +| Three-Way Handshake | 3 | +| SYN-ACK | 3 | +| AV1 | 3 | +| Multiplexing | 3 | +| Pipelining | 3 | +| Spectrum | 3 | +| WPA3 | 3 | +| Auracast | 3 | +| Channel Sounding | 3 | +| Thread | 3 | +| Direct-to-Cell | 3 | +| Codec | 3 | +| HPACK | 3 | +| CUBIC | 3 | +| QPACK | 3 | +| _…133 more_ | | ### Per-file concept hits (high priority) **`src/lib/data/book/chapters.ts`** β€” 1 term(s) -- L48 β€” `{{encryption|encryption}}` Β· _each makes easy or hard.', 'encryption-basics': "What HTTPS actual_ + +- L48 β€” `{{encryption|encryption}}` Β· _each makes easy or hard.', 'encryption-basics': "What HTTPS actual_ **`src/lib/data/book/parts/async-iot.ts`** β€” 3 term(s) -- L71 β€” `{{topic|topic}}` Β· _agram β€” sensor publishes to a topic on a broker; subscriber recei_ -- L241 β€” `{{matter|Matter}}` Β· _CoAP Actually Runs β€” And the Matter Misconception', text:_ -- L124 β€” `{{broadcom|Broadcom}}` Β· _arrative', title: 'The Broadcom Acquisition, And Where AMQP G_ + +- L71 β€” `{{topic|topic}}` Β· _agram β€” sensor publishes to a topic on a broker; subscriber recei_ +- L241 β€” `{{matter|Matter}}` Β· _CoAP Actually Runs β€” And the Matter Misconception', text:_ +- L124 β€” `{{broadcom|Broadcom}}` Β· _arrative', title: 'The Broadcom Acquisition, And Where AMQP G_ **`src/lib/data/book/parts/famous-outages.ts`** β€” 5 term(s) -- L21 β€” `{{arpanet|arpanet}}` Β· _───────────────── { id: 'arpanet-1980', title: 'ARPANET 198_ -- L77 β€” `{{darpa|DARPA}}` Β· _elf.', credit: 'Image: DARPA / public domain, via Wikimedi_ -- L135 β€” `{{peering|peering}}` Β· _ng topology β€” each line a BGP peering relationship.', captio_ -- L534 β€” `{{meta|Meta}}` Β· _.jpg', alt: 'Facebook (Meta) Headquarters campus in Menlo_ -- L397 β€” `{{linux|Linux}}` Β· _.png', alt: 'Tux β€” the Linux mascot, a chubby cartoon peng_ + +- L21 β€” `{{arpanet|arpanet}}` Β· _───────────────── { id: 'arpanet-1980', title: 'ARPANET 198_ +- L77 β€” `{{darpa|DARPA}}` Β· _elf.', credit: 'Image: DARPA / public domain, via Wikimedi_ +- L135 β€” `{{peering|peering}}` Β· _ng topology β€” each line a BGP peering relationship.', captio_ +- L534 β€” `{{meta|Meta}}` Β· _.jpg', alt: 'Facebook (Meta) Headquarters campus in Menlo_ +- L397 β€” `{{linux|Linux}}` Β· _.png', alt: 'Tux β€” the Linux mascot, a chubby cartoon peng_ **`src/lib/data/book/parts/frontier.ts`** β€” 10 term(s) -- L274 β€” `{{arpanet|ARPANET}}` Β· _march_1977.png', alt: 'ARPANET logical map, March 1977 β€” the_ -- L277 β€” `{{darpa|DARPA}}` Β· _net.', credit: 'Image: DARPA / public domain, via Wikimedi_ -- L74 β€” `{{public-key|public key}}` Β· _metric cryptography diagram β€” public key encrypts, private key decrypt_ -- L74 β€” `{{private-key|private key}}` Β· _iagram β€” public key encrypts, private key decrypts.', caption:_ -- L103 β€” `{{bufferbloat|Bufferbloat}}` Β· _', title: 'The Problem Bufferbloat Created', text: `The m_ -- L205 β€” `{{peering|peering}}` Β· _topology with each line a BGP peering relationship.', captio_ -- L50 β€” `{{apple|Apple}}` Β· _pe: 'callout', title: 'Apple iOS 26 cliff: <2% to 25% in 9_ -- L337 β€” `{{nvidia|NVIDIA}}` Β· _rwan%29_22.png', alt: 'NVIDIA GB200 NVL72 GPU rack on displ_ -- L147 β€” `{{bbrv3|bbrv3}}` Β· _{ kind: 'frontier', id: 'bbrv3-default' } ] }, // ──_ -- L76 β€” `{{rsa|RSA}}` Β· _on. The classical primitives (RSA, {{ecdh\|ECDH}} on {{curve2551_ + +- L274 β€” `{{arpanet|ARPANET}}` Β· _march_1977.png', alt: 'ARPANET logical map, March 1977 β€” the_ +- L277 β€” `{{darpa|DARPA}}` Β· _net.', credit: 'Image: DARPA / public domain, via Wikimedi_ +- L74 β€” `{{public-key|public key}}` Β· _metric cryptography diagram β€” public key encrypts, private key decrypt_ +- L74 β€” `{{private-key|private key}}` Β· _iagram β€” public key encrypts, private key decrypts.', caption:_ +- L103 β€” `{{bufferbloat|Bufferbloat}}` Β· _', title: 'The Problem Bufferbloat Created', text: `The m_ +- L205 β€” `{{peering|peering}}` Β· _topology with each line a BGP peering relationship.', captio_ +- L50 β€” `{{apple|Apple}}` Β· _pe: 'callout', title: 'Apple iOS 26 cliff: <2% to 25% in 9_ +- L337 β€” `{{nvidia|NVIDIA}}` Β· _rwan%29_22.png', alt: 'NVIDIA GB200 NVL72 GPU rack on displ_ +- L147 β€” `{{bbrv3|bbrv3}}` Β· _{ kind: 'frontier', id: 'bbrv3-default' } ] }, // ──_ +- L76 β€” `{{rsa|RSA}}` Β· _on. The classical primitives (RSA, {{ecdh\|ECDH}} on {{curve2551_ **`src/lib/data/book/parts/how-to-learn-more.ts`** β€” 3 term(s) -- L50 β€” `{{arpanet|ARPANET}}` Β· _t_1974.svg.png', alt: 'ARPANET in 1974 β€” the network the fir_ -- L167 β€” `{{cloudflare|Cloudflare}}` Β· _go.svg.png', alt: 'The Cloudflare logo β€” a stylised orange clou_ -- L210 β€” `{{wireshark|Wireshark}}` Β· _screenshot.png', alt: 'Wireshark β€” packet capture with protoco_ + +- L50 β€” `{{arpanet|ARPANET}}` Β· _t_1974.svg.png', alt: 'ARPANET in 1974 β€” the network the fir_ +- L167 β€” `{{cloudflare|Cloudflare}}` Β· _go.svg.png', alt: 'The Cloudflare logo β€” a stylised orange clou_ +- L210 β€” `{{wireshark|Wireshark}}` Β· _screenshot.png', alt: 'Wireshark β€” packet capture with protoco_ **`src/lib/data/book/parts/layer-2-3.ts`** β€” 8 term(s) -- L485 β€” `{{arpanet|ARPANET}}` Β· _march_1977.png', alt: 'ARPANET logical map, March 1977 β€” pre_ -- L488 β€” `{{darpa|DARPA}}` Β· _aks.', credit: 'Image: DARPA / public domain, via Wikimedi_ -- L382 β€” `{{firewall|firewall}}` Β· _title: 'Dropping ICMP at the firewall is partially refusing to impl_ -- L171 β€” `{{checksum|checksum}}` Β· _t', title: 'ARP has no checksum and no authentication',_ -- L69 β€” `{{payload|payload}}` Β· _n MAC, source MAC, EtherType, payload, and FCS.', caption:_ -- L155 β€” `{{hop|hop}}` Β· _ket}} finds the next physical hop β€” [[arp\|STD 37]] has not been_ -- L226 β€” `{{linux|Linux}}` Β· _attribution: 'Vint Cerf, Linux.conf.au 2011' }, {_ -- L366 β€” `{{ping|ping}}` Β· _tion: 'Mike Muuss, on writing ping in December 1983' },_ + +- L485 β€” `{{arpanet|ARPANET}}` Β· _march_1977.png', alt: 'ARPANET logical map, March 1977 β€” pre_ +- L488 β€” `{{darpa|DARPA}}` Β· _aks.', credit: 'Image: DARPA / public domain, via Wikimedi_ +- L382 β€” `{{firewall|firewall}}` Β· _title: 'Dropping ICMP at the firewall is partially refusing to impl_ +- L171 β€” `{{checksum|checksum}}` Β· _t', title: 'ARP has no checksum and no authentication',_ +- L69 β€” `{{payload|payload}}` Β· _n MAC, source MAC, EtherType, payload, and FCS.', caption:_ +- L155 β€” `{{hop|hop}}` Β· _ket}} finds the next physical hop β€” [[arp\|STD 37]] has not been_ +- L226 β€” `{{linux|Linux}}` Β· _attribution: 'Vint Cerf, Linux.conf.au 2011' }, {_ +- L366 β€” `{{ping|ping}}` Β· _tion: 'Mike Muuss, on writing ping in December 1983' },_ **`src/lib/data/book/parts/patterns-failures.ts`** β€” 7 term(s) -- L115 β€” `{{latency|Latency}}` Β· _title: 'Bufferbloat β€” Latency Without Loss', text: `_ -- L78 β€” `{{handshake|handshake}}` Β· _', alt: 'TCP three-way handshake β€” SYN, SYN-ACK, ACK between c_ -- L175 β€” `{{congestion-control|Congestion Control}}` Β· _ory', title: 'A History of Congestion Control', synopsis: 'Tahoe β†’ Reno_ -- L78 β€” `{{three-way-handshake|three-way handshake}}` Β· _ke.svg.png', alt: 'TCP three-way handshake β€” SYN, SYN-ACK, ACK between c_ -- L115 β€” `{{bufferbloat|Bufferbloat}}` Β· _: 'narrative', title: 'Bufferbloat β€” Latency Without Loss',_ -- L239 β€” `{{bbrv3|bbrv3}}` Β· _{ kind: 'frontier', id: 'bbrv3-default' }, { kind: 'fron_ -- L78 β€” `{{syn-ack|SYN-ACK}}` Β· _CP three-way handshake β€” SYN, SYN-ACK, ACK between client and serve_ + +- L115 β€” `{{latency|Latency}}` Β· _title: 'Bufferbloat β€” Latency Without Loss', text: `_ +- L78 β€” `{{handshake|handshake}}` Β· _', alt: 'TCP three-way handshake β€” SYN, SYN-ACK, ACK between c_ +- L175 β€” `{{congestion-control|Congestion Control}}` Β· _ory', title: 'A History of Congestion Control', synopsis: 'Tahoe β†’ Reno_ +- L78 β€” `{{three-way-handshake|three-way handshake}}` Β· _ke.svg.png', alt: 'TCP three-way handshake β€” SYN, SYN-ACK, ACK between c_ +- L115 β€” `{{bufferbloat|Bufferbloat}}` Β· _: 'narrative', title: 'Bufferbloat β€” Latency Without Loss',_ +- L239 β€” `{{bbrv3|bbrv3}}` Β· _{ kind: 'frontier', id: 'bbrv3-default' }, { kind: 'fron_ +- L78 β€” `{{syn-ack|SYN-ACK}}` Β· _CP three-way handshake β€” SYN, SYN-ACK, ACK between client and serve_ **`src/lib/data/book/parts/realtime-av.ts`** β€” 5 term(s) -- L4 β€” `{{latency|latency}}` Β· _Protocols that prioritise low latency over perfect delivery β€” * vo_ -- L167 β€” `{{hop|hop}}` Β· _URI scheme means [[tls\|TLS]] hop-by-hop only, NOT end-to-end l_ -- L98 β€” `{{cloudflare|Cloudflare}}` Β· _}} mode.', attribution: 'Cloudflare engineering blog' },_ -- L271 β€” `{{apple|Apple}}` Β· _title: 'Low-Latency, And The "Apple Took It Away" Drama',_ -- L121 β€” `{{av1|AV1}}` Β· _pe: 'callout', title: 'AV1 came from screen-share',_ + +- L4 β€” `{{latency|latency}}` Β· _Protocols that prioritise low latency over perfect delivery β€” \* vo_ +- L167 β€” `{{hop|hop}}` Β· _URI scheme means [[tls\|TLS]] hop-by-hop only, NOT end-to-end l_ +- L98 β€” `{{cloudflare|Cloudflare}}` Β· _}} mode.', attribution: 'Cloudflare engineering blog' },_ +- L271 β€” `{{apple|Apple}}` Β· _title: 'Low-Latency, And The "Apple Took It Away" Drama',_ +- L121 β€” `{{av1|AV1}}` Β· _pe: 'callout', title: 'AV1 came from screen-share',_ **`src/lib/data/book/parts/story-of-the-internet.ts`** β€” 5 term(s) -- L55 β€” `{{arpanet|ARPANET}}` Β· _alt: 'Hand-drawn sketch of ARPANET, December 1969 β€” the original_ -- L58 β€” `{{darpa|DARPA}}` Β· _ite.', credit: 'Image: DARPA / public domain, via Wikimedi_ -- L261 β€” `{{bufferbloat|bufferbloat}}` Β· _] }, { id: 'mobile-and-bufferbloat', title: 'The Mobile and B_ -- L327 β€” `{{google|Google}}` Β· _The_Dalles.jpg', alt: 'Google data center in The Dalles, Or_ -- L374 β€” `{{linux|linux}}` Β· _{ kind: 'frontier', id: 'a2a-linux-foundation' }, { kin_ + +- L55 β€” `{{arpanet|ARPANET}}` Β· _alt: 'Hand-drawn sketch of ARPANET, December 1969 β€” the original_ +- L58 β€” `{{darpa|DARPA}}` Β· _ite.', credit: 'Image: DARPA / public domain, via Wikimedi_ +- L261 β€” `{{bufferbloat|bufferbloat}}` Β· _] }, { id: 'mobile-and-bufferbloat', title: 'The Mobile and B_ +- L327 β€” `{{google|Google}}` Β· _The_Dalles.jpg', alt: 'Google data center in The Dalles, Or_ +- L374 β€” `{{linux|linux}}` Β· _{ kind: 'frontier', id: 'a2a-linux-foundation' }, { kin_ **`src/lib/data/book/parts/transport.ts`** β€” 6 term(s) -- L149 β€” `{{encapsulation|encapsulation}}` Β· _on.svg.png', alt: 'UDP encapsulation diagram showing an IP packet_ -- L58 β€” `{{congestion-control|Congestion Control}}` Β· _: 'narrative', title: 'Congestion Control: Tahoe Through BBR Through L4_ -- L265 β€” `{{multipath|Multipath}}` Β· _arrative', title: 'The Multipath QUIC Succession', text_ -- L349 β€” `{{google|Google}}` Β· _Rack.jpg', alt: 'Early Google "corkboard" server rack β€” bar_ -- L251 β€” `{{apple|Apple}}` Β· _arrative', title: 'The Apple iOS 7 Deployment', tex_ -- L214 β€” `{{multi-homing|multi-homing}}` Β· _oming.png', alt: 'SCTP multi-homing diagram showing one associati_ + +- L149 β€” `{{encapsulation|encapsulation}}` Β· _on.svg.png', alt: 'UDP encapsulation diagram showing an IP packet_ +- L58 β€” `{{congestion-control|Congestion Control}}` Β· _: 'narrative', title: 'Congestion Control: Tahoe Through BBR Through L4_ +- L265 β€” `{{multipath|Multipath}}` Β· _arrative', title: 'The Multipath QUIC Succession', text_ +- L349 β€” `{{google|Google}}` Β· _Rack.jpg', alt: 'Early Google "corkboard" server rack β€” bar_ +- L251 β€” `{{apple|Apple}}` Β· _arrative', title: 'The Apple iOS 7 Deployment', tex_ +- L214 β€” `{{multi-homing|multi-homing}}` Β· _oming.png', alt: 'SCTP multi-homing diagram showing one associati_ **`src/lib/data/book/parts/utilities-security.ts`** β€” 7 term(s) -- L142 β€” `{{certificate|certificate}}` Β· _st.png', alt: 'Digital certificate chain of trust diagram β€” root_ -- L142 β€” `{{certificate-chain|certificate chain}}` Β· _st.png', alt: 'Digital certificate chain of trust diagram β€” root CA, i_ -- L70 β€” `{{dns-resolution|DNS resolution}}` Β· _.png', alt: 'Iterative DNS resolution diagram β€” client β†’ recursive_ -- L47 β€” `{{dnssec|DNSSEC}}` Β· _e Kaminsky Moment, And Modern DNSSEC', text: `**Dan Kaminsk_ -- L216 β€” `{{payload|payload}}` Β· _rmat showing length, padding, payload, and MAC fields.', cap_ -- L186 β€” `{{sftp|SFTP}}` Β· _pe: 'callout', title: 'SFTP is not "FTP over SSH"',_ -- L70 β€” `{{recursive-resolver|recursive resolver}}` Β· _resolution diagram β€” client β†’ recursive resolver β†’ root β†’ TLD β†’ authoritative_ + +- L142 β€” `{{certificate|certificate}}` Β· _st.png', alt: 'Digital certificate chain of trust diagram β€” root_ +- L142 β€” `{{certificate-chain|certificate chain}}` Β· _st.png', alt: 'Digital certificate chain of trust diagram β€” root CA, i_ +- L70 β€” `{{dns-resolution|DNS resolution}}` Β· _.png', alt: 'Iterative DNS resolution diagram β€” client β†’ recursive_ +- L47 β€” `{{dnssec|DNSSEC}}` Β· _e Kaminsky Moment, And Modern DNSSEC', text: `\*\*Dan Kaminsk_ +- L216 β€” `{{payload|payload}}` Β· _rmat showing length, padding, payload, and MAC fields.', cap_ +- L186 β€” `{{sftp|SFTP}}` Β· _pe: 'callout', title: 'SFTP is not "FTP over SSH"',_ +- L70 β€” `{{recursive-resolver|recursive resolver}}` Β· _resolution diagram β€” client β†’ recursive resolver β†’ root β†’ TLD β†’ authoritative_ **`src/lib/data/book/parts/web-api.ts`** β€” 12 term(s) -- L280 β€” `{{client-server|Client-server model}}` Β· _del-en.svg.png', alt: 'Client-server model diagram β€” multiple clients se_ -- L214 β€” `{{handshake|handshake}}` Β· _g', alt: 'TLS 1.3 full handshake diagram showing ClientHello,_ -- L141 β€” `{{multiplexing|multiplexing}}` Β· _HTTP/1.1 pipelining vs HTTP/2 multiplexing diagram, showing how multiple_ -- L42 β€” `{{stateless|Stateless}}` Β· _title: 'Text on the Wire, Stateless Semantics, Persistent Connect_ -- L214 β€” `{{certificate|certificate}}` Β· _ing ClientHello, ServerHello, certificate, finished messages in one rou_ -- L122 β€” `{{server-push|Server Push}}` Β· _pe: 'callout', title: 'Server Push is gone', text: '[[htt_ -- L399 β€” `{{webtransport|WebTransport}}` Β· _: 'narrative', title: 'WebTransport, and the Transport Future',_ -- L223 β€” `{{multipath|multipath}}` Β· _{ kind: 'frontier', id: 'multipath-quic' }, { kind: 'frontie_ -- L487 β€” `{{linux|linux}}` Β· _{ kind: 'frontier', id: 'a2a-linux-foundation' }, { kind: 's_ -- L214 β€” `{{client-hello|ClientHello}}` Β· _ull handshake diagram showing ClientHello, ServerHello, certificate, fi_ -- L214 β€” `{{server-hello|ServerHello}}` Β· _diagram showing ClientHello, ServerHello, certificate, finished messag_ -- L141 β€” `{{pipelining|pipelining}}` Β· _g.png', alt: 'HTTP/1.1 pipelining vs HTTP/2 multiplexing diagra_ + +- L280 β€” `{{client-server|Client-server model}}` Β· _del-en.svg.png', alt: 'Client-server model diagram β€” multiple clients se_ +- L214 β€” `{{handshake|handshake}}` Β· _g', alt: 'TLS 1.3 full handshake diagram showing ClientHello,_ +- L141 β€” `{{multiplexing|multiplexing}}` Β· _HTTP/1.1 pipelining vs HTTP/2 multiplexing diagram, showing how multiple_ +- L42 β€” `{{stateless|Stateless}}` Β· _title: 'Text on the Wire, Stateless Semantics, Persistent Connect_ +- L214 β€” `{{certificate|certificate}}` Β· _ing ClientHello, ServerHello, certificate, finished messages in one rou_ +- L122 β€” `{{server-push|Server Push}}` Β· _pe: 'callout', title: 'Server Push is gone', text: '[[htt_ +- L399 β€” `{{webtransport|WebTransport}}` Β· _: 'narrative', title: 'WebTransport, and the Transport Future',_ +- L223 β€” `{{multipath|multipath}}` Β· _{ kind: 'frontier', id: 'multipath-quic' }, { kind: 'frontie_ +- L487 β€” `{{linux|linux}}` Β· _{ kind: 'frontier', id: 'a2a-linux-foundation' }, { kind: 's_ +- L214 β€” `{{client-hello|ClientHello}}` Β· _ull handshake diagram showing ClientHello, ServerHello, certificate, fi_ +- L214 β€” `{{server-hello|ServerHello}}` Β· _diagram showing ClientHello, ServerHello, certificate, finished messag_ +- L141 β€” `{{pipelining|pipelining}}` Β· _g.png', alt: 'HTTP/1.1 pipelining vs HTTP/2 multiplexing diagra_ **`src/lib/data/book/parts/wireless.ts`** β€” 22 term(s) -- L560 β€” `{{darpa|DARPA}}` Β· _rrative', title: 'From DARPA radar to AirTag β€” the 70-year_ -- L143 β€” `{{bandwidth|bandwidth}}` Β· _ned multipath from enemy into bandwidth', text: `The original_ -- L321 β€” `{{hop|hop}}` Β· _e fabric β€” and every backhaul hop is wrapped in [[ipsec\|IPsec]]_ -- L610 β€” `{{ccc-digital-key|CCC Digital Key}}` Β· _: 'narrative', title: 'CCC Digital Key β€” the canonical unlock flow',_ -- L674 β€” `{{trust-center|trust center}}` Β· _title: 'The mesh, the trust center, and the install code',_ -- L674 β€” `{{install-code|install code}}` Β· _sh, the trust center, and the install code', text: `A Zigbee netw_ -- L494 β€” `{{matter|Matter}}` Β· _β€” bootstrap to BLE / Wi-Fi / Matter', text: `For higher-th_ -- L8 β€” `{{spectrum|spectrum}}` Β· _-security * lineage, and the spectrum frontier through 2030. The pe_ -- L143 β€” `{{multipath|multipath}}` Β· _title: 'How MIMO turned multipath from enemy into bandwidth',_ -- L168 β€” `{{wpa3|WPA3}}` Β· _Dragonblood, and the road to WPA3', text: `{{wpa2\|WPA2}}_ -- L264 β€” `{{le-audio|LE Audio}}` Β· _: 'narrative', title: "LE Audio, Auracast, and the hearing-lo_ -- L264 β€” `{{auracast|Auracast}}` Β· _ve', title: "LE Audio, Auracast, and the hearing-loop replace_ -- L273 β€” `{{channel-sounding|Channel Sounding}}` Β· _: 'narrative', title: 'Channel Sounding β€” taking the fight to UWB',_ -- L282 β€” `{{knob-attack|KNOB / BIAS / BLUFFS}}` Β· _'callout', title: 'The KNOB / BIAS / BLUFFS lineage', text: 'Three_ -- L910 β€” `{{mmwave|mmWave}}` Β· _: 'narrative', title: 'mmWave β€” the band that under-deliver_ -- L400 β€” `{{diameter|Diameter}}` Β· _ve', title: 'The SS7 / Diameter trust holdover', text:_ -- L648 β€” `{{thread|Thread}}` Β· _'zigbee', title: 'Zigbee, Thread, and the Matter bridge', s_ -- L5 β€” `{{direct-to-cell|Direct-to-Cell}}` Β· _* 5G-Advanced, and Starlink Direct-to-Cell. Nine chapters cover the * s_ -- L943 β€” `{{ambient-iot|Ambient IoT}}` Β· _: 'narrative', title: 'Ambient IoT β€” when the IoT device has no_ -- L629 β€” `{{apple|Apple}}` Β· _Tag.svg.png', alt: 'An Apple AirTag β€” a small round white_ -- L5 β€” `{{starlink|Starlink}}` Β· _ooth 6.0, * 5G-Advanced, and Starlink Direct-to-Cell. Nine chapters_ -- L854 β€” `{{wireshark|Wireshark}}` Β· _screenshot.png', alt: 'Wireshark screen capture showing a pack_ + +- L560 β€” `{{darpa|DARPA}}` Β· _rrative', title: 'From DARPA radar to AirTag β€” the 70-year_ +- L143 β€” `{{bandwidth|bandwidth}}` Β· _ned multipath from enemy into bandwidth', text: `The original_ +- L321 β€” `{{hop|hop}}` Β· _e fabric β€” and every backhaul hop is wrapped in [[ipsec\|IPsec]]_ +- L610 β€” `{{ccc-digital-key|CCC Digital Key}}` Β· _: 'narrative', title: 'CCC Digital Key β€” the canonical unlock flow',_ +- L674 β€” `{{trust-center|trust center}}` Β· _title: 'The mesh, the trust center, and the install code',_ +- L674 β€” `{{install-code|install code}}` Β· _sh, the trust center, and the install code', text: `A Zigbee netw_ +- L494 β€” `{{matter|Matter}}` Β· _β€” bootstrap to BLE / Wi-Fi / Matter', text: `For higher-th_ +- L8 β€” `{{spectrum|spectrum}}` Β· _-security \* lineage, and the spectrum frontier through 2030. The pe_ +- L143 β€” `{{multipath|multipath}}` Β· _title: 'How MIMO turned multipath from enemy into bandwidth',_ +- L168 β€” `{{wpa3|WPA3}}` Β· _Dragonblood, and the road to WPA3', text: `{{wpa2\|WPA2}}_ +- L264 β€” `{{le-audio|LE Audio}}` Β· _: 'narrative', title: "LE Audio, Auracast, and the hearing-lo_ +- L264 β€” `{{auracast|Auracast}}` Β· _ve', title: "LE Audio, Auracast, and the hearing-loop replace_ +- L273 β€” `{{channel-sounding|Channel Sounding}}` Β· _: 'narrative', title: 'Channel Sounding β€” taking the fight to UWB',_ +- L282 β€” `{{knob-attack|KNOB / BIAS / BLUFFS}}` Β· _'callout', title: 'The KNOB / BIAS / BLUFFS lineage', text: 'Three_ +- L910 β€” `{{mmwave|mmWave}}` Β· _: 'narrative', title: 'mmWave β€” the band that under-deliver_ +- L400 β€” `{{diameter|Diameter}}` Β· _ve', title: 'The SS7 / Diameter trust holdover', text:_ +- L648 β€” `{{thread|Thread}}` Β· _'zigbee', title: 'Zigbee, Thread, and the Matter bridge', s_ +- L5 β€” `{{direct-to-cell|Direct-to-Cell}}` Β· _* 5G-Advanced, and Starlink Direct-to-Cell. Nine chapters cover the * s_ +- L943 β€” `{{ambient-iot|Ambient IoT}}` Β· _: 'narrative', title: 'Ambient IoT β€” when the IoT device has no_ +- L629 β€” `{{apple|Apple}}` Β· _Tag.svg.png', alt: 'An Apple AirTag β€” a small round white_ +- L5 β€” `{{starlink|Starlink}}` Β· _ooth 6.0, \* 5G-Advanced, and Starlink Direct-to-Cell. Nine chapters_ +- L854 β€” `{{wireshark|Wireshark}}` Β· _screenshot.png', alt: 'Wireshark screen capture showing a pack_ **`src/lib/data/category-deep-dives.ts`** β€” 15 term(s) -- L354 β€” `{{jitter|Jitter}}` Β· _'realtime-av', tagline: 'Jitter buffers, error correction, ad_ -- L427 β€” `{{handshake|handshake}}` Β· _e: 'PKI internals, TLS 1.3 handshake walkthrough, cryptographic pr_ -- L101 β€” `{{flow-control|flow control}}` Β· _ongestion control algorithms, flow control mechanics, and the subtle eng_ -- L101 β€” `{{congestion-control|Congestion control}}` Β· _: 'transport', tagline: 'Congestion control algorithms, flow control mech_ -- L431 β€” `{{certificate|Certificate}}` Β· _rrative', title: 'PKI and Certificate Chains', text: `The {{pki_ -- L303 β€” `{{broker|Message Broker}}` Β· _type: 'diagram', title: 'Message Broker Architecture Patterns', c_ -- L427 β€” `{{dns-resolution|DNS resolution}}` Β· _cryptographic primitives, and DNS resolution mechanics.', sections: [_ -- L354 β€” `{{codec|codec}}` Β· _correction, adaptive bitrate, codec negotiation, and the engineer_ -- L213 β€” `{{hpack|HPACK}}` Β· _ype: 'narrative', title: 'HPACK and QPACK Compression', t_ -- L378 β€” `{{adaptive-bitrate|Adaptive Bitrate Streaming}}` Β· _type: 'diagram', title: 'Adaptive Bitrate Streaming Flow', caption: `How {{ad_ -- L118 β€” `{{cubic|CUBIC}}` Β· _ndow Growth: Tahoe vs Reno vs CUBIC vs BBR', caption: `How di_ -- L151 β€” `{{bufferbloat|Bufferbloat}}` Β· _e: 'callout', title: 'The Bufferbloat Problem', text: 'Oversize_ -- L288 β€” `{{exactly-once-delivery|exactly-once delivery}}` Β· _antics, broker architectures, exactly-once delivery, and event sourcing patterns_ -- L156 β€” `{{tcp-fast-open|TCP Fast Open}}` Β· _ype: 'narrative', title: 'TCP Fast Open', text: `Standard [[tcp\|T_ -- L213 β€” `{{qpack|QPACK}}` Β· _ative', title: 'HPACK and QPACK Compression', text: `{{he_ + +- L354 β€” `{{jitter|Jitter}}` Β· _'realtime-av', tagline: 'Jitter buffers, error correction, ad_ +- L427 β€” `{{handshake|handshake}}` Β· _e: 'PKI internals, TLS 1.3 handshake walkthrough, cryptographic pr_ +- L101 β€” `{{flow-control|flow control}}` Β· _ongestion control algorithms, flow control mechanics, and the subtle eng_ +- L101 β€” `{{congestion-control|Congestion control}}` Β· _: 'transport', tagline: 'Congestion control algorithms, flow control mech_ +- L431 β€” `{{certificate|Certificate}}` Β· _rrative', title: 'PKI and Certificate Chains', text: `The {{pki_ +- L303 β€” `{{broker|Message Broker}}` Β· _type: 'diagram', title: 'Message Broker Architecture Patterns', c_ +- L427 β€” `{{dns-resolution|DNS resolution}}` Β· _cryptographic primitives, and DNS resolution mechanics.', sections: [_ +- L354 β€” `{{codec|codec}}` Β· _correction, adaptive bitrate, codec negotiation, and the engineer_ +- L213 β€” `{{hpack|HPACK}}` Β· _ype: 'narrative', title: 'HPACK and QPACK Compression', t_ +- L378 β€” `{{adaptive-bitrate|Adaptive Bitrate Streaming}}` Β· _type: 'diagram', title: 'Adaptive Bitrate Streaming Flow', caption: `How {{ad_ +- L118 β€” `{{cubic|CUBIC}}` Β· _ndow Growth: Tahoe vs Reno vs CUBIC vs BBR', caption: `How di_ +- L151 β€” `{{bufferbloat|Bufferbloat}}` Β· _e: 'callout', title: 'The Bufferbloat Problem', text: 'Oversize_ +- L288 β€” `{{exactly-once-delivery|exactly-once delivery}}` Β· _antics, broker architectures, exactly-once delivery, and event sourcing patterns_ +- L156 β€” `{{tcp-fast-open|TCP Fast Open}}` Β· _ype: 'narrative', title: 'TCP Fast Open', text: `Standard [[tcp\|T_ +- L213 β€” `{{qpack|QPACK}}` Β· _ative', title: 'HPACK and QPACK Compression', text: `{{he_ **`src/lib/data/category-stories/network-foundations.ts`** β€” 6 term(s) -- L77 β€” `{{darpa|DARPA}}` Β· _CP/IP', org: 'Stanford / DARPA / Google', contribution:_ -- L5 β€” `{{xerox-parc|Xerox PARC}}` Β· _foundations', tagline: 'From Xerox PARC to every connected device β€” h_ -- L185 β€” `{{encapsulation|Encapsulation}}` Β· _e: 'The Journey of a Packet β€” Encapsulation in Action', definition: `g_ -- L77 β€” `{{google|Google}}` Β· _org: 'Stanford / DARPA / Google', contribution: 'C_ -- L103 β€” `{{cisco|Cisco}}` Β· _Pv6', org: 'Xerox PARC / Cisco', contribution: 'P_ -- L95 β€” `{{juniper|Juniper Networks}}` Β· _tor of BGP', org: 'IBM / Juniper Networks', contribution: 'C_ + +- L77 β€” `{{darpa|DARPA}}` Β· _CP/IP', org: 'Stanford / DARPA / Google', contribution:_ +- L5 β€” `{{xerox-parc|Xerox PARC}}` Β· _foundations', tagline: 'From Xerox PARC to every connected device β€” h_ +- L185 β€” `{{encapsulation|Encapsulation}}` Β· _e: 'The Journey of a Packet β€” Encapsulation in Action', definition: `g_ +- L77 β€” `{{google|Google}}` Β· _org: 'Stanford / DARPA / Google', contribution: 'C_ +- L103 β€” `{{cisco|Cisco}}` Β· _Pv6', org: 'Xerox PARC / Cisco', contribution: 'P_ +- L95 β€” `{{juniper|Juniper Networks}}` Β· _tor of BGP', org: 'IBM / Juniper Networks', contribution: 'C_ **`src/lib/data/category-stories/realtime-av.ts`** β€” 6 term(s) -- L51 β€” `{{arpanet|ARPANET}}` Β· _e: 'Network Voice Protocol on ARPANET', description: 'Fi_ -- L97 β€” `{{signaling|Signaling}}` Β· _e: 'pioneers', title: 'The Signaling Architects', people: [_ -- L150 β€” `{{google|Google}}` Β· _year: 2010, title: 'Google Acquires GIPS for $68.2M',_ -- L143 β€” `{{apple|Apple}}` Β· _title: 'HLS Announced by Apple', description: 'HT_ -- L119 β€” `{{cisco|Cisco}}` Β· _ct', org: 'dynamicsoft / Cisco / Five9', contribution:_ -- L111 β€” `{{intel|Intel}}` Β· _', org: 'Caltech / ISI / Intel', contribution: 'P_ + +- L51 β€” `{{arpanet|ARPANET}}` Β· _e: 'Network Voice Protocol on ARPANET', description: 'Fi_ +- L97 β€” `{{signaling|Signaling}}` Β· _e: 'pioneers', title: 'The Signaling Architects', people: [_ +- L150 β€” `{{google|Google}}` Β· _year: 2010, title: 'Google Acquires GIPS for $68.2M',_ +- L143 β€” `{{apple|Apple}}` Β· _title: 'HLS Announced by Apple', description: 'HT_ +- L119 β€” `{{cisco|Cisco}}` Β· _ct', org: 'dynamicsoft / Cisco / Five9', contribution:_ +- L111 β€” `{{intel|Intel}}` Β· _', org: 'Caltech / ISI / Intel', contribution: 'P_ **`src/lib/data/category-stories/transport.ts`** β€” 4 term(s) -- L5 β€” `{{arpanet|ARPANET}}` Β· _'transport', tagline: 'From ARPANET to the modern web \u2014 the_ -- L28 β€” `{{darpa|DARPA}}` Β· _CP/IP', org: 'Stanford / DARPA', contribution: 'D_ -- L167 β€” `{{google|Google}}` Β· _: 'QUIC Development Begins at Google', description: "[[_ -- L214 β€” `{{cisco|Cisco}}` Β· _'SCTP Architect', org: 'Cisco', contribution: 'D_ + +- L5 β€” `{{arpanet|ARPANET}}` Β· _'transport', tagline: 'From ARPANET to the modern web \u2014 the_ +- L28 β€” `{{darpa|DARPA}}` Β· _CP/IP', org: 'Stanford / DARPA', contribution: 'D_ +- L167 β€” `{{google|Google}}` Β· _: 'QUIC Development Begins at Google', description: "[[_ +- L214 β€” `{{cisco|Cisco}}` Β· _'SCTP Architect', org: 'Cisco', contribution: 'D_ **`src/lib/data/category-stories/utilities.ts`** β€” 2 term(s) -- L253 β€” `{{encryption|encryption}}` Β· _e browser that introduced SSL encryption to the web', caption:_ -- L152 β€” `{{cisco|Cisco}}` Β· _org: 'Bucknell University / Cisco', contribution: 'D_ + +- L253 β€” `{{encryption|encryption}}` Β· _e browser that introduced SSL encryption to the web', caption:_ +- L152 β€” `{{cisco|Cisco}}` Β· _org: 'Bucknell University / Cisco', contribution: 'D_ **`src/lib/data/category-stories/web-api.ts`** β€” 5 term(s) -- L141 β€” `{{hpack|HPACK}}` Β· _title: 'Co-creator of SPDY & HPACK', org: 'Google', co_ -- L132 β€” `{{google|Google}}` Β· _-creator of SPDY', org: 'Google', contribution: 'L_ -- L224 β€” `{{meta|Meta}}` Β· _aphQL', org: 'Facebook / Meta', contribution: 'P_ -- L319 β€” `{{linux|Linux}}` Β· _tle: 'Both Protocols Join the Linux Foundation', description_ -- L131 β€” `{{spdy|SPDY}}` Β· _', title: 'Co-creator of SPDY', org: 'Google', co_ + +- L141 β€” `{{hpack|HPACK}}` Β· _title: 'Co-creator of SPDY & HPACK', org: 'Google', co_ +- L132 β€” `{{google|Google}}` Β· _-creator of SPDY', org: 'Google', contribution: 'L_ +- L224 β€” `{{meta|Meta}}` Β· _aphQL', org: 'Facebook / Meta', contribution: 'P_ +- L319 β€” `{{linux|Linux}}` Β· _tle: 'Both Protocols Join the Linux Foundation', description_ +- L131 β€” `{{spdy|SPDY}}` Β· _', title: 'Co-creator of SPDY', org: 'Google', co_ **`src/lib/data/category-stories/wireless.ts`** β€” 5 term(s) -- L191 β€” `{{spectrum|Spectrum}}` Β· _type: 'callout', title: 'Spectrum at a glance', text: `Every_ -- L170 β€” `{{auracast|Auracast}}` Β· _e: 'Frankfurt Airport β€” first Auracast deployment', description_ -- L156 β€” `{{channel-sounding|Channel Sounding}}` Β· _title: 'Bluetooth 6.0 β€” Channel Sounding', description: 'Ad_ -- L177 β€” `{{direct-to-cell|Direct-to-Cell}}` Β· _title: 'T-Mobile + SpaceX Direct-to-Cell launches commercially',_ -- L69 β€” `{{intel|Intel}}` Β· _'Named Bluetooth', org: 'Intel', contribution: 'P_ + +- L191 β€” `{{spectrum|Spectrum}}` Β· _type: 'callout', title: 'Spectrum at a glance', text: `Every_ +- L170 β€” `{{auracast|Auracast}}` Β· _e: 'Frankfurt Airport β€” first Auracast deployment', description_ +- L156 β€” `{{channel-sounding|Channel Sounding}}` Β· _title: 'Bluetooth 6.0 β€” Channel Sounding', description: 'Ad_ +- L177 β€” `{{direct-to-cell|Direct-to-Cell}}` Β· _title: 'T-Mobile + SpaceX Direct-to-Cell launches commercially',_ +- L69 β€” `{{intel|Intel}}` Β· _'Named Bluetooth', org: 'Intel', contribution: 'P_ **`src/lib/data/comparison/pairs.ts`** β€” 65 term(s) -- L43 β€” `{{bandwidth|bandwidth}}` Β· _Throughput', left: 'Aggregate bandwidth of all paths', right: 'Limite_ -- L14 β€” `{{latency|latency}}` Β· _rives in order at the cost of latency; [[udp\|UDP]] prioritizes spee_ -- L16 β€” `{{handshake|handshake}}` Β· _\|Connection-oriented}} (3-way handshake)', right: '{{connectionless\|C_ -- L448 β€” `{{connectionless|connectionless}}` Β· _ansport', left: '[[udp\|UDP]] (connectionless)', right: '[[tcp\|TCP]] (persi_ -- L1314 β€” `{{encapsulation|encapsulation}}` Β· _aries, and multi-homing. This encapsulation is how [[webrtc\|WebRTC]] data_ -- L67 β€” `{{multiplexing|Multiplexing}}` Β· _boundaries)' }, { aspect: 'Multiplexing', left: 'Multiple independent_ -- L17 β€” `{{retransmission|retransmission}}` Β· _ft: 'Guaranteed delivery with retransmission', right: 'Best-effort, no ret_ -- L317 β€” `{{stateless|stateless}}` Β· _: '[[rest\|REST]] follows a stateless {{request-response\|request-re_ -- L688 β€” `{{stateful|stateful}}` Β· _model', left: 'Persistent stateful session (SELECT, FETCH, IDLE)_ -- L89 β€” `{{encryption|encryption}}` Β· _eliability, multiplexing, and encryption on top of [[udp\|UDP]] to repl_ -- L669 β€” `{{certificate|Certificate}}` Β· _t changing its protocol', 'Certificate-based trust via public CAs (L_ -- L398 β€” `{{topic|topic}}` Β· _', right: 'Binary with simple topic-based pub/sub' }, { aspect_ -- L591 β€” `{{firewall|firewall}}` Β· _'{{nat\|NAT}} traversal and firewall friendliness are critical'_ -- L2151 β€” `{{subnet|subnet}}` Β· _obtain an [[ip\|IP]] address, subnet mask, and {{default-gateway\|d_ -- L756 β€” `{{checksum|checksum}}` Β· _'Variable 20-60 bytes, header checksum, options', right: 'Fixed 40 b_ -- L523 β€” `{{codec|codec}}` Β· _t; [[dash\|DASH]] is the open, codec-agnostic MPEG standard for ad_ -- L808 β€” `{{serialization|Serialization}}` Β· _yDifferences: [ { aspect: 'Serialization', left: '{{xml\|XML}} (text-ba_ -- L1274 β€” `{{unicast|unicast}}` Β· _via [[udp\|UDP]] broadcast or unicast. This bootstrap problem makes_ -- L551 β€” `{{multicast|multicast}}` Β· _eer-to-peer\|Peer-to-peer}} or multicast', right: 'Client-to-server (i_ -- L1274 β€” `{{broadcast|broadcast}}` Β· _n OFFER, also via [[udp\|UDP]] broadcast or unicast. This bootstrap pr_ -- L1844 β€” `{{anycast|anycast}}` Β· _utes to reach it. [[dns\|DNS]] anycast relies on [[bgp\|BGP]] to adve_ -- L76 β€” `{{signaling|signaling}}` Β· _'You are building telecom signaling (SS7/SIGTRAN) or [[webrtc\|Web_ -- L1304 β€” `{{payload|payload}}` Β· _ence numbers, timestamps, and payload type identifiers, then sends_ -- L1487 β€” `{{hop|hop}}` Β· _(sips:) mandates [[tls\|TLS]] hop-by-hop across the signaling p_ -- L757 β€” `{{fragmentation|Fragmentation}}` Β· _eader chain' }, { aspect: 'Fragmentation', left: 'Routers and hosts ca_ + +- L43 β€” `{{bandwidth|bandwidth}}` Β· _Throughput', left: 'Aggregate bandwidth of all paths', right: 'Limite_ +- L14 β€” `{{latency|latency}}` Β· _rives in order at the cost of latency; [[udp\|UDP]] prioritizes spee_ +- L16 β€” `{{handshake|handshake}}` Β· _\|Connection-oriented}} (3-way handshake)', right: '{{connectionless\|C_ +- L448 β€” `{{connectionless|connectionless}}` Β· _ansport', left: '[[udp\|UDP]] (connectionless)', right: '[[tcp\|TCP]] (persi_ +- L1314 β€” `{{encapsulation|encapsulation}}` Β· _aries, and multi-homing. This encapsulation is how [[webrtc\|WebRTC]] data_ +- L67 β€” `{{multiplexing|Multiplexing}}` Β· _boundaries)' }, { aspect: 'Multiplexing', left: 'Multiple independent_ +- L17 β€” `{{retransmission|retransmission}}` Β· _ft: 'Guaranteed delivery with retransmission', right: 'Best-effort, no ret_ +- L317 β€” `{{stateless|stateless}}` Β· _: '[[rest\|REST]] follows a stateless {{request-response\|request-re_ +- L688 β€” `{{stateful|stateful}}` Β· _model', left: 'Persistent stateful session (SELECT, FETCH, IDLE)_ +- L89 β€” `{{encryption|encryption}}` Β· _eliability, multiplexing, and encryption on top of [[udp\|UDP]] to repl_ +- L669 β€” `{{certificate|Certificate}}` Β· _t changing its protocol', 'Certificate-based trust via public CAs (L_ +- L398 β€” `{{topic|topic}}` Β· _', right: 'Binary with simple topic-based pub/sub' }, { aspect_ +- L591 β€” `{{firewall|firewall}}` Β· _'{{nat\|NAT}} traversal and firewall friendliness are critical'_ +- L2151 β€” `{{subnet|subnet}}` Β· _obtain an [[ip\|IP]] address, subnet mask, and {{default-gateway\|d_ +- L756 β€” `{{checksum|checksum}}` Β· _'Variable 20-60 bytes, header checksum, options', right: 'Fixed 40 b_ +- L523 β€” `{{codec|codec}}` Β· _t; [[dash\|DASH]] is the open, codec-agnostic MPEG standard for ad_ +- L808 β€” `{{serialization|Serialization}}` Β· _yDifferences: [ { aspect: 'Serialization', left: '{{xml\|XML}} (text-ba_ +- L1274 β€” `{{unicast|unicast}}` Β· _via [[udp\|UDP]] broadcast or unicast. This bootstrap problem makes_ +- L551 β€” `{{multicast|multicast}}` Β· _eer-to-peer\|Peer-to-peer}} or multicast', right: 'Client-to-server (i_ +- L1274 β€” `{{broadcast|broadcast}}` Β· _n OFFER, also via [[udp\|UDP]] broadcast or unicast. This bootstrap pr_ +- L1844 β€” `{{anycast|anycast}}` Β· _utes to reach it. [[dns\|DNS]] anycast relies on [[bgp\|BGP]] to adve_ +- L76 β€” `{{signaling|signaling}}` Β· _'You are building telecom signaling (SS7/SIGTRAN) or [[webrtc\|Web_ +- L1304 β€” `{{payload|payload}}` Β· _ence numbers, timestamps, and payload type identifiers, then sends_ +- L1487 β€” `{{hop|hop}}` Β· _(sips:) mandates [[tls\|TLS]] hop-by-hop across the signaling p_ +- L757 β€” `{{fragmentation|Fragmentation}}` Β· _eader chain' }, { aspect: 'Fragmentation', left: 'Routers and hosts ca_ - _…40 more in this file_ **`src/lib/data/concept-foundations.ts`** β€” 20 term(s) -- L75 β€” `{{darpa|DARPA}}` Β· _P/IP', org: 'Stanford β†’ DARPA β†’ Google', contribution_ -- L266 β€” `{{mac-address|MAC address}}` Β· _t-field structure of a 48-bit MAC address β€” 24-bit OUI + 24-bit NIC, wi_ -- L37 β€” `{{handshake|handshake}}` Β· _png', alt: 'TCP three-way handshake sequence diagram β€” client SYN_ -- L297 β€” `{{encapsulation|Encapsulation}}` Β· _packets', title: 'Packets & Encapsulation', sections: [ { type_ -- L645 β€” `{{encryption|encryption}}` Β· _ers."` } ] }, { id: 'encryption-basics', title: 'Encryption_ -- L693 β€” `{{certificate|certificate}}` Β· _iate CA, which signs the leaf certificate.', caption: 'The X.5_ -- L671 β€” `{{public-key|public key}}` Β· _ncrypts with the recipient\'s public key; recipient decrypts with thei_ -- L671 β€” `{{private-key|private key}}` Β· _decrypts with their matching private key.', caption: '{{publi_ -- L399 β€” `{{checksum|checksum}}` Β· _e/ACK numbers, flags, window, checksum.', caption: 'The [[t_ -- L266 β€” `{{multicast|multicast}}` Β· _24-bit OUI + 24-bit NIC, with multicast and locally-administered flag_ -- L37 β€” `{{three-way-handshake|three-way handshake}}` Β· _shake.svg.png', alt: 'TCP three-way handshake sequence diagram β€” client SYN_ -- L340 β€” `{{payload|payload}}` Β· _source MAC, 2-byte EtherType, payload, 4-byte FCS.', caption:_ -- L506 β€” `{{cubic|CUBIC}}` Β· _ype: 'narrative', title: 'CUBIC: A Curve That Scales', te_ -- L423 β€” `{{time-wait|TIME_WAIT}}` Β· _e: 'callout', title: 'Why TIME_WAIT lives for 60 seconds', te_ -- L524 β€” `{{pacing|Pacing}}` Β· _e: 'callout', title: 'Why Pacing Matters', text: 'Classic_ -- L459 β€” `{{spectrum|Spectrum}}` Β· _, title: 'The Reliability Spectrum', definition: `graph LR_ -- L75 β€” `{{google|Google}}` Β· _org: 'Stanford β†’ DARPA β†’ Google', contribution:_ -- L788 β€” `{{anthropic|Anthropic}}` Β· _people: [ { name: 'Anthropic team', years: '2024 –',_ -- L37 β€” `{{syn-ack|SYN-ACK}}` Β· _diagram β€” client SYN, server SYN-ACK, client ACK.', caption:_ -- L712 β€” `{{rsa|RSA}}` Β· _emoved RC4, 3DES, MD5, SHA-1, RSA key {{exchange\|exchange}}, an_ + +- L75 β€” `{{darpa|DARPA}}` Β· _P/IP', org: 'Stanford β†’ DARPA β†’ Google', contribution_ +- L266 β€” `{{mac-address|MAC address}}` Β· _t-field structure of a 48-bit MAC address β€” 24-bit OUI + 24-bit NIC, wi_ +- L37 β€” `{{handshake|handshake}}` Β· _png', alt: 'TCP three-way handshake sequence diagram β€” client SYN_ +- L297 β€” `{{encapsulation|Encapsulation}}` Β· _packets', title: 'Packets & Encapsulation', sections: [ { type_ +- L645 β€” `{{encryption|encryption}}` Β· _ers."` } ] }, { id: 'encryption-basics', title: 'Encryption_ +- L693 β€” `{{certificate|certificate}}` Β· _iate CA, which signs the leaf certificate.', caption: 'The X.5_ +- L671 β€” `{{public-key|public key}}` Β· _ncrypts with the recipient\'s public key; recipient decrypts with thei_ +- L671 β€” `{{private-key|private key}}` Β· _decrypts with their matching private key.', caption: '{{publi_ +- L399 β€” `{{checksum|checksum}}` Β· _e/ACK numbers, flags, window, checksum.', caption: 'The [[t_ +- L266 β€” `{{multicast|multicast}}` Β· _24-bit OUI + 24-bit NIC, with multicast and locally-administered flag_ +- L37 β€” `{{three-way-handshake|three-way handshake}}` Β· _shake.svg.png', alt: 'TCP three-way handshake sequence diagram β€” client SYN_ +- L340 β€” `{{payload|payload}}` Β· _source MAC, 2-byte EtherType, payload, 4-byte FCS.', caption:_ +- L506 β€” `{{cubic|CUBIC}}` Β· _ype: 'narrative', title: 'CUBIC: A Curve That Scales', te_ +- L423 β€” `{{time-wait|TIME_WAIT}}` Β· _e: 'callout', title: 'Why TIME_WAIT lives for 60 seconds', te_ +- L524 β€” `{{pacing|Pacing}}` Β· _e: 'callout', title: 'Why Pacing Matters', text: 'Classic_ +- L459 β€” `{{spectrum|Spectrum}}` Β· _, title: 'The Reliability Spectrum', definition: `graph LR_ +- L75 β€” `{{google|Google}}` Β· _org: 'Stanford β†’ DARPA β†’ Google', contribution:_ +- L788 β€” `{{anthropic|Anthropic}}` Β· _people: [ { name: 'Anthropic team', years: '2024 –',_ +- L37 β€” `{{syn-ack|SYN-ACK}}` Β· _diagram β€” client SYN, server SYN-ACK, client ACK.', caption:_ +- L712 β€” `{{rsa|RSA}}` Β· _emoved RC4, 3DES, MD5, SHA-1, RSA key {{exchange\|exchange}}, an_ **`src/lib/data/diagram-definitions.ts`** β€” 14 term(s) -- L203 β€” `{{bandwidth|bandwidth}}` Β· _when nothing changed β€” saves bandwidth on repeat visits. {{content-e_ -- L1532 β€” `{{latency|latency}}` Β· _l connection-interval / slave-latency / supervision-timeout.', 4_ -- L1471 β€” `{{handshake|handshake}}` Β· _crecy}} within a session, per-handshake {{forward-secrecy\|forward sec_ -- L200 β€” `{{keep-alive|keep-alive}}` Β· _e}}** on every fetch. Without keep-alive, each resource would need a b_ -- L1403 β€” `{{public-key|public key}}` Β· _pted with the home network\'s public key (ECIES Profile A on Curve2551_ -- L203 β€” `{{payload|payload}}` Β· _or `br` (Brotli) shrinks the payload further.', 7: 'Each reques_ -- L664 β€” `{{hop|hop}}` Β· _peer\|peer-to-peer}}** with no hop through your servers (W3C / {_ -- L1467 β€” `{{cookie|cookie}}` Β· _ion). {{wg-mac2\|`MAC2`}} is a cookie under DoS load.', 3: '{{wg_ -- L1665 β€” `{{multipath|multipath}}` Β· _solved to ~1 ns β‰ˆ 30 cm; with multipath and {{sts\|STS}} valid, real-w_ -- L377 β€” `{{fire-and-forget|fire-and-forget}}` Β· _onse will come back. Used for fire-and-forget events (logging, telemetry).'_ -- L900 β€” `{{key-share|key share}}` Β· _}} the client supports plus a key share (its half of a {{diffie-hellm_ -- L1403 β€” `{{curve25519|Curve25519}}` Β· _ublic key (ECIES Profile A on Curve25519 β€” never sent in clear).',_ -- L1665 β€” `{{clock-drift|clock drift}}` Β· _ross-product cancels relative clock drift to first order. {{tof-ranging_ -- L1634 β€” `{{association-request|Association Request}}` Β· _+ LQI + capability.', 2: 'Association Request β€” the {{zigbee-joiner\|joiner}_ + +- L203 β€” `{{bandwidth|bandwidth}}` Β· _when nothing changed β€” saves bandwidth on repeat visits. {{content-e_ +- L1532 β€” `{{latency|latency}}` Β· _l connection-interval / slave-latency / supervision-timeout.', 4_ +- L1471 β€” `{{handshake|handshake}}` Β· _crecy}} within a session, per-handshake {{forward-secrecy\|forward sec_ +- L200 β€” `{{keep-alive|keep-alive}}` Β· _e}}\*\* on every fetch. Without keep-alive, each resource would need a b_ +- L1403 β€” `{{public-key|public key}}` Β· _pted with the home network\'s public key (ECIES Profile A on Curve2551_ +- L203 β€” `{{payload|payload}}` Β· _or `br` (Brotli) shrinks the payload further.', 7: 'Each reques_ +- L664 β€” `{{hop|hop}}` Β· _peer\|peer-to-peer}}\*\* with no hop through your servers (W3C / {_ +- L1467 β€” `{{cookie|cookie}}` Β· _ion). {{wg-mac2\|`MAC2`}} is a cookie under DoS load.', 3: '{{wg_ +- L1665 β€” `{{multipath|multipath}}` Β· _solved to ~1 ns β‰ˆ 30 cm; with multipath and {{sts\|STS}} valid, real-w_ +- L377 β€” `{{fire-and-forget|fire-and-forget}}` Β· _onse will come back. Used for fire-and-forget events (logging, telemetry).'_ +- L900 β€” `{{key-share|key share}}` Β· _}} the client supports plus a key share (its half of a {{diffie-hellm_ +- L1403 β€” `{{curve25519|Curve25519}}` Β· _ublic key (ECIES Profile A on Curve25519 β€” never sent in clear).',_ +- L1665 β€” `{{clock-drift|clock drift}}` Β· _ross-product cancels relative clock drift to first order. {{tof-ranging_ +- L1634 β€” `{{association-request|Association Request}}` Β· _+ LQI + capability.', 2: 'Association Request β€” the {{zigbee-joiner\|joiner}_ **`src/lib/data/frontier.ts`** β€” 8 term(s) -- L41 β€” `{{topic|topic}}` Β· _: string; oneLiner: string; topic: FrontierTopic; status: Fron_ -- L24 β€” `{{observability|observability}}` Β· _\| 'web' \| 'datacenter' \| 'observability' \| 'ai-agents' \| 'standards_ -- L232 β€” `{{multipath|multipath}}` Β· _inciples' } ] }, { id: 'multipath-quic', title: 'Multipath QU_ -- L69 β€” `{{cloudflare|Cloudflare}}` Β· _'2026-03-28' }, { label: 'Cloudflare HTTP', value: '40%', date: '2_ -- L9 β€” `{{google|Google}}` Β· _ROV/ASPA, IPv6 hitting 50% of Google * traffic (March 2026), Wi-F_ -- L85 β€” `{{apple|Apple}}` Β· _date: '2025-09 (default in Apple platforms)', protocols: ['t_ -- L282 β€” `{{linux|linux}}` Β· _auth' } ] }, { id: 'a2a-linux-foundation', title: 'A2A Do_ -- L9 β€” `{{bbrv3|BBRv3}}` Β· _ntum TLS (X25519MLKEM768), * BBRv3, L4S, ECH (RFC 9849), RPKI/RO_ + +- L41 β€” `{{topic|topic}}` Β· _: string; oneLiner: string; topic: FrontierTopic; status: Fron_ +- L24 β€” `{{observability|observability}}` Β· _\| 'web' \| 'datacenter' \| 'observability' \| 'ai-agents' \| 'standards_ +- L232 β€” `{{multipath|multipath}}` Β· _inciples' } ] }, { id: 'multipath-quic', title: 'Multipath QU_ +- L69 β€” `{{cloudflare|Cloudflare}}` Β· _'2026-03-28' }, { label: 'Cloudflare HTTP', value: '40%', date: '2_ +- L9 β€” `{{google|Google}}` Β· _ROV/ASPA, IPv6 hitting 50% of Google \* traffic (March 2026), Wi-F_ +- L85 β€” `{{apple|Apple}}` Β· _date: '2025-09 (default in Apple platforms)', protocols: ['t_ +- L282 β€” `{{linux|linux}}` Β· _auth' } ] }, { id: 'a2a-linux-foundation', title: 'A2A Do_ +- L9 β€” `{{bbrv3|BBRv3}}` Β· _ntum TLS (X25519MLKEM768), \* BBRv3, L4S, ECH (RFC 9849), RPKI/RO_ **`src/lib/data/journeys.ts`** β€” 14 term(s) -- L38 β€” `{{handshake|Handshake}}` Β· _colId: 'tcp', title: 'TCP Handshake', description: 'The_ -- L147 β€” `{{encryption|Encryption}}` Β· _: 'tls', title: 'TLS: The Encryption Layer', description:_ -- L352 β€” `{{request-response|Request-Response}}` Β· _Id: 'rest', title: 'REST: Request-Response', description: '[[re_ -- L31 β€” `{{dns-resolution|DNS Resolution}}` Β· _rotocolId: 'dns', title: 'DNS Resolution', description: 'Befo_ -- L84 β€” `{{hop|hop}}` Β· _ion address, then forwards it hop by hop toward its target. Eac_ -- L703 β€” `{{connection-migration|Connection Migration}}` Β· _Id: 'quic', title: 'QUIC: Connection Migration', description: '[[qu_ -- L479 β€” `{{ice|ICE (Interactive Connectivity Establishment)}}` Β· _orchestrates an entire stack: ICE (Interactive Connectivity Establishment) punches through NATs by testi_ -- L511 β€” `{{vp9|VP9}}` Β· _] supports H.264, H.265/HEVC, VP9, AV1, and any future {{codec\|_ -- L511 β€” `{{av1|AV1}}` Β· _ports H.264, H.265/HEVC, VP9, AV1, and any future {{codec\|codec_ -- L545 β€” `{{rsa|RSA}}` Β· _sword, public-key (Ed25519 or RSA), {{certificate\|certificate}}_ -- L933 β€” `{{association-request|Association Request}}` Β· _ocolId: 'zigbee', title: 'Association Request + Response β€” get a short addr_ -- L843 β€” `{{anti-collision|Anti-collision}}` Β· _rotocolId: 'nfc', title: 'Anti-collision + RATS/ATS β€” negotiate framin_ -- L850 β€” `{{select-aid|SELECT AID}}` Β· _c', title: 'SELECT PPSE β†’ SELECT AID β€” enumerate payment apps',_ -- L857 β€” `{{generate-ac|GENERATE AC}}` Β· _rotocolId: 'nfc', title: 'GENERATE AC β€” the cryptogram', descri_ + +- L38 β€” `{{handshake|Handshake}}` Β· _colId: 'tcp', title: 'TCP Handshake', description: 'The_ +- L147 β€” `{{encryption|Encryption}}` Β· _: 'tls', title: 'TLS: The Encryption Layer', description:_ +- L352 β€” `{{request-response|Request-Response}}` Β· _Id: 'rest', title: 'REST: Request-Response', description: '[[re_ +- L31 β€” `{{dns-resolution|DNS Resolution}}` Β· _rotocolId: 'dns', title: 'DNS Resolution', description: 'Befo_ +- L84 β€” `{{hop|hop}}` Β· _ion address, then forwards it hop by hop toward its target. Eac_ +- L703 β€” `{{connection-migration|Connection Migration}}` Β· _Id: 'quic', title: 'QUIC: Connection Migration', description: '[[qu_ +- L479 β€” `{{ice|ICE (Interactive Connectivity Establishment)}}` Β· _orchestrates an entire stack: ICE (Interactive Connectivity Establishment) punches through NATs by testi_ +- L511 β€” `{{vp9|VP9}}` Β· _] supports H.264, H.265/HEVC, VP9, AV1, and any future {{codec\|_ +- L511 β€” `{{av1|AV1}}` Β· _ports H.264, H.265/HEVC, VP9, AV1, and any future {{codec\|codec_ +- L545 β€” `{{rsa|RSA}}` Β· _sword, public-key (Ed25519 or RSA), {{certificate\|certificate}}_ +- L933 β€” `{{association-request|Association Request}}` Β· _ocolId: 'zigbee', title: 'Association Request + Response β€” get a short addr_ +- L843 β€” `{{anti-collision|Anti-collision}}` Β· _rotocolId: 'nfc', title: 'Anti-collision + RATS/ATS β€” negotiate framin_ +- L850 β€” `{{select-aid|SELECT AID}}` Β· _c', title: 'SELECT PPSE β†’ SELECT AID β€” enumerate payment apps',_ +- L857 β€” `{{generate-ac|GENERATE AC}}` Β· _rotocolId: 'nfc', title: 'GENERATE AC β€” the cryptogram', descri_ **`src/lib/data/outages.ts`** β€” 7 term(s) -- L380 β€” `{{congestion-control|Congestion Control}}` Β· _5681', label: 'RFC 5681 β€” TCP Congestion Control' } ] }, { id: 'centuryl_ -- L374 β€” `{{congestion-avoidance|Congestion Avoidance}}` Β· _.pdf', label: "Jacobson β€” Congestion Avoidance and Control (SIGCOMM '88)"_ -- L333 β€” `{{hop|hop}}` Β· _scale: 'NSFNET β€” three-IMP-hop path between Lawrence Berkele_ -- L426 β€” `{{peering|peering}}` Β· _}, { title: 'Manual de-peering needed', description:_ -- L83 β€” `{{cloudflare|Cloudflare}}` Β· _le: 'Operator' }, { name: 'Cloudflare', role: 'External monitor (1._ -- L82 β€” `{{meta|Meta}}` Β· _'tcp'], cast: [ { name: 'Meta (AS 32934)', role: 'Operator'_ -- L563 β€” `{{linux|Linux}}` Β· _e: 'SACK Panic β€” A One-Packet Linux Kernel Crash', date: '2019-_ + +- L380 β€” `{{congestion-control|Congestion Control}}` Β· _5681', label: 'RFC 5681 β€” TCP Congestion Control' } ] }, { id: 'centuryl_ +- L374 β€” `{{congestion-avoidance|Congestion Avoidance}}` Β· _.pdf', label: "Jacobson β€” Congestion Avoidance and Control (SIGCOMM '88)"_ +- L333 β€” `{{hop|hop}}` Β· _scale: 'NSFNET β€” three-IMP-hop path between Lawrence Berkele_ +- L426 β€” `{{peering|peering}}` Β· _}, { title: 'Manual de-peering needed', description:_ +- L83 β€” `{{cloudflare|Cloudflare}}` Β· _le: 'Operator' }, { name: 'Cloudflare', role: 'External monitor (1._ +- L82 β€” `{{meta|Meta}}` Β· _'tcp'], cast: [ { name: 'Meta (AS 32934)', role: 'Operator'_ +- L563 β€” `{{linux|Linux}}` Β· _e: 'SACK Panic β€” A One-Packet Linux Kernel Crash', date: '2019-_ **`src/lib/data/protocols/a2a.ts`** β€” 2 term(s) -- L164 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'HTTP round-trip latency_ -- L152 β€” `{{agent-card|Agent Card}}` Β· _tions: [ { title: 'Agent Card (/.well-known/agent.json)',_ + +- L164 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'HTTP round-trip latency_ +- L152 β€” `{{agent-card|Agent Card}}` Β· _tions: [ { title: 'Agent Card (/.well-known/agent.json)',_ **`src/lib/data/protocols/amqp.ts`** β€” 1 term(s) -- L158 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Connection setup is heav_ + +- L158 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Connection setup is heav_ **`src/lib/data/protocols/arp.ts`** β€” 8 term(s) -- L169 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Single broadcast + unica_ -- L29 β€” `{{unicast|Unicast}}` Β· _segment.' }, { title: 'Unicast ARP reply', description:_ -- L24 β€” `{{broadcast|Broadcast}}` Β· _process.' }, { title: 'Broadcast ARP request', description:_ -- L173 β€” `{{payload|payload}}` Β· _, overhead: '28-byte ARP payload inside a 42-byte Ethernet hea_ -- L48 β€” `{{failover|Failover}}` Β· _s detection at boot time', 'Failover and high-availability (gratui_ -- L19 β€” `{{arp-cache|ARP cache}}` Β· _Works: [ { title: 'Check ARP cache', description: 'Before_ -- L24 β€” `{{arp-request|ARP request}}` Β· _}, { title: 'Broadcast ARP request', description: 'If no_ -- L29 β€” `{{arp-reply|ARP reply}}` Β· _' }, { title: 'Unicast ARP reply', description: "The de_ + +- L169 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Single broadcast + unica_ +- L29 β€” `{{unicast|Unicast}}` Β· _segment.' }, { title: 'Unicast ARP reply', description:_ +- L24 β€” `{{broadcast|Broadcast}}` Β· _process.' }, { title: 'Broadcast ARP request', description:_ +- L173 β€” `{{payload|payload}}` Β· _, overhead: '28-byte ARP payload inside a 42-byte Ethernet hea_ +- L48 β€” `{{failover|Failover}}` Β· _s detection at boot time', 'Failover and high-availability (gratui_ +- L19 β€” `{{arp-cache|ARP cache}}` Β· _Works: [ { title: 'Check ARP cache', description: 'Before_ +- L24 β€” `{{arp-request|ARP request}}` Β· _}, { title: 'Broadcast ARP request', description: 'If no_ +- L29 β€” `{{arp-reply|ARP reply}}` Β· _' }, { title: 'Unicast ARP reply', description: "The de_ **`src/lib/data/protocols/bgp.ts`** β€” 7 term(s) -- L150 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Session setup: seconds (_ -- L56 β€” `{{anycast|anycast}}` Β· _ivery network}} ({{cdn\|CDN}}) anycast routing' ], codeExample: {_ -- L54 β€” `{{peering|peering}}` Β· _)', 'Cloud provider network peering (AWS, Google, Azure edge netw_ -- L200 β€” `{{cloudflare|Cloudflare}}` Β· _onstraint.' }, { org: 'Cloudflare', scale: '335+ cities, any_ -- L54 β€” `{{google|Google}}` Β· _rovider network peering (AWS, Google, Azure edge networks)', '{{_ -- L186 β€” `{{linux|Linux}}` Β· _', title: 'TCP-AO ships in Linux 6.7 for BGP', description:_ -- L53 β€” `{{multi-homing|multi-homing}}` Β· _ent providers', 'Enterprise multi-homing (connecting to multiple ISPs_ + +- L150 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Session setup: seconds (_ +- L56 β€” `{{anycast|anycast}}` Β· _ivery network}} ({{cdn\|CDN}}) anycast routing' ], codeExample: {_ +- L54 β€” `{{peering|peering}}` Β· _)', 'Cloud provider network peering (AWS, Google, Azure edge netw_ +- L200 β€” `{{cloudflare|Cloudflare}}` Β· _onstraint.' }, { org: 'Cloudflare', scale: '335+ cities, any_ +- L54 β€” `{{google|Google}}` Β· _rovider network peering (AWS, Google, Azure edge networks)', '{{_ +- L186 β€” `{{linux|Linux}}` Β· _', title: 'TCP-AO ships in Linux 6.7 for BGP', description:_ +- L53 β€” `{{multi-homing|multi-homing}}` Β· _ent providers', 'Enterprise multi-homing (connecting to multiple ISPs_ **`src/lib/data/protocols/bluetooth.ts`** β€” 14 term(s) -- L199 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'BLE connection event lat_ -- L35 β€” `{{encryption|encryption}}` Β· _}, { title: 'Pairing and encryption (SMP)', description: '_ -- L204 β€” `{{payload|payload}}` Β· _fault ATT MTU = 23 β†’ 20 bytes payload per Notify; negotiate up to 2_ -- L22 β€” `{{hop|hop}}` Β· _37 data channels (0–36) that hop once per connection event."_ -- L20 β€” `{{ism-band|ISM band}}` Β· _quency-hopping in the 2.4 GHz ISM band', description: "Both B_ -- L286 β€” `{{ccc-digital-key|CCC Digital Key}}` Β· _l." }, { org: 'Tesla / CCC Digital Key', scale: 'Every Tesla sinc_ -- L40 β€” `{{le-audio|LE Audio}}` Β· _racking.' }, { title: 'LE Audio and Auracast (5.2+)', desc_ -- L40 β€” `{{auracast|Auracast}}` Β· _, { title: 'LE Audio and Auracast (5.2+)', description:_ -- L45 β€” `{{channel-sounding|Channel Sounding}}` Β· _acement.' }, { title: 'Channel Sounding (6.0+)', description:_ -- L54 β€” `{{thread|Thread}}` Β· _strap for {{matter\|Matter}} / Thread / [[wifi\|Wi-Fi]] IoT devices'_ -- L252 β€” `{{google|Google}}` Β· _: '2024-12', title: 'Apple-Google DULT anti-stalking draft β†’ IE_ -- L53 β€” `{{apple|Apple}}` Β· _artwatches', 'Item finders: Apple AirTag, Samsung SmartTag, Til_ -- L167 β€” `{{adv-ind|ADV_IND}}` Β· _title: 'BLE Advertisement (ADV_IND on ch 37)', code: `ADV__ -- L204 β€” `{{att-mtu|ATT MTU}}` Β· _4-byte L2CAP header. Default ATT MTU = 23 β†’ 20 bytes payload per N_ + +- L199 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'BLE connection event lat_ +- L35 β€” `{{encryption|encryption}}` Β· _}, { title: 'Pairing and encryption (SMP)', description: '_ +- L204 β€” `{{payload|payload}}` Β· _fault ATT MTU = 23 β†’ 20 bytes payload per Notify; negotiate up to 2_ +- L22 β€” `{{hop|hop}}` Β· _37 data channels (0–36) that hop once per connection event."_ +- L20 β€” `{{ism-band|ISM band}}` Β· _quency-hopping in the 2.4 GHz ISM band', description: "Both B_ +- L286 β€” `{{ccc-digital-key|CCC Digital Key}}` Β· _l." }, { org: 'Tesla / CCC Digital Key', scale: 'Every Tesla sinc_ +- L40 β€” `{{le-audio|LE Audio}}` Β· _racking.' }, { title: 'LE Audio and Auracast (5.2+)', desc_ +- L40 β€” `{{auracast|Auracast}}` Β· _, { title: 'LE Audio and Auracast (5.2+)', description:_ +- L45 β€” `{{channel-sounding|Channel Sounding}}` Β· _acement.' }, { title: 'Channel Sounding (6.0+)', description:_ +- L54 β€” `{{thread|Thread}}` Β· _strap for {{matter\|Matter}} / Thread / [[wifi\|Wi-Fi]] IoT devices'_ +- L252 β€” `{{google|Google}}` Β· _: '2024-12', title: 'Apple-Google DULT anti-stalking draft β†’ IE_ +- L53 β€” `{{apple|Apple}}` Β· _artwatches', 'Item finders: Apple AirTag, Samsung SmartTag, Til_ +- L167 β€” `{{adv-ind|ADV_IND}}` Β· \_title: 'BLE Advertisement (ADV_IND on ch 37)', code: `ADV\_\_ +- L204 β€” `{{att-mtu|ATT MTU}}` Β· _4-byte L2CAP header. Default ATT MTU = 23 β†’ 20 bytes payload per N_ **`src/lib/data/protocols/cellular.ts`** β€” 8 term(s) -- L263 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Air-interface RTT: ~1 ms_ -- L268 β€” `{{hop|hop}}` Β· _ys an IPsec round on every N3 hop. ROHC header compression brin_ -- L264 β€” `{{mmwave|mmWave}}` Β· _cal mid-band 5G FR1, ~5–10 ms mmWave with retransmits, ~30–50 ms L_ -- L62 β€” `{{volte|VoLTE / VoNR}}` Β· _P "non-public networks")', 'VoLTE / VoNR voice + Wi-Fi calling handoff_ -- L63 β€” `{{direct-to-cell|direct-to-cell}}` Β· _alling handoff', 'Satellite direct-to-cell β€” T-Mobile + Starlink, AT&T +_ -- L63 β€” `{{apple|Apple}}` Β· _link, AT&T + AST SpaceMobile, Apple + Globalstar' ], codeExampl_ -- L63 β€” `{{starlink|Starlink}}` Β· _e direct-to-cell β€” T-Mobile + Starlink, AT&T + AST SpaceMobile, Appl_ -- L264 β€” `{{pdu-session|PDU Session}}` Β· _e setup (RRC β†’ Registration β†’ PDU Session): ~200–400 ms on 5G-SA; ~50 m_ + +- L263 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Air-interface RTT: ~1 ms_ +- L268 β€” `{{hop|hop}}` Β· _ys an IPsec round on every N3 hop. ROHC header compression brin_ +- L264 β€” `{{mmwave|mmWave}}` Β· _cal mid-band 5G FR1, ~5–10 ms mmWave with retransmits, ~30–50 ms L_ +- L62 β€” `{{volte|VoLTE / VoNR}}` Β· _P "non-public networks")', 'VoLTE / VoNR voice + Wi-Fi calling handoff_ +- L63 β€” `{{direct-to-cell|direct-to-cell}}` Β· _alling handoff', 'Satellite direct-to-cell β€” T-Mobile + Starlink, AT&T +_ +- L63 β€” `{{apple|Apple}}` Β· _link, AT&T + AST SpaceMobile, Apple + Globalstar' ], codeExampl_ +- L63 β€” `{{starlink|Starlink}}` Β· _e direct-to-cell β€” T-Mobile + Starlink, AT&T + AST SpaceMobile, Appl_ +- L264 β€” `{{pdu-session|PDU Session}}` Β· _e setup (RRC β†’ Registration β†’ PDU Session): ~200–400 ms on 5G-SA; ~50 m_ **`src/lib/data/protocols/coap.ts`** β€” 1 term(s) -- L159 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'No connection setup (UDP) β€”_ + +- L159 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'No connection setup (UDP) β€”_ **`src/lib/data/protocols/dash.ts`** β€” 2 term(s) -- L178 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Standard: 10-30 seconds._ -- L25 β€” `{{manifest|manifest}}` Β· _mat.' }, { title: 'MPD manifest generation', description:_ + +- L178 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Standard: 10-30 seconds._ +- L25 β€” `{{manifest|manifest}}` Β· _mat.' }, { title: 'MPD manifest generation', description:_ **`src/lib/data/protocols/dhcp.ts`** β€” 2 term(s) -- L181 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Full DORA cycle: ~100-500ms_ -- L21 β€” `{{broadcast|broadcast}}` Β· _s: [ { title: 'DISCOVER (broadcast)', description: 'New d_ + +- L181 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Full DORA cycle: ~100-500ms_ +- L21 β€” `{{broadcast|broadcast}}` Β· _s: [ { title: 'DISCOVER (broadcast)', description: 'New d_ **`src/lib/data/protocols/dns.ts`** β€” 9 term(s) -- L167 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Cached: <1ms. Uncached:_ -- L179 β€” `{{dns-resolution|DNS resolution}}` Β· _t: 'Diagram showing iterative DNS resolution: client queries recursive res_ -- L222 β€” `{{anycast|anycast}}` Β· _13 root server letters, ~1500 anycast instances', description:_ -- L194 β€” `{{dnssec|DNSSEC}}` Β· _{ date: '2024', title: 'DNSSEC validation reaches 38%', d_ -- L209 β€” `{{cloudflare|Cloudflare}}` Β· _ldDeployments: [ { org: 'Cloudflare 1.1.1.1', scale: '~1 trill_ -- L215 β€” `{{google|Google}}` Β· _surements.' }, { org: 'Google 8.8.8.8', scale: '~14 tril_ -- L43 β€” `{{mx-record|MX record}}` Β· _slation)', 'Email delivery (MX record lookups)', 'Domain verifica_ -- L44 β€” `{{dmarc|DMARC}}` Β· _n (TXT records for SPF, DKIM, DMARC)', '{{load-balancing\|Load b_ -- L179 β€” `{{recursive-resolver|recursive resolver}}` Β· _NS resolution: client queries recursive resolver, which queries root, TLD, and_ + +- L167 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Cached: <1ms. Uncached:_ +- L179 β€” `{{dns-resolution|DNS resolution}}` Β· _t: 'Diagram showing iterative DNS resolution: client queries recursive res_ +- L222 β€” `{{anycast|anycast}}` Β· _13 root server letters, ~1500 anycast instances', description:_ +- L194 β€” `{{dnssec|DNSSEC}}` Β· _{ date: '2024', title: 'DNSSEC validation reaches 38%', d_ +- L209 β€” `{{cloudflare|Cloudflare}}` Β· _ldDeployments: [ { org: 'Cloudflare 1.1.1.1', scale: '~1 trill_ +- L215 β€” `{{google|Google}}` Β· _surements.' }, { org: 'Google 8.8.8.8', scale: '~14 tril_ +- L43 β€” `{{mx-record|MX record}}` Β· _slation)', 'Email delivery (MX record lookups)', 'Domain verifica_ +- L44 β€” `{{dmarc|DMARC}}` Β· _n (TXT records for SPF, DKIM, DMARC)', '{{load-balancing\|Load b_ +- L179 β€” `{{recursive-resolver|recursive resolver}}` Β· _NS resolution: client queries recursive resolver, which queries root, TLD, and_ **`src/lib/data/protocols/ethernet.ts`** β€” 3 term(s) -- L145 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Sub-microsecond latency_ -- L158 β€” `{{payload|payload}}` Β· _le, MAC addresses, EtherType, payload, and FCS fields', caption:_ -- L146 β€” `{{store-and-forward|store-and-forward}}` Β· _ng at high speeds (25+ Gbps); store-and-forward at 1 Gbps takes ~12 \u00b5s f_ + +- L145 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Sub-microsecond latency_ +- L158 β€” `{{payload|payload}}` Β· _le, MAC addresses, EtherType, payload, and FCS fields', caption:_ +- L146 β€” `{{store-and-forward|store-and-forward}}` Β· _ng at high speeds (25+ Gbps); store-and-forward at 1 Gbps takes ~12 \u00b5s f_ **`src/lib/data/protocols/ftp.ts`** β€” 1 term(s) -- L148 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Connection setup + transfer_ + +- L148 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Connection setup + transfer_ **`src/lib/data/protocols/graphql.ts`** β€” 4 term(s) -- L40 β€” `{{bandwidth|bandwidth}}` Β· _Mobile applications (minimize bandwidth)', 'Complex dashboard UIs w_ -- L133 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Single HTTP round trip for_ -- L134 β€” `{{payload|payload}}` Β· _ut: 'No over-fetching reduces payload size; but complex queries can_ -- L134 β€” `{{over-fetching|over-fetching}}` Β· _ST calls)', throughput: 'No over-fetching reduces payload size; but com_ + +- L40 β€” `{{bandwidth|bandwidth}}` Β· _Mobile applications (minimize bandwidth)', 'Complex dashboard UIs w_ +- L133 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Single HTTP round trip for_ +- L134 β€” `{{payload|payload}}` Β· _ut: 'No over-fetching reduces payload size; but complex queries can_ +- L134 β€” `{{over-fetching|over-fetching}}` Β· _ST calls)', throughput: 'No over-fetching reduces payload size; but com_ **`src/lib/data/protocols/grpc.ts`** β€” 3 term(s) -- L119 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'HTTP/2 connection reuse + b_ -- L119 β€” `{{serialization|serialization}}` Β· _P/2 connection reuse + binary serialization = very low latency per call',_ -- L130 β€” `{{google|Google}}` Β· _ard_Server_Rack.jpg', alt: "Google's original corkboard server r_ + +- L119 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'HTTP/2 connection reuse + b_ +- L119 β€” `{{serialization|serialization}}` Β· _P/2 connection reuse + binary serialization = very low latency per call',_ +- L130 β€” `{{google|Google}}` Β· _ard_Server_Rack.jpg', alt: "Google's original corkboard server r_ **`src/lib/data/protocols/hls.ts`** β€” 3 term(s) -- L153 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Standard: 10-30 seconds._ -- L40 β€” `{{apple|Apple}}` Β· _'Video on demand (Disney+, Apple TV+, and as fallback on Netfl_ -- L24 β€” `{{manifest|Manifest}}` Β· _ne file.' }, { title: 'Manifest playlist', description:_ + +- L153 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Standard: 10-30 seconds._ +- L40 β€” `{{apple|Apple}}` Β· _'Video on demand (Disney+, Apple TV+, and as fallback on Netfl_ +- L24 β€” `{{manifest|Manifest}}` Β· _ne file.' }, { title: 'Manifest playlist', description:_ **`src/lib/data/protocols/http1.ts`** β€” 2 term(s) -- L108 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: '1 RTT per {{request-resp_ -- L132 β€” `{{keep-alive|keep-alive}}` Β· _tent connections, showing how keep-alive reduces round trips', capti_ + +- L108 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: '1 RTT per {{request-resp_ +- L132 β€” `{{keep-alive|keep-alive}}` Β· _tent connections, showing how keep-alive reduces round trips', capti_ **`src/lib/data/protocols/http2.ts`** β€” 5 term(s) -- L113 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Same connection setup as_ -- L126 β€” `{{multiplexing|multiplexing}}` Β· _uests, pipelining, and HTTP/2 multiplexing over a single connection',_ -- L117 β€” `{{hpack|HPACK}}` Β· _rhead waste', overhead: 'HPACK compresses headers by 30-76%_ -- L26 β€” `{{binary-framing|Binary framing}}` Β· _es, etc.' }, { title: 'Binary framing', description: 'All co_ -- L126 β€” `{{pipelining|pipelining}}` Β· _HTTP/1.1 sequential requests, pipelining, and HTTP/2 multiplexing over_ + +- L113 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Same connection setup as_ +- L126 β€” `{{multiplexing|multiplexing}}` Β· _uests, pipelining, and HTTP/2 multiplexing over a single connection',_ +- L117 β€” `{{hpack|HPACK}}` Β· _rhead waste', overhead: 'HPACK compresses headers by 30-76%_ +- L26 β€” `{{binary-framing|Binary framing}}` Β· _es, etc.' }, { title: 'Binary framing', description: 'All co_ +- L126 β€” `{{pipelining|pipelining}}` Β· _HTTP/1.1 sequential requests, pipelining, and HTTP/2 multiplexing over_ **`src/lib/data/protocols/http3.ts`** β€” 10 term(s) -- L42 β€” `{{latency|latency}}` Β· _-first applications', 'High-latency networks (satellite, remote a_ -- L19 β€” `{{handshake|handshake}}` Β· _tWorks: [ { title: 'QUIC handshake (1 RTT)', description:_ -- L187 β€” `{{head-of-line-blocking|head-of-line blocking}}` Β· _' }, { title: 'No more head-of-line blocking', text: 'In [[http2\|HTTP/2_ -- L124 β€” `{{encryption|encryption}}` Β· _r-packet than TCP due to QUIC encryption, offset by fewer round trips'_ -- L34 β€” `{{connection-migration|Connection migration}}` Β· _others.' }, { title: 'Connection migration', description: "If the_ -- L154 β€” `{{webtransport|WebTransport}}` Β· _{ date: '2024', title: 'WebTransport API ships in Chrome', desc_ -- L162 β€” `{{cloudflare|Cloudflare}}` Β· _ldDeployments: [ { org: 'Cloudflare', scale: 'All HTTPS traffi_ -- L168 β€” `{{google|Google}}` Β· _\|HTTP/3]].' }, { org: 'Google', scale: 'google.com / You_ -- L174 β€” `{{meta|Meta}}` Β· _rdisation.' }, { org: 'Meta', scale: '>75% of internet_ -- L24 β€” `{{qpack|QPACK}}` Β· _\|RTT}}).' }, { title: 'QPACK header compression', descr_ + +- L42 β€” `{{latency|latency}}` Β· _-first applications', 'High-latency networks (satellite, remote a_ +- L19 β€” `{{handshake|handshake}}` Β· _tWorks: [ { title: 'QUIC handshake (1 RTT)', description:_ +- L187 β€” `{{head-of-line-blocking|head-of-line blocking}}` Β· _' }, { title: 'No more head-of-line blocking', text: 'In [[http2\|HTTP/2_ +- L124 β€” `{{encryption|encryption}}` Β· _r-packet than TCP due to QUIC encryption, offset by fewer round trips'_ +- L34 β€” `{{connection-migration|Connection migration}}` Β· _others.' }, { title: 'Connection migration', description: "If the_ +- L154 β€” `{{webtransport|WebTransport}}` Β· _{ date: '2024', title: 'WebTransport API ships in Chrome', desc_ +- L162 β€” `{{cloudflare|Cloudflare}}` Β· _ldDeployments: [ { org: 'Cloudflare', scale: 'All HTTPS traffi_ +- L168 β€” `{{google|Google}}` Β· _\|HTTP/3]].' }, { org: 'Google', scale: 'google.com / You_ +- L174 β€” `{{meta|Meta}}` Β· _rdisation.' }, { org: 'Meta', scale: '>75% of internet_ +- L24 β€” `{{qpack|QPACK}}` Β· _\|RTT}}).' }, { title: 'QPACK header compression', descr_ **`src/lib/data/protocols/icmp.ts`** β€” 6 term(s) -- L50 β€” `{{latency|latency}}` Β· _ping)', 'Path discovery and latency measurement (traceroute/trace_ -- L181 β€” `{{checksum|Checksum}}` Β· _byte ICMP header (Type, Code, Checksum, Id, Seq) encapsulated in IP._ -- L53 β€” `{{signaling|signaling}}` Β· _Too Big messages)', 'Router signaling and redirect optimization' ]_ -- L45 β€” `{{hop|hop}}` Β· _s a host to use a better next-hop router. If a router receives_ -- L23 β€” `{{ping|ping}}` Β· _{ title: 'Echo Request (ping)', description: 'Sourc_ -- L38 β€” `{{traceroute|traceroute}}` Β· _{ title: 'Time Exceeded (traceroute)', description: "When_ + +- L50 β€” `{{latency|latency}}` Β· _ping)', 'Path discovery and latency measurement (traceroute/trace_ +- L181 β€” `{{checksum|Checksum}}` Β· _byte ICMP header (Type, Code, Checksum, Id, Seq) encapsulated in IP._ +- L53 β€” `{{signaling|signaling}}` Β· _Too Big messages)', 'Router signaling and redirect optimization' ]_ +- L45 β€” `{{hop|hop}}` Β· _s a host to use a better next-hop router. If a router receives_ +- L23 β€” `{{ping|ping}}` Β· _{ title: 'Echo Request (ping)', description: 'Sourc_ +- L38 β€” `{{traceroute|traceroute}}` Β· _{ title: 'Time Exceeded (traceroute)', description: "When_ **`src/lib/data/protocols/imap.ts`** β€” 1 term(s) -- L148 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'LOGIN + SELECT: ~200ms._ + +- L148 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'LOGIN + SELECT: ~200ms._ **`src/lib/data/protocols/ip.ts`** β€” 7 term(s) -- L173 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Per-hop forwarding: 1-10_ -- L48 β€” `{{encapsulation|encapsulation}}` Β· _eling ([[ip\|IP]]-in-[[ip\|IP]] encapsulation)', '{{multicast\|Multicast}}_ -- L47 β€” `{{subnet|subnet}}` Β· _n between devices on the same subnet', '{{vpn\|VPN}} tunneling ([_ -- L187 β€” `{{checksum|checksum}}` Β· _cation, flags, TTL, protocol, checksum, source and destination addre_ -- L174 β€” `{{hop|hop}}` Β· _ormance: { latency: 'Per-hop forwarding: 1-10 \u00b5s in h_ -- L35 β€” `{{fragmentation|Fragmentation}}` Β· _works).' }, { title: 'Fragmentation if needed', description:_ -- L99 β€” `{{loopback|loopback}}` Β· _\`\${addr.internal ? '(loopback)' : '(external)'}\` );_ + +- L173 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Per-hop forwarding: 1-10_ +- L48 β€” `{{encapsulation|encapsulation}}` Β· _eling ([[ip\|IP]]-in-[[ip\|IP]] encapsulation)', '{{multicast\|Multicast}}_ +- L47 β€” `{{subnet|subnet}}` Β· _n between devices on the same subnet', '{{vpn\|VPN}} tunneling ([_ +- L187 β€” `{{checksum|checksum}}` Β· _cation, flags, TTL, protocol, checksum, source and destination addre_ +- L174 β€” `{{hop|hop}}` Β· _ormance: { latency: 'Per-hop forwarding: 1-10 \u00b5s in h_ +- L35 β€” `{{fragmentation|Fragmentation}}` Β· _works).' }, { title: 'Fragmentation if needed', description:_ +- L99 β€” `{{loopback|loopback}}` Β· _\`\${addr.internal ? '(loopback)' : '(external)'}\` );_ **`src/lib/data/protocols/ipsec.ts`** β€” 14 term(s) -- L219 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: '2 round trips for IKE_SA_ -- L56 β€” `{{encryption|encryption}}` Β· _y networks', 'Opportunistic encryption between cooperating networks_ -- L141 β€” `{{certificate|Certificate}}` Β· _enticationMethod</key><string>Certificate</string> <key>RemoteIdent_ -- L338 β€” `{{hop|hop}}` Β· _overhead. If an intermediate hop drops large packets and the [_ -- L35 β€” `{{anti-replay|Anti-replay window}}` Β· _crypted." }, { title: 'Anti-replay window', description: 'The 32_ -- L53 β€” `{{apple|Apple}}` Β· _'Roadwarrior remote access β€” Apple iOS/macOS native IKEv2, Micro_ -- L53 β€” `{{microsoft|Microsoft}}` Β· _Apple iOS/macOS native IKEv2, Microsoft Always-On VPN, strongSwan / N_ -- L52 β€” `{{cisco|Cisco}}` Β· _o-site VPN between firewalls (Cisco ASA, Juniper SRX, Fortinet, O_ -- L222 β€” `{{intel|Intel}}` Β· _pto NICs (Mellanox BlueField, Intel QAT). AWS Site-to-Site VPN: 5_ -- L182 β€” `{{aes-gcm|AES-GCM}}` Β· _le: 'ESP packet (tunnel mode, AES-GCM-256)', code: `Outer IP_ -- L25 β€” `{{child-sa|Child SA}}` Β· _prove identity, authorize the Child SA', description: 'Each {_ -- L20 β€” `{{ipsec-ike-sa-init|IKE_SA_INIT}}` Β· _howItWorks: [ { title: 'IKE_SA_INIT β€” negotiate crypto, exchange_ -- L25 β€” `{{ipsec-ike-auth|IKE_AUTH}}` Β· _hange}}.' }, { title: 'IKE_AUTH β€” prove identity, authorize t_ -- L196 β€” `{{ipsec-create-child-sa|CREATE_CHILD_SA}}` Β· _}, { title: 'CREATE_CHILD_SA β€” rekey before lifetime expir_ + +- L219 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: '2 round trips for IKE_SA_ +- L56 β€” `{{encryption|encryption}}` Β· _y networks', 'Opportunistic encryption between cooperating networks_ +- L141 β€” `{{certificate|Certificate}}` Β· _enticationMethod</key><string>Certificate</string> <key>RemoteIdent_ +- L338 β€” `{{hop|hop}}` Β· _overhead. If an intermediate hop drops large packets and the [_ +- L35 β€” `{{anti-replay|Anti-replay window}}` Β· _crypted." }, { title: 'Anti-replay window', description: 'The 32_ +- L53 β€” `{{apple|Apple}}` Β· _'Roadwarrior remote access β€” Apple iOS/macOS native IKEv2, Micro_ +- L53 β€” `{{microsoft|Microsoft}}` Β· _Apple iOS/macOS native IKEv2, Microsoft Always-On VPN, strongSwan / N_ +- L52 β€” `{{cisco|Cisco}}` Β· _o-site VPN between firewalls (Cisco ASA, Juniper SRX, Fortinet, O_ +- L222 β€” `{{intel|Intel}}` Β· _pto NICs (Mellanox BlueField, Intel QAT). AWS Site-to-Site VPN: 5_ +- L182 β€” `{{aes-gcm|AES-GCM}}` Β· _le: 'ESP packet (tunnel mode, AES-GCM-256)', code: `Outer IP_ +- L25 β€” `{{child-sa|Child SA}}` Β· _prove identity, authorize the Child SA', description: 'Each {_ +- L20 β€” `{{ipsec-ike-sa-init|IKE_SA_INIT}}` Β· _howItWorks: [ { title: 'IKE_SA_INIT β€” negotiate crypto, exchange_ +- L25 β€” `{{ipsec-ike-auth|IKE_AUTH}}` Β· _hange}}.' }, { title: 'IKE_AUTH β€” prove identity, authorize t_ +- L196 β€” `{{ipsec-create-child-sa|CREATE_CHILD_SA}}` Β· _}, { title: 'CREATE_CHILD_SA β€” rekey before lifetime expir_ **`src/lib/data/protocols/ipv6.ts`** β€” 5 term(s) -- L168 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Same as IPv4 for most pa_ -- L44 β€” `{{stateless|Stateless}}` Β· _cast}}).' }, { title: 'Stateless autoconfiguration (SLAAC)',_ -- L169 β€” `{{checksum|checksum}}` Β· _β€” no NAT traversal, no header checksum computation at each hop, and_ -- L169 β€” `{{hop|hop}}` Β· _checksum computation at each hop, and some ISPs have shorter I_ -- L171 β€” `{{fragmentation|fragmentation}}` Β· _ksum recalculation, no router fragmentation, and fixed header size enable_ + +- L168 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Same as IPv4 for most pa_ +- L44 β€” `{{stateless|Stateless}}` Β· _cast}}).' }, { title: 'Stateless autoconfiguration (SLAAC)',_ +- L169 β€” `{{checksum|checksum}}` Β· _β€” no NAT traversal, no header checksum computation at each hop, and_ +- L169 β€” `{{hop|hop}}` Β· _checksum computation at each hop, and some ISPs have shorter I_ +- L171 β€” `{{fragmentation|fragmentation}}` Β· _ksum recalculation, no router fragmentation, and fixed header size enable_ **`src/lib/data/protocols/json-rpc.ts`** β€” 2 term(s) -- L158 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Same as the underlying t_ -- L47 β€” `{{lsp|Language Server Protocol (LSP)}}` Β· _tcoin, Solana, Polkadot)', 'Language Server Protocol (LSP) for code editors', 'AI agen_ + +- L158 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Same as the underlying t_ +- L47 β€” `{{lsp|Language Server Protocol (LSP)}}` Β· _tcoin, Solana, Polkadot)', 'Language Server Protocol (LSP) for code editors', 'AI agen_ **`src/lib/data/protocols/kafka.ts`** β€” 3 term(s) -- L186 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'End-to-end: 2-10ms typical._ -- L198 β€” `{{topic|topic}}` Β· _ng Kafka producers writing to topic partitions across brokers, wi_ -- L50 β€” `{{stream-processing|Stream processing}}` Β· _ure (CDC) from databases', 'Stream processing with [[kafka\|Kafka]] Streams_ + +- L186 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'End-to-end: 2-10ms typical._ +- L198 β€” `{{topic|topic}}` Β· _ng Kafka producers writing to topic partitions across brokers, wi_ +- L50 β€” `{{stream-processing|Stream processing}}` Β· _ure (CDC) from databases', 'Stream processing with [[kafka\|Kafka]] Streams_ **`src/lib/data/protocols/kerberos.ts`** β€” 8 term(s) -- L261 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: '1 RTT for AS-REQ/AS-REP_ -- L386 β€” `{{encryption|encryption}}` Β· _' }, { title: 'Weak encryption types still lurk in old keyta_ -- L299 β€” `{{certificate|certificate}}` Β· _e: 'Microsoft enforces strong certificate binding (CVE-2022-37967 long-_ -- L208 β€” `{{payload|payload}}` Β· _: 'AS-REP β€” the magic two-key payload', code: `KRB-AS-REP ::=_ -- L344 β€” `{{apple|Apple}}` Β· _org: 'Heimdal', scale: 'Apple\'s macOS, Samba, FreeBSD',_ -- L53 β€” `{{microsoft|Microsoft}}` Β· _'**Active Directory** β€” every Microsoft AD domain on Earth, primary a_ -- L338 β€” `{{linux|Linux}}` Β· _al C codebase; ships in every Linux distro', description:_ -- L44 β€” `{{kerberos-krbtgt|krbtgt}}` Β· _graph of shared keys between krbtgt principals β€” the same mechani_ + +- L261 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: '1 RTT for AS-REQ/AS-REP_ +- L386 β€” `{{encryption|encryption}}` Β· _' }, { title: 'Weak encryption types still lurk in old keyta_ +- L299 β€” `{{certificate|certificate}}` Β· _e: 'Microsoft enforces strong certificate binding (CVE-2022-37967 long-_ +- L208 β€” `{{payload|payload}}` Β· _: 'AS-REP β€” the magic two-key payload', code: `KRB-AS-REP ::=_ +- L344 β€” `{{apple|Apple}}` Β· _org: 'Heimdal', scale: 'Apple\'s macOS, Samba, FreeBSD',_ +- L53 β€” `{{microsoft|Microsoft}}` Β· _'**Active Directory** β€” every Microsoft AD domain on Earth, primary a_ +- L338 β€” `{{linux|Linux}}` Β· _al C codebase; ships in every Linux distro', description:_ +- L44 β€” `{{kerberos-krbtgt|krbtgt}}` Β· _graph of shared keys between krbtgt principals β€” the same mechani_ **`src/lib/data/protocols/mcp.ts`** β€” 2 term(s) -- L150 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'stdio transport has near_ -- L25 β€” `{{handshake|handshake}}` Β· _}, { title: 'Initialize handshake', description: 'The cl_ + +- L150 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'stdio transport has near_ +- L25 β€” `{{handshake|handshake}}` Β· _}, { title: 'Initialize handshake', description: 'The cl_ **`src/lib/data/protocols/mdns-dns-sd.ts`** β€” 15 term(s) -- L299 β€” `{{icann|ICANN}}` Β· _act of IETF jurisdiction over ICANN', text: 'RFC 6761 (Februar_ -- L202 β€” `{{bandwidth|bandwidth}}` Β· _nnounce/resolve. Steady-state bandwidth is dominated by the announce_ -- L199 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: '~750 ms for full probe (_ -- L200 β€” `{{unicast|unicast}}` Β· _on avoidance. Far faster than unicast DNS because no recursion is i_ -- L5 β€” `{{multicast|Multicast}}` Β· _{ id: 'mdns-dns-sd', name: 'Multicast DNS & DNS-Based Service Disco_ -- L5 β€” `{{service-discovery|Service Discovery}}` Β· _e: 'Multicast DNS & DNS-Based Service Discovery', abbreviation: 'mDNS / DNS-_ -- L53 β€” `{{matter|Matter}}` Β· __pdl-datastream._tcp`)', '**Matter** device commissioning (`_mat_ -- L6 β€” `{{mdns|mDNS / DNS-SD}}` Β· _e Discovery', abbreviation: 'mDNS / DNS-SD', categoryId: 'utilities',_ -- L280 β€” `{{google|Google}}` Β· _n at work." }, { org: 'Google Chromecast + Cast ecosystem',_ -- L56 β€” `{{apple|Apple}}` Β· _E remote-debug discovery', 'Apple Continuity (AirDrop, Handoff,_ -- L234 β€” `{{microsoft|Microsoft}}` Β· _ces-configuring', label: 'Microsoft security baseline' } },_ -- L249 β€” `{{cisco|Cisco}}` Β· _date: '2024-03', title: 'Cisco WLC mDNS DoS β€” cisco-sa-wlc-m_ -- L275 β€” `{{linux|Linux}}` Β· _cale: 'Default on every major Linux distro', description:_ -- L56 β€” `{{airdrop|AirDrop}}` Β· _covery', 'Apple Continuity (AirDrop, Handoff, Universal Clipboard_ -- L162 β€” `{{mdns-announce|mDNS announce}}` Β· _}, { title: 'mDNS announce (PTR + SRV + TXT + A, cache-f_ + +- L299 β€” `{{icann|ICANN}}` Β· _act of IETF jurisdiction over ICANN', text: 'RFC 6761 (Februar_ +- L202 β€” `{{bandwidth|bandwidth}}` Β· _nnounce/resolve. Steady-state bandwidth is dominated by the announce_ +- L199 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: '~750 ms for full probe (_ +- L200 β€” `{{unicast|unicast}}` Β· _on avoidance. Far faster than unicast DNS because no recursion is i_ +- L5 β€” `{{multicast|Multicast}}` Β· _{ id: 'mdns-dns-sd', name: 'Multicast DNS & DNS-Based Service Disco_ +- L5 β€” `{{service-discovery|Service Discovery}}` Β· _e: 'Multicast DNS & DNS-Based Service Discovery', abbreviation: 'mDNS / DNS-_ +- L53 β€” `{{matter|Matter}}` Β· \__pdl-datastream.\_tcp`)', '**Matter** device commissioning (`\_mat_ +- L6 β€” `{{mdns|mDNS / DNS-SD}}` Β· _e Discovery', abbreviation: 'mDNS / DNS-SD', categoryId: 'utilities',_ +- L280 β€” `{{google|Google}}` Β· _n at work." }, { org: 'Google Chromecast + Cast ecosystem',_ +- L56 β€” `{{apple|Apple}}` Β· _E remote-debug discovery', 'Apple Continuity (AirDrop, Handoff,_ +- L234 β€” `{{microsoft|Microsoft}}` Β· _ces-configuring', label: 'Microsoft security baseline' } },_ +- L249 β€” `{{cisco|Cisco}}` Β· _date: '2024-03', title: 'Cisco WLC mDNS DoS β€” cisco-sa-wlc-m_ +- L275 β€” `{{linux|Linux}}` Β· _cale: 'Default on every major Linux distro', description:_ +- L56 β€” `{{airdrop|AirDrop}}` Β· _covery', 'Apple Continuity (AirDrop, Handoff, Universal Clipboard_ +- L162 β€” `{{mdns-announce|mDNS announce}}` Β· _}, { title: 'mDNS announce (PTR + SRV + TXT + A, cache-f_ **`src/lib/data/protocols/mptcp.ts`** β€” 8 term(s) -- L164 β€” `{{bandwidth|bandwidth}}` Β· _throughput: 'Aggregated bandwidth of all subflows. Two 100Mbps_ -- L161 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Initial: same as TCP (1_ -- L19 β€” `{{handshake|handshake}}` Β· _rks: [ { title: 'Initial handshake with MP_CAPABLE', descript_ -- L5 β€” `{{multipath|Multipath}}` Β· _col = { id: 'mptcp', name: 'Multipath TCP', abbreviation: 'MPTCP',_ -- L46 β€” `{{apple|Apple}}` Β· _]] to cellular handover)', 'Apple Siri, Maps, and Music on iOS_ -- L19 β€” `{{mp-capable|MP_CAPABLE}}` Β· _itle: 'Initial handshake with MP_CAPABLE', description: 'The fi_ -- L24 β€” `{{mp-join|MP_JOIN}}` Β· _tle: 'Additional subflows via MP_JOIN', description: 'Either_ -- L39 β€” `{{failover|failover}}` Β· _}, { title: 'Seamless failover', description: 'If a {_ + +- L164 β€” `{{bandwidth|bandwidth}}` Β· _throughput: 'Aggregated bandwidth of all subflows. Two 100Mbps_ +- L161 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Initial: same as TCP (1_ +- L19 β€” `{{handshake|handshake}}` Β· _rks: [ { title: 'Initial handshake with MP_CAPABLE', descript_ +- L5 β€” `{{multipath|Multipath}}` Β· _col = { id: 'mptcp', name: 'Multipath TCP', abbreviation: 'MPTCP',_ +- L46 β€” `{{apple|Apple}}` Β· _]] to cellular handover)', 'Apple Siri, Maps, and Music on iOS_ +- L19 β€” `{{mp-capable|MP_CAPABLE}}` Β· _itle: 'Initial handshake with MP_CAPABLE', description: 'The fi_ +- L24 β€” `{{mp-join|MP_JOIN}}` Β· _tle: 'Additional subflows via MP_JOIN', description: 'Either_ +- L39 β€” `{{failover|failover}}` Β· _}, { title: 'Seamless failover', description: 'If a {_ **`src/lib/data/protocols/mqtt.ts`** β€” 2 term(s) -- L154 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Sub-second for QoS 0; 1-2 R_ -- L79 β€” `{{topic|topic}}` Β· _sage) => { console.log(\`\${topic}: \${message.toString()}\`);_ + +- L154 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Sub-second for QoS 0; 1-2 R_ +- L79 β€” `{{topic|topic}}` Β· _sage) => { console.log(\`\${topic}: \${message.toString()}\`);_ **`src/lib/data/protocols/nat-traversal.ts`** β€” 12 term(s) -- L207 β€” `{{ip-address|IP address}}` Β· _translated to a single public IP address', caption: 'The reason {_ -- L195 β€” `{{bandwidth|bandwidth}}` Β· _ra hop of latency and re-bill bandwidth; Cloudflare Realtime charges_ -- L192 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: '1 RTT for a STUN Binding_ -- L6 β€” `{{stun-turn-ice|STUN/TURN/ICE}}` Β· _T Traversal', abbreviation: 'STUN/TURN/ICE', categoryId: 'utilities',_ -- L259 β€” `{{anycast|anycast}}` Β· _e: '`stun.l.google.com:19302` anycast, free, default in libwebrtc',_ -- L195 β€” `{{hop|hop}}` Β· _e). TURN relays add one extra hop of latency and re-bill bandwi_ -- L207 β€” `{{public-ip-address|public IP address}}` Β· _router translated to a single public IP address', caption: 'The reason {_ -- L285 β€” `{{cookie|cookie}}` Β· _s: [ { title: 'The magic cookie spells "STUN"', text: '{{s_ -- L55 β€” `{{cloudflare|Cloudflare}}` Β· _, DERP as TURN-analogue)', 'Cloudflare Realtime, Twilio NTS, Microso_ -- L51 β€” `{{google|Google}}` Β· _[webrtc\|WebRTC]] video calls (Google Meet, Zoom, Teams, Discord, F_ -- L55 β€” `{{microsoft|Microsoft}}` Β· _udflare Realtime, Twilio NTS, Microsoft Teams relay backbone' ], co_ -- L136 β€” `{{binding-request|STUN Binding Request}}` Β· _tions: [ { title: 'STUN Binding Request (client β†’ server)', cod_ + +- L207 β€” `{{ip-address|IP address}}` Β· _translated to a single public IP address', caption: 'The reason {_ +- L195 β€” `{{bandwidth|bandwidth}}` Β· _ra hop of latency and re-bill bandwidth; Cloudflare Realtime charges_ +- L192 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: '1 RTT for a STUN Binding_ +- L6 β€” `{{stun-turn-ice|STUN/TURN/ICE}}` Β· _T Traversal', abbreviation: 'STUN/TURN/ICE', categoryId: 'utilities',_ +- L259 β€” `{{anycast|anycast}}` Β· _e: '`stun.l.google.com:19302` anycast, free, default in libwebrtc',_ +- L195 β€” `{{hop|hop}}` Β· _e). TURN relays add one extra hop of latency and re-bill bandwi_ +- L207 β€” `{{public-ip-address|public IP address}}` Β· _router translated to a single public IP address', caption: 'The reason {_ +- L285 β€” `{{cookie|cookie}}` Β· _s: [ { title: 'The magic cookie spells "STUN"', text: '{{s_ +- L55 β€” `{{cloudflare|Cloudflare}}` Β· _, DERP as TURN-analogue)', 'Cloudflare Realtime, Twilio NTS, Microso_ +- L51 β€” `{{google|Google}}` Β· _[webrtc\|WebRTC]] video calls (Google Meet, Zoom, Teams, Discord, F_ +- L55 β€” `{{microsoft|Microsoft}}` Β· _udflare Realtime, Twilio NTS, Microsoft Teams relay backbone' ], co_ +- L136 β€” `{{binding-request|STUN Binding Request}}` Β· _tions: [ { title: 'STUN Binding Request (client β†’ server)', cod_ **`src/lib/data/protocols/nfc.ts`** β€” 13 term(s) -- L271 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: '50–200 ms typical for ta_ -- L173 β€” `{{payload|payload}}` Β· _rd header β€” the universal NFC payload container', code: `Byte_ -- L20 β€” `{{ism-band|ISM band}}` Β· _MHz inductive coupling in the ISM band', description: "All NF_ -- L20 β€” `{{inductive-coupling|inductive coupling}}` Β· _s: [ { title: '13.56 MHz inductive coupling in the ISM band', descript_ -- L324 β€” `{{ccc-digital-key|CCC Digital Key}}` Β· _date: '2025-07', title: 'CCC Digital Key 4.0 announced', descriptio_ -- L205 β€” `{{aliro|Aliro}}` Β· _16-4 APDU β€” the EMV / eMRTD / Aliro command alphabet', code_ -- L45 β€” `{{matter|Matter}}` Β· _ndover to Bluetooth / Wi-Fi / Matter', description: "For hi_ -- L56 β€” `{{google|Google}}` Β· _[[nfc\|NFC]] tap at Apple Pay, Google Wallet, Samsung Pay, and ever_ -- L56 β€” `{{apple|Apple}}` Β· _payment β€” [[nfc\|NFC]] tap at Apple Pay, Google Wallet, Samsung P_ -- L433 β€” `{{android|Android}}` Β· _cts and cold-start latency on Android', text: "When two install_ -- L30 β€” `{{anti-collision|Anti-collision}}` Β· _NFC tag.' }, { title: 'Anti-collision: REQA β†’ ATQA β†’ SEL/NVB β†’ SAK'_ -- L35 β€” `{{select-aid|SELECT AID}}` Β· _Card Emulation: SELECT PPSE β†’ SELECT AID β†’ GET PROCESSING OPTIONS β†’ GE_ -- L35 β€” `{{generate-ac|GENERATE AC}}` Β· _ID β†’ GET PROCESSING OPTIONS β†’ GENERATE AC', description: "For ca_ + +- L271 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: '50–200 ms typical for ta_ +- L173 β€” `{{payload|payload}}` Β· _rd header β€” the universal NFC payload container', code: `Byte_ +- L20 β€” `{{ism-band|ISM band}}` Β· _MHz inductive coupling in the ISM band', description: "All NF_ +- L20 β€” `{{inductive-coupling|inductive coupling}}` Β· _s: [ { title: '13.56 MHz inductive coupling in the ISM band', descript_ +- L324 β€” `{{ccc-digital-key|CCC Digital Key}}` Β· _date: '2025-07', title: 'CCC Digital Key 4.0 announced', descriptio_ +- L205 β€” `{{aliro|Aliro}}` Β· _16-4 APDU β€” the EMV / eMRTD / Aliro command alphabet', code_ +- L45 β€” `{{matter|Matter}}` Β· _ndover to Bluetooth / Wi-Fi / Matter', description: "For hi_ +- L56 β€” `{{google|Google}}` Β· _[[nfc\|NFC]] tap at Apple Pay, Google Wallet, Samsung Pay, and ever_ +- L56 β€” `{{apple|Apple}}` Β· _payment β€” [[nfc\|NFC]] tap at Apple Pay, Google Wallet, Samsung P_ +- L433 β€” `{{android|Android}}` Β· _cts and cold-start latency on Android', text: "When two install_ +- L30 β€” `{{anti-collision|Anti-collision}}` Β· _NFC tag.' }, { title: 'Anti-collision: REQA β†’ ATQA β†’ SEL/NVB β†’ SAK'_ +- L35 β€” `{{select-aid|SELECT AID}}` Β· _Card Emulation: SELECT PPSE β†’ SELECT AID β†’ GET PROCESSING OPTIONS β†’ GE_ +- L35 β€” `{{generate-ac|GENERATE AC}}` Β· _ID β†’ GET PROCESSING OPTIONS β†’ GENERATE AC', description: "For ca_ **`src/lib/data/protocols/ntp.ts`** β€” 3 term(s) -- L154 β€” `{{bandwidth|bandwidth}}` Β· _: 64-1024 seconds. Negligible bandwidth.', overhead: '48-byte packe_ -- L153 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Single UDP round trip. Sync_ -- L46 β€” `{{certificate|Certificate}}` Β· _atory time requirements)', 'Certificate validity and expiration check_ + +- L154 β€” `{{bandwidth|bandwidth}}` Β· _: 64-1024 seconds. Negligible bandwidth.', overhead: '48-byte packe_ +- L153 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Single UDP round trip. Sync_ +- L46 β€” `{{certificate|Certificate}}` Β· _atory time requirements)', 'Certificate validity and expiration check_ **`src/lib/data/protocols/oauth2.ts`** β€” 3 term(s) -- L223 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Authorization flow: 1-3_ -- L48 β€” `{{google|Google}}` Β· _'Social login ("Sign in with Google/GitHub/Apple")', 'Third-par_ -- L48 β€” `{{apple|Apple}}` Β· _("Sign in with Google/GitHub/Apple")', 'Third-party API access_ + +- L223 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Authorization flow: 1-3_ +- L48 β€” `{{google|Google}}` Β· _'Social login ("Sign in with Google/GitHub/Apple")', 'Third-par_ +- L48 β€” `{{apple|Apple}}` Β· _("Sign in with Google/GitHub/Apple")', 'Third-party API access_ **`src/lib/data/protocols/ospf.ts`** β€” 6 term(s) -- L185 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Default convergence ~40_ -- L52 β€” `{{peering|peering}}` Β· _ackbones)', 'MPLS-VPN PE-CE peering (RFC 4577)', 'Mid-tier ISP_ -- L246 β€” `{{microsoft|Microsoft}}` Β· _ldDeployments: [ { org: 'Microsoft Azure', scale: 'Inter-regi_ -- L252 β€” `{{nvidia|NVIDIA}}` Β· _{ org: 'Cumulus Networks / NVIDIA SONiC', scale: 'Default IG_ -- L264 β€” `{{cisco|Cisco}}` Β· _revalence." }, { org: 'Cisco IOS-XR / Juniper Junos', s_ -- L25 β€” `{{adjacency|Adjacency}}` Β· _s field.' }, { title: 'Adjacency state machine', descriptio_ + +- L185 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Default convergence ~40_ +- L52 β€” `{{peering|peering}}` Β· _ackbones)', 'MPLS-VPN PE-CE peering (RFC 4577)', 'Mid-tier ISP_ +- L246 β€” `{{microsoft|Microsoft}}` Β· _ldDeployments: [ { org: 'Microsoft Azure', scale: 'Inter-regi_ +- L252 β€” `{{nvidia|NVIDIA}}` Β· _{ org: 'Cumulus Networks / NVIDIA SONiC', scale: 'Default IG_ +- L264 β€” `{{cisco|Cisco}}` Β· _revalence." }, { org: 'Cisco IOS-XR / Juniper Junos', s_ +- L25 β€” `{{adjacency|Adjacency}}` Β· _s field.' }, { title: 'Adjacency state machine', descriptio_ **`src/lib/data/protocols/quic.ts`** β€” 9 term(s) -- L150 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: '1 RTT for new connection_ -- L20 β€” `{{handshake|handshake}}` Β· _rks: [ { title: 'Initial handshake (1 RTT)', description:_ -- L154 β€” `{{encryption|encryption}}` Β· _er per-packet than TCP due to encryption, but fewer round trips overal_ -- L35 β€” `{{connection-migration|Connection migration}}` Β· _others." }, { title: 'Connection migration', description: 'Connec_ -- L186 β€” `{{multipath|Multipath}}` Β· _date: '2024-09', title: 'Multipath QUIC reaches stable IETF draf_ -- L216 β€” `{{cloudflare|Cloudflare}}` Β· _en-source.' }, { org: 'Cloudflare', scale: 'All HTTPS traffi_ -- L164 β€” `{{google|Google}}` Β· _r%2C_The_Dalles.jpg', alt: 'Google data center in The Dalles, Or_ -- L222 β€” `{{apple|Apple}}` Β· _y default.' }, { org: 'Apple', scale: 'iOS 18+ / macOS_ -- L180 β€” `{{meta|Meta}}` Β· _date: '2024-Q4', title: 'Meta reports >75% of internet traf_ + +- L150 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: '1 RTT for new connection_ +- L20 β€” `{{handshake|handshake}}` Β· _rks: [ { title: 'Initial handshake (1 RTT)', description:_ +- L154 β€” `{{encryption|encryption}}` Β· _er per-packet than TCP due to encryption, but fewer round trips overal_ +- L35 β€” `{{connection-migration|Connection migration}}` Β· _others." }, { title: 'Connection migration', description: 'Connec_ +- L186 β€” `{{multipath|Multipath}}` Β· _date: '2024-09', title: 'Multipath QUIC reaches stable IETF draf_ +- L216 β€” `{{cloudflare|Cloudflare}}` Β· _en-source.' }, { org: 'Cloudflare', scale: 'All HTTPS traffi_ +- L164 β€” `{{google|Google}}` Β· _r%2C_The_Dalles.jpg', alt: 'Google data center in The Dalles, Or_ +- L222 β€” `{{apple|Apple}}` Β· _y default.' }, { org: 'Apple', scale: 'iOS 18+ / macOS_ +- L180 β€” `{{meta|Meta}}` Β· _date: '2024-Q4', title: 'Meta reports >75% of internet traf_ **`src/lib/data/protocols/rest.ts`** β€” 4 term(s) -- L139 β€” `{{client-server|client-server model}}` Β· _.png', alt: 'Diagram of the client-server model showing multiple clients comm_ -- L115 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Per-request (no persistent_ -- L28 β€” `{{stateless|Stateless}}` Β· _ot safe.' }, { title: 'Stateless requests', description:_ -- L43 β€” `{{matter|matter}}` Β· _icity and broad compatibility matter' ], codeExample: { langua_ + +- L139 β€” `{{client-server|client-server model}}` Β· _.png', alt: 'Diagram of the client-server model showing multiple clients comm_ +- L115 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Per-request (no persistent_ +- L28 β€” `{{stateless|Stateless}}` Β· _ot safe.' }, { title: 'Stateless requests', description:_ +- L43 β€” `{{matter|matter}}` Β· _icity and broad compatibility matter' ], codeExample: { langua_ **`src/lib/data/protocols/rtmp.ts`** β€” 3 term(s) -- L47 β€” `{{latency|latency}}` Β· _-server transmission', 'Low-latency live broadcasts and gaming st_ -- L19 β€” `{{handshake|handshake}}` Β· _ItWorks: [ { title: 'TCP handshake + RTMP handshake', descrip_ -- L69 β€” `{{hop|hop}}` Β· _\|RTMP]] is the standard first hop for live streaming β€” from enc_ + +- L47 β€” `{{latency|latency}}` Β· _-server transmission', 'Low-latency live broadcasts and gaming st_ +- L19 β€” `{{handshake|handshake}}` Β· _ItWorks: [ { title: 'TCP handshake + RTMP handshake', descrip_ +- L69 β€” `{{hop|hop}}` Β· _\|RTMP]] is the standard first hop for live streaming β€” from enc_ **`src/lib/data/protocols/rtp.ts`** β€” 3 term(s) -- L155 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'No connection setup (UDP)._ -- L155 β€” `{{jitter|jitter}}` Β· _typically 50-300ms including jitter buffering.', throughput:_ -- L157 β€” `{{codec|codec}}` Β· _, throughput: 'Adaptive: codec and bitrate adjust based on R_ + +- L155 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'No connection setup (UDP)._ +- L155 β€” `{{jitter|jitter}}` Β· _typically 50-300ms including jitter buffering.', throughput:_ +- L157 β€” `{{codec|codec}}` Β· _, throughput: 'Adaptive: codec and bitrate adjust based on R_ **`src/lib/data/protocols/sctp.ts`** β€” 6 term(s) -- L147 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: '2 RTT for connection setup_ -- L19 β€” `{{handshake|handshake}}` Β· _Works: [ { title: '4-way handshake', description: "[[sctp_ -- L40 β€” `{{signaling|signaling}}` Β· _} ], useCases: [ 'Telecom signaling (SS7 over [[ip\|IP]], Diameter_ -- L40 β€” `{{diameter|Diameter}}` Β· _ignaling (SS7 over [[ip\|IP]], Diameter)', '4G/5G mobile network in_ -- L19 β€” `{{four-way-handshake|4-way handshake}}` Β· _howItWorks: [ { title: '4-way handshake', description: "[[sctp_ -- L29 β€” `{{multi-homing|Multi-homing}}` Β· _cking}}." }, { title: 'Multi-homing', description: 'An [[s_ + +- L147 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: '2 RTT for connection setup_ +- L19 β€” `{{handshake|handshake}}` Β· _Works: [ { title: '4-way handshake', description: "[[sctp_ +- L40 β€” `{{signaling|signaling}}` Β· _} ], useCases: [ 'Telecom signaling (SS7 over [[ip\|IP]], Diameter_ +- L40 β€” `{{diameter|Diameter}}` Β· _ignaling (SS7 over [[ip\|IP]], Diameter)', '4G/5G mobile network in_ +- L19 β€” `{{four-way-handshake|4-way handshake}}` Β· _howItWorks: [ { title: '4-way handshake', description: "[[sctp_ +- L29 β€” `{{multi-homing|Multi-homing}}` Β· _cking}}." }, { title: 'Multi-homing', description: 'An [[s_ **`src/lib/data/protocols/sdp.ts`** β€” 3 term(s) -- L177 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'SDP itself adds no latency_ -- L177 β€” `{{signaling|signaling}}` Β· _no latency β€” exchanged during signaling, before media flows.', thro_ -- L189 β€” `{{cisco|Cisco}}` Β· _Prototype.jpg', alt: 'Early Cisco TelePresence CTS-3000 prototy_ + +- L177 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'SDP itself adds no latency_ +- L177 β€” `{{signaling|signaling}}` Β· _no latency β€” exchanged during signaling, before media flows.', thro_ +- L189 β€” `{{cisco|Cisco}}` Β· _Prototype.jpg', alt: 'Early Cisco TelePresence CTS-3000 prototy_ **`src/lib/data/protocols/sip.ts`** β€” 2 term(s) -- L167 β€” `{{bandwidth|bandwidth}}` Β· _; the media (RTP) carries the bandwidth load', overhead: 'Text-base_ -- L166 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Call setup: 1-3 seconds (IN_ + +- L167 β€” `{{bandwidth|bandwidth}}` Β· _; the media (RTP) carries the bandwidth load', overhead: 'Text-base_ +- L166 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Call setup: 1-3 seconds (IN_ **`src/lib/data/protocols/smtp.ts`** β€” 2 term(s) -- L146 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Seconds to minutes (store a_ -- L11 β€” `{{hop|hop}}` Β· _internet β€” store and forward, hop by hop.', overview: `[[smtp\|_ + +- L146 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Seconds to minutes (store a_ +- L11 β€” `{{hop|hop}}` Β· _internet β€” store and forward, hop by hop.', overview: `[[smtp\|_ **`src/lib/data/protocols/soap.ts`** β€” 3 term(s) -- L127 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Same as HTTP β€” one reque_ -- L128 β€” `{{request-response|request-response}}` Β· _tency: 'Same as HTTP β€” one request-response round trip. XML parsing adds_ -- L119 β€” `{{soap-fault|SOAP Fault}}` Β· _}, { title: 'SOAP Fault', code: `HTTP/1.1 500 I_ + +- L127 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Same as HTTP β€” one reque_ +- L128 β€” `{{request-response|request-response}}` Β· _tency: 'Same as HTTP β€” one request-response round trip. XML parsing adds_ +- L119 β€” `{{soap-fault|SOAP Fault}}` Β· _}, { title: 'SOAP Fault', code: `HTTP/1.1 500 I_ **`src/lib/data/protocols/sse.ts`** β€” 1 term(s) -- L117 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Sub-second (persistent conn_ + +- L117 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Sub-second (persistent conn_ **`src/lib/data/protocols/ssh.ts`** β€” 7 term(s) -- L175 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: '1-2 RTTs for connection + k_ -- L176 β€” `{{encryption|encryption}}` Β· _, throughput: 'Hardware AES encryption; limited mainly by the networ_ -- L187 β€” `{{payload|payload}}` Β· _acket length, padding length, payload, padding, and MAC fields',_ -- L178 β€” `{{aes-gcm|AES-GCM}}` Β· _256 = 32 bytes. AEAD ciphers (AES-GCM, ChaCha20-Poly1305) use a 16-_ -- L178 β€” `{{chacha20-poly1305|ChaCha20-Poly1305}}` Β· _bytes. AEAD ciphers (AES-GCM, ChaCha20-Poly1305) use a 16-byte authentication_ -- L42 β€” `{{sftp|SFTP}}` Β· _'Secure file transfer (SCP, SFTP)', '{{port-forwarding\|Port_ -- L178 β€” `{{poly1305|Poly1305}}` Β· _AD ciphers (AES-GCM, ChaCha20-Poly1305) use a 16-byte authentication_ + +- L175 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: '1-2 RTTs for connection + k_ +- L176 β€” `{{encryption|encryption}}` Β· _, throughput: 'Hardware AES encryption; limited mainly by the networ_ +- L187 β€” `{{payload|payload}}` Β· _acket length, padding length, payload, padding, and MAC fields',_ +- L178 β€” `{{aes-gcm|AES-GCM}}` Β· _256 = 32 bytes. AEAD ciphers (AES-GCM, ChaCha20-Poly1305) use a 16-_ +- L178 β€” `{{chacha20-poly1305|ChaCha20-Poly1305}}` Β· _bytes. AEAD ciphers (AES-GCM, ChaCha20-Poly1305) use a 16-byte authentication_ +- L42 β€” `{{sftp|SFTP}}` Β· _'Secure file transfer (SCP, SFTP)', '{{port-forwarding\|Port_ +- L178 β€” `{{poly1305|Poly1305}}` Β· _AD ciphers (AES-GCM, ChaCha20-Poly1305) use a 16-byte authentication_ **`src/lib/data/protocols/stomp.ts`** β€” 2 term(s) -- L173 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Similar to the underlying b_ -- L184 β€” `{{broker|message broker}}` Β· _337%29.jpg', alt: 'RabbitMQ message broker presentation at a developer c_ + +- L173 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Similar to the underlying b_ +- L184 β€” `{{broker|message broker}}` Β· _337%29.jpg', alt: 'RabbitMQ message broker presentation at a developer c_ **`src/lib/data/protocols/tcp.ts`** β€” 14 term(s) -- L157 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: '1 RTT for TCP handshake_ -- L111 β€” `{{handshake|Handshake}}` Β· _{ title: 'Three-Way Handshake', code: `Client β†’ Serve_ -- L111 β€” `{{three-way-handshake|Three-Way Handshake}}` Β· _tions: [ { title: 'Three-Way Handshake', code: `Client β†’ Serve_ -- L277 β€” `{{ephemeral-port|Ephemeral port}}` Β· _apps.' }, { title: 'Ephemeral port exhaustion', text: 'On a_ -- L227 β€” `{{cubic|CUBIC}}` Β· _g: 'Linux kernel', scale: 'CUBIC default since 2.6.19', des_ -- L184 β€” `{{time-wait|TIME_WAIT}}` Β· _CLOSED through ESTABLISHED to TIME_WAIT', caption: 'The [[tcp\|TC_ -- L273 β€” `{{delayed-ack|Delayed ACK}}` Β· _s: [ { title: 'Nagle + Delayed ACK = 200ms latency', text: '_ -- L232 β€” `{{google|Google}}` Β· _e) run it.' }, { org: 'Google', scale: 'BBR for google.c_ -- L244 β€” `{{apple|Apple}}` Β· _ent paths.' }, { org: 'Apple', scale: 'iOS / macOS defa_ -- L238 β€” `{{meta|Meta}}` Β· _}\'s edge.' }, { org: 'Meta', scale: '>50% of traffic_ -- L193 β€” `{{linux|Linux}}` Β· _date: '2024-01', title: 'Linux 6.7 ships native TCP-AO (RFC_ -- L21 β€” `{{syn|SYN (synchronize)}}` Β· _tion: 'The client sends a SYN (synchronize) packet to the server, proposi_ -- L24 β€” `{{syn-ack|SYN-ACK}}` Β· _message.' }, { title: 'SYN-ACK β€” Server responds', descri_ -- L47 β€” `{{sftp|SFTP}}` Β· _'File transfer ([[ftp\|FTP]], SFTP)', 'Remote access ([[ssh\|SS_ + +- L157 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: '1 RTT for TCP handshake_ +- L111 β€” `{{handshake|Handshake}}` Β· _{ title: 'Three-Way Handshake', code: `Client β†’ Serve_ +- L111 β€” `{{three-way-handshake|Three-Way Handshake}}` Β· _tions: [ { title: 'Three-Way Handshake', code: `Client β†’ Serve_ +- L277 β€” `{{ephemeral-port|Ephemeral port}}` Β· _apps.' }, { title: 'Ephemeral port exhaustion', text: 'On a_ +- L227 β€” `{{cubic|CUBIC}}` Β· _g: 'Linux kernel', scale: 'CUBIC default since 2.6.19', des_ +- L184 β€” `{{time-wait|TIME_WAIT}}` Β· _CLOSED through ESTABLISHED to TIME_WAIT', caption: 'The [[tcp\|TC_ +- L273 β€” `{{delayed-ack|Delayed ACK}}` Β· _s: [ { title: 'Nagle + Delayed ACK = 200ms latency', text: '_ +- L232 β€” `{{google|Google}}` Β· _e) run it.' }, { org: 'Google', scale: 'BBR for google.c_ +- L244 β€” `{{apple|Apple}}` Β· _ent paths.' }, { org: 'Apple', scale: 'iOS / macOS defa_ +- L238 β€” `{{meta|Meta}}` Β· _}\'s edge.' }, { org: 'Meta', scale: '>50% of traffic_ +- L193 β€” `{{linux|Linux}}` Β· _date: '2024-01', title: 'Linux 6.7 ships native TCP-AO (RFC_ +- L21 β€” `{{syn|SYN (synchronize)}}` Β· _tion: 'The client sends a SYN (synchronize) packet to the server, proposi_ +- L24 β€” `{{syn-ack|SYN-ACK}}` Β· _message.' }, { title: 'SYN-ACK β€” Server responds', descri_ +- L47 β€” `{{sftp|SFTP}}` Β· _'File transfer ([[ftp\|FTP]], SFTP)', 'Remote access ([[ssh\|SS_ **`src/lib/data/protocols/tls.ts`** β€” 13 term(s) -- L170 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'TLS 1.3: 1 RTT for new conn_ -- L194 β€” `{{handshake|handshake}}` Β· _e diagram of the full TLS 1.3 handshake showing ClientHello, ServerHe_ -- L44 β€” `{{encryption|encryption}}` Β· _API communication', 'Email encryption (SMTPS, IMAPS)', '{{vpn\|VPN_ -- L26 β€” `{{certificate|Certificate}}` Β· _{ title: 'ServerHello + Certificate', description: 'Server_ -- L223 β€” `{{ech|ECH (Encrypted Client Hello)}}` Β· _date: '2024-09', title: 'ECH (Encrypted Client Hello) progresses', description:_ -- L231 β€” `{{cloudflare|Cloudflare}}` Β· _ldDeployments: [ { org: 'Cloudflare', scale: '100% of HTTPS ed_ -- L243 β€” `{{google|Google}}` Β· _in iOS 26.' }, { org: 'Google Chrome', scale: 'Chrome 12_ -- L237 β€” `{{apple|Apple}}` Β· _udflare}}.' }, { org: 'Apple', scale: 'iOS 26 / macOS 1_ -- L21 β€” `{{client-hello|ClientHello}}` Β· _howItWorks: [ { title: 'ClientHello', description: 'Client_ -- L26 β€” `{{server-hello|ServerHello}}` Β· _nd trip.' }, { title: 'ServerHello + Certificate', descriptio_ -- L172 β€” `{{aes-gcm|AES-GCM}}` Β· _: 2 RTTs.', throughput: 'AES-GCM encryption is hardware-accele_ -- L44 β€” `{{imaps|IMAPS}}` Β· _, 'Email encryption (SMTPS, IMAPS)', '{{vpn\|VPN}} tunneling (_ -- L263 β€” `{{rsa|RSA}}` Β· _emoved RC4, 3DES, MD5, SHA-1, RSA key {{exchange\|exchange}}, an_ + +- L170 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'TLS 1.3: 1 RTT for new conn_ +- L194 β€” `{{handshake|handshake}}` Β· _e diagram of the full TLS 1.3 handshake showing ClientHello, ServerHe_ +- L44 β€” `{{encryption|encryption}}` Β· _API communication', 'Email encryption (SMTPS, IMAPS)', '{{vpn\|VPN_ +- L26 β€” `{{certificate|Certificate}}` Β· _{ title: 'ServerHello + Certificate', description: 'Server_ +- L223 β€” `{{ech|ECH (Encrypted Client Hello)}}` Β· _date: '2024-09', title: 'ECH (Encrypted Client Hello) progresses', description:_ +- L231 β€” `{{cloudflare|Cloudflare}}` Β· _ldDeployments: [ { org: 'Cloudflare', scale: '100% of HTTPS ed_ +- L243 β€” `{{google|Google}}` Β· _in iOS 26.' }, { org: 'Google Chrome', scale: 'Chrome 12_ +- L237 β€” `{{apple|Apple}}` Β· _udflare}}.' }, { org: 'Apple', scale: 'iOS 26 / macOS 1_ +- L21 β€” `{{client-hello|ClientHello}}` Β· _howItWorks: [ { title: 'ClientHello', description: 'Client_ +- L26 β€” `{{server-hello|ServerHello}}` Β· _nd trip.' }, { title: 'ServerHello + Certificate', descriptio_ +- L172 β€” `{{aes-gcm|AES-GCM}}` Β· _: 2 RTTs.', throughput: 'AES-GCM encryption is hardware-accele_ +- L44 β€” `{{imaps|IMAPS}}` Β· _, 'Email encryption (SMTPS, IMAPS)', '{{vpn\|VPN}} tunneling (_ +- L263 β€” `{{rsa|RSA}}` Β· _emoved RC4, 3DES, MD5, SHA-1, RSA key {{exchange\|exchange}}, an_ **`src/lib/data/protocols/udp.ts`** β€” 10 term(s) -- L152 β€” `{{arpanet|ARPANET}}` Β· _.svg.png', alt: 'Map of the ARPANET in 1974, showing interconnect_ -- L141 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Zero connection setup; sing_ -- L19 β€” `{{handshake|handshake}}` Β· _wItWorks: [ { title: 'No handshake', description: 'Unlike_ -- L142 β€” `{{congestion-control|congestion control}}` Β· _-response', throughput: 'No congestion control β€” can send as fast as the net_ -- L141 β€” `{{request-response|request-response}}` Β· _nection setup; single RTT for request-response', throughput: 'No congestio_ -- L222 β€” `{{fragmentation|Fragmentation}}` Β· _own.' }, { title: 'Fragmentation = unreliable delivery', t_ -- L176 β€” `{{google|Google}}` Β· _e: '~14 trillion queries/day (Google 8.8.8.8 alone)', descripti_ -- L194 β€” `{{meta|Meta}}` Β· _0% of Chrome traffic, >75% of Meta', description: 'The la_ -- L167 β€” `{{linux|Linux}}` Β· _{ date: '2025', title: 'Linux io_uring + UDP zero-copy',_ -- L222 β€” `{{unreliable-delivery|unreliable delivery}}` Β· _{ title: 'Fragmentation = unreliable delivery', text: '[[udp\|UDP]] data_ + +- L152 β€” `{{arpanet|ARPANET}}` Β· _.svg.png', alt: 'Map of the ARPANET in 1974, showing interconnect_ +- L141 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Zero connection setup; sing_ +- L19 β€” `{{handshake|handshake}}` Β· _wItWorks: [ { title: 'No handshake', description: 'Unlike_ +- L142 β€” `{{congestion-control|congestion control}}` Β· _-response', throughput: 'No congestion control β€” can send as fast as the net_ +- L141 β€” `{{request-response|request-response}}` Β· _nection setup; single RTT for request-response', throughput: 'No congestio_ +- L222 β€” `{{fragmentation|Fragmentation}}` Β· _own.' }, { title: 'Fragmentation = unreliable delivery', t_ +- L176 β€” `{{google|Google}}` Β· _e: '~14 trillion queries/day (Google 8.8.8.8 alone)', descripti_ +- L194 β€” `{{meta|Meta}}` Β· _0% of Chrome traffic, >75% of Meta', description: 'The la_ +- L167 β€” `{{linux|Linux}}` Β· _{ date: '2025', title: 'Linux io_uring + UDP zero-copy',_ +- L222 β€” `{{unreliable-delivery|unreliable delivery}}` Β· _{ title: 'Fragmentation = unreliable delivery', text: '[[udp\|UDP]] data_ **`src/lib/data/protocols/uwb.ts`** β€” 7 term(s) -- L270 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Single DS-TWR ranging ro_ -- L436 β€” `{{cipher-suite|cipher suite}}` Β· _}, { title: 'STS / cipher suite β€” turn it on, and watch the r_ -- L40 β€” `{{ccc-digital-key|CCC Digital Key}}` Β· _ed form." }, { title: 'CCC Digital Key 3.0 β€” the canonical UWB unloc_ -- L343 β€” `{{aliro|Aliro}}` Β· _date: '2026-02', title: 'Aliro 1.0 finalised β€” "Matter for d_ -- L343 β€” `{{matter|Matter}}` Β· _itle: 'Aliro 1.0 finalised β€” "Matter for door locks" with UWB',_ -- L56 β€” `{{apple|Apple}}` Β· _ing with cm-class direction β€” Apple AirTag, Samsung SmartTag+, Fi_ -- L27 β€” `{{clock-drift|clock drift}}` Β· _T_reply1 + T_reply2)` cancels clock drift to first order β€” the producti_ + +- L270 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Single DS-TWR ranging ro_ +- L436 β€” `{{cipher-suite|cipher suite}}` Β· _}, { title: 'STS / cipher suite β€” turn it on, and watch the r_ +- L40 β€” `{{ccc-digital-key|CCC Digital Key}}` Β· _ed form." }, { title: 'CCC Digital Key 3.0 β€” the canonical UWB unloc_ +- L343 β€” `{{aliro|Aliro}}` Β· _date: '2026-02', title: 'Aliro 1.0 finalised β€” "Matter for d_ +- L343 β€” `{{matter|Matter}}` Β· _itle: 'Aliro 1.0 finalised β€” "Matter for door locks" with UWB',_ +- L56 β€” `{{apple|Apple}}` Β· _ing with cm-class direction β€” Apple AirTag, Samsung SmartTag+, Fi_ +- L27 β€” `{{clock-drift|clock drift}}` Β· _T_reply1 + T_reply2)` cancels clock drift to first order β€” the producti_ **`src/lib/data/protocols/webrtc.ts`** β€” 6 term(s) -- L156 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Connection setup: 2-5 secon_ -- L29 β€” `{{handshake|handshake}}` Β· _er.' }, { title: 'DTLS handshake', description: 'Once a_ -- L19 β€” `{{signaling|Signaling}}` Β· _howItWorks: [ { title: 'Signaling', description: 'Peers_ -- L24 β€” `{{ice-candidate|ICE candidate}}` Β· _re how).' }, { title: 'ICE candidate gathering', description:_ -- L40 β€” `{{google|Google}}` Β· _ses: [ 'Video conferencing (Google Meet, Zoom web client)', 'V_ -- L129 β€” `{{binding-request|STUN Binding Request}}` Β· _}, { title: 'STUN Binding Request', code: `STUN Message:_ + +- L156 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Connection setup: 2-5 secon_ +- L29 β€” `{{handshake|handshake}}` Β· _er.' }, { title: 'DTLS handshake', description: 'Once a_ +- L19 β€” `{{signaling|Signaling}}` Β· _howItWorks: [ { title: 'Signaling', description: 'Peers_ +- L24 β€” `{{ice-candidate|ICE candidate}}` Β· _re how).' }, { title: 'ICE candidate gathering', description:_ +- L40 β€” `{{google|Google}}` Β· _ses: [ 'Video conferencing (Google Meet, Zoom web client)', 'V_ +- L129 β€” `{{binding-request|STUN Binding Request}}` Β· _}, { title: 'STUN Binding Request', code: `STUN Message:_ **`src/lib/data/protocols/websockets.ts`** β€” 5 term(s) -- L112 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: '1 HTTP round trip for up_ -- L100 β€” `{{handshake|Handshake}}` Β· _{ title: 'Upgrade Handshake', code: `GET /chat HTTP_ -- L124 β€” `{{full-duplex|full-duplex}}` Β· _upgrade handshake followed by full-duplex bidirectional communication',_ -- L42 β€” `{{google|Google}}` Β· _s', 'Collaborative editing (Google Docs, Figma)', 'Multiplayer_ -- L34 β€” `{{ping|Ping}}` Β· _tweight.' }, { title: 'Ping/pong keepalive', descripti_ + +- L112 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: '1 HTTP round trip for up_ +- L100 β€” `{{handshake|Handshake}}` Β· _{ title: 'Upgrade Handshake', code: `GET /chat HTTP_ +- L124 β€” `{{full-duplex|full-duplex}}` Β· _upgrade handshake followed by full-duplex bidirectional communication',_ +- L42 β€” `{{google|Google}}` Β· _s', 'Collaborative editing (Google Docs, Figma)', 'Multiplayer_ +- L34 β€” `{{ping|Ping}}` Β· _tweight.' }, { title: 'Ping/pong keepalive', descripti_ **`src/lib/data/protocols/wifi.ts`** β€” 9 term(s) -- L164 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: '1-5 ms typical for local ac_ -- L32 β€” `{{handshake|handshake}}` Β· _s.' }, { title: '4-way handshake (WPA2/WPA3)', description:_ -- L168 β€” `{{encryption|encryption}}` Β· _flags (vs 14 for Ethernet) + encryption overhead (CCMP adds 16 bytes)_ -- L168 β€” `{{airtime|airtime}}` Β· _s); acknowledgment frames add airtime cost' }, connections: ['eth_ -- L32 β€” `{{wpa3|WPA3}}` Β· _title: '4-way handshake (WPA2/WPA3)', description: 'After_ -- L32 β€” `{{wpa2|WPA2}}` Β· _{ title: '4-way handshake (WPA2/WPA3)', description: '_ -- L141 β€” `{{beacon-frame|Beacon Frame}}` Β· _}, { title: 'Beacon Frame', code: `802.11 Beacon_ -- L32 β€” `{{four-way-handshake|4-way handshake}}` Β· _access.' }, { title: '4-way handshake (WPA2/WPA3)', description:_ -- L141 β€” `{{beacon|Beacon Frame}}` Β· _}, { title: 'Beacon Frame', code: `802.11 Beacon_ + +- L164 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: '1-5 ms typical for local ac_ +- L32 β€” `{{handshake|handshake}}` Β· _s.' }, { title: '4-way handshake (WPA2/WPA3)', description:_ +- L168 β€” `{{encryption|encryption}}` Β· _flags (vs 14 for Ethernet) + encryption overhead (CCMP adds 16 bytes)_ +- L168 β€” `{{airtime|airtime}}` Β· _s); acknowledgment frames add airtime cost' }, connections: ['eth_ +- L32 β€” `{{wpa3|WPA3}}` Β· _title: '4-way handshake (WPA2/WPA3)', description: 'After_ +- L32 β€” `{{wpa2|WPA2}}` Β· _{ title: '4-way handshake (WPA2/WPA3)', description: '_ +- L141 β€” `{{beacon-frame|Beacon Frame}}` Β· _}, { title: 'Beacon Frame', code: `802.11 Beacon_ +- L32 β€” `{{four-way-handshake|4-way handshake}}` Β· _access.' }, { title: '4-way handshake (WPA2/WPA3)', description:_ +- L141 β€” `{{beacon|Beacon Frame}}` Β· _}, { title: 'Beacon Frame', code: `802.11 Beacon_ **`src/lib/data/protocols/wireguard.ts`** β€” 7 term(s) -- L211 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: '1 round trip for handsha_ -- L25 β€” `{{handshake|Handshake}}` Β· _plane).' }, { title: 'Handshake Initiation (148 bytes, type=1_ -- L20 β€” `{{public-key|public key}}` Β· _: [ { title: 'Identity = public key', description: 'Each {_ -- L333 β€” `{{routing-table|routing table}}` Β· _title: 'AllowedIPs is your routing table AND your ACL', text: 'A s_ -- L52 β€” `{{cloudflare|Cloudflare}}` Β· _sumer "global VPN" services β€” Cloudflare WARP, Mullvad, NordVPN NordLy_ -- L212 β€” `{{linux|Linux}}` Β· _ding-plane overhead in-kernel Linux; ~3–5 ms with BoringTun (user_ -- L216 β€” `{{poly1305|Poly1305}}` Β· _B UDP + 20 B outer IP + 16 B Poly1305. Roughly 4% data inflation on_ + +- L211 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: '1 round trip for handsha_ +- L25 β€” `{{handshake|Handshake}}` Β· _plane).' }, { title: 'Handshake Initiation (148 bytes, type=1_ +- L20 β€” `{{public-key|public key}}` Β· _: [ { title: 'Identity = public key', description: 'Each {_ +- L333 β€” `{{routing-table|routing table}}` Β· _title: 'AllowedIPs is your routing table AND your ACL', text: 'A s_ +- L52 β€” `{{cloudflare|Cloudflare}}` Β· _sumer "global VPN" services β€” Cloudflare WARP, Mullvad, NordVPN NordLy_ +- L212 β€” `{{linux|Linux}}` Β· _ding-plane overhead in-kernel Linux; ~3–5 ms with BoringTun (user_ +- L216 β€” `{{poly1305|Poly1305}}` Β· _B UDP + 20 B outer IP + 16 B Poly1305. Roughly 4% data inflation on_ **`src/lib/data/protocols/xmpp.ts`** β€” 3 term(s) -- L195 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Near-instant over persis_ -- L46 β€” `{{cisco|Cisco}}` Β· _Enterprise instant messaging (Cisco Jabber, Zoom Chat backend)',_ -- L35 β€” `{{federation|federation}}` Β· _{ title: 'Server-to-server federation', description: 'When a_ + +- L195 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: 'Near-instant over persis_ +- L46 β€” `{{cisco|Cisco}}` Β· _Enterprise instant messaging (Cisco Jabber, Zoom Chat backend)',_ +- L35 β€” `{{federation|federation}}` Β· _{ title: 'Server-to-server federation', description: 'When a_ **`src/lib/data/protocols/zigbee.ts`** β€” 9 term(s) -- L234 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: '~30–80 ms one-hop ZCL co_ -- L235 β€” `{{hop|hop}}` Β· _latency: '~30–80 ms one-hop ZCL command on idle networks;_ -- L10 β€” `{{ieee-802-15-4|IEEE 802.15.4}}` Β· _rfc: 'Zigbee PRO 2023 (R23) / IEEE 802.15.4-2020', oneLiner: '{{ieee-8_ -- L40 β€” `{{trust-center|Trust Center}}` Β· _er 2023." }, { title: 'Trust Center + install codes β€” securing th_ -- L45 β€” `{{matter|Matter}}` Β· _ntirely." }, { title: 'Matter bridge β€” how Zigbee gets to t_ -- L277 β€” `{{thread|Thread}}` Β· _M3 ships globally β€” Zigbee + Thread + Matter in one box', desc_ -- L368 β€” `{{apple|Apple}}` Β· _title: 'Philips Hue\'s 2012 Apple Store launch never said "Zigb_ -- L332 β€” `{{failover|failover}}` Β· _100+ device models; multi-hub failover', description: "Shenzh_ -- L60 β€” `{{curve25519|Curve25519}}` Β· _t\|GATT}} bootstrap with SPEKE/Curve25519)', 'Utility AMI β€” Zigbee Sm_ +- L234 β€” `{{latency|latency}}` Β· _} ] }, performance: { latency: '~30–80 ms one-hop ZCL co_ +- L235 β€” `{{hop|hop}}` Β· _latency: '~30–80 ms one-hop ZCL command on idle networks;_ +- L10 β€” `{{ieee-802-15-4|IEEE 802.15.4}}` Β· _rfc: 'Zigbee PRO 2023 (R23) / IEEE 802.15.4-2020', oneLiner: '{{ieee-8_ +- L40 β€” `{{trust-center|Trust Center}}` Β· _er 2023." }, { title: 'Trust Center + install codes β€” securing th_ +- L45 β€” `{{matter|Matter}}` Β· _ntirely." }, { title: 'Matter bridge β€” how Zigbee gets to t_ +- L277 β€” `{{thread|Thread}}` Β· _M3 ships globally β€” Zigbee + Thread + Matter in one box', desc_ +- L368 β€” `{{apple|Apple}}` Β· _title: 'Philips Hue\'s 2012 Apple Store launch never said "Zigb_ +- L332 β€” `{{failover|failover}}` Β· _100+ device models; multi-hub failover', description: "Shenzh_ +- L60 β€” `{{curve25519|Curve25519}}` Β· _t\|GATT}} bootstrap with SPEKE/Curve25519)', 'Utility AMI β€” Zigbee Sm_ diff --git a/scripts/unwrap-codespans.ts b/scripts/unwrap-codespans.ts index 1e675ef..abe5b42 100644 --- a/scripts/unwrap-codespans.ts +++ b/scripts/unwrap-codespans.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ /** * unwrap-codespans.ts β€” Strip {{...}} and [[...]] wraps that ended up * inside markdown inline-code spans (\`...\` in template literals). diff --git a/scripts/validate-cross-references.ts b/scripts/validate-cross-references.ts new file mode 100644 index 0000000..e2ae967 --- /dev/null +++ b/scripts/validate-cross-references.ts @@ -0,0 +1,221 @@ +/** + * validate-cross-references.ts β€” build-time content integrity gate. + * + * The content layer is hand-authored across ~150 files and wires entities + * together by string id (protocol connections, journey steps, comparison pairs, + * subcategory membership, RFC/outage/pioneer/frontier protocol lists, story + * parents) plus inline `[[id|label]]` / `{{concept}}` markup in prose. Nothing + * at the type level catches a typo'd id. This script does: it loads every + * registry, resolves every cross-reference, and exits non-zero with a readable + * list on the first broken link. + * + * Run: npm run validate (wired into `build` and CI) + */ +import { allProtocols } from '../src/lib/data/protocols'; +import { categories } from '../src/lib/data/categories'; +import { subcategories } from '../src/lib/data/subcategories'; +import { journeys } from '../src/lib/data/journeys'; +import { allPairs } from '../src/lib/data/comparison/pairs'; +import { rfcs } from '../src/lib/data/rfcs'; +import { outages } from '../src/lib/data/outages'; +import { pioneers } from '../src/lib/data/pioneers'; +import { frontierEntries } from '../src/lib/data/frontier'; +import { concepts } from '../src/lib/data/concepts'; +import { categoryStories } from '../src/lib/data/category-stories/index'; +import { subcategoryStories } from '../src/lib/data/subcategory-stories/index'; +import { bookParts } from '../src/lib/data/book/chapters'; + +const errors: string[] = []; +const warnings: string[] = []; + +// ── Id universes ───────────────────────────────────────────────── +const P = new Set(allProtocols.map((p) => p.id)); +const C = new Set(categories.map((c) => c.id)); +const S = new Set(subcategories.map((s) => s.id)); +const OUT = new Set(outages.map((o) => o.id)); +const PIO = new Set(pioneers.map((p) => p.id)); +const FRO = new Set(frontierEntries.map((f) => f.id)); +const CON = new Set(concepts.map((c) => c.id)); +const PART = new Set(bookParts.map((b) => b.id)); + +// ── Duplicate ids ──────────────────────────────────────────────── +// A duplicate id silently shadows the earlier entry in the *Map lookups +// (Map keeps the last value), so one definition becomes unreachable. +function findDuplicates(ids: string[]): string[] { + const seen = new Set<string>(); + const dup = new Set<string>(); + for (const id of ids) { + if (seen.has(id)) dup.add(id); + seen.add(id); + } + return [...dup]; +} +for (const [label, ids, sink] of [ + ['protocol', allProtocols.map((p) => p.id), errors], + ['pioneer', pioneers.map((p) => p.id), errors], + ['RFC', rfcs.map((r) => String(r.number)), errors], + ['outage', outages.map((o) => o.id), errors], + ['frontier', frontierEntries.map((f) => f.id), errors], + // Concepts have 18 known pre-existing collisions (two authored definitions + // share an id). They render a valid definition today, so they are surfaced + // as warnings for editorial review rather than breaking the build. + ['concept', concepts.map((c) => c.id), warnings] +] as const) { + for (const id of findDuplicates(ids)) { + sink.push(`duplicate ${label} id "${id}" β€” one definition shadows the other`); + } +} + +const ref = (set: Set<string>, id: string, where: string) => { + if (!set.has(id)) errors.push(`${where} β†’ unknown id "${id}"`); +}; + +// ── 1. Protocols ───────────────────────────────────────────────── +for (const p of allProtocols) { + ref(C, p.categoryId, `protocol "${p.id}".categoryId`); + for (const c of p.connections) ref(P, c, `protocol "${p.id}".connections`); + for (const f of p.frontier ?? []) ref(FRO, f, `protocol "${p.id}".frontier`); + for (const pi of p.pioneers ?? []) ref(PIO, pi, `protocol "${p.id}".pioneers`); +} + +// ── 2. Subcategories ───────────────────────────────────────────── +const protoToSub = new Map<string, string>(); +for (const s of subcategories) { + ref(C, s.categoryId, `subcategory "${s.id}".categoryId`); + for (const pid of s.protocolIds) { + ref(P, pid, `subcategory "${s.id}".protocolIds`); + if (protoToSub.has(pid)) { + errors.push( + `protocol "${pid}" is in two subcategories ("${protoToSub.get(pid)}" and "${s.id}")` + ); + } + protoToSub.set(pid, s.id); + } +} +// Coverage (informational): protocols with no subcategory. +for (const p of allProtocols) { + if (!protoToSub.has(p.id)) warnings.push(`protocol "${p.id}" belongs to no subcategory`); +} + +// ── 3. Journeys ────────────────────────────────────────────────── +for (const j of journeys) { + if (j.scope !== 'global') ref(C, j.scope, `journey "${j.id}".scope`); + for (const step of j.steps) ref(P, step.protocolId, `journey "${j.id}" step`); +} + +// ── 4. Comparison pairs ────────────────────────────────────────── +for (const pair of allPairs) { + for (const id of pair.ids) ref(P, id, `comparison pair [${pair.ids.join(', ')}]`); +} + +// ── 5. RFCs / outages / pioneers / frontier protocol lists ─────── +for (const r of rfcs) for (const id of r.protocols ?? []) ref(P, id, `rfc ${r.number}.protocols`); +for (const o of outages) + for (const id of o.affectedProtocols ?? []) ref(P, id, `outage "${o.id}".affectedProtocols`); +for (const p of pioneers) { + for (const id of p.protocols ?? []) ref(P, id, `pioneer "${p.id}".protocols`); + for (const id of p.categories ?? []) ref(C, id, `pioneer "${p.id}".categories`); +} +for (const f of frontierEntries) + for (const id of f.protocols ?? []) ref(P, id, `frontier "${f.id}".protocols`); + +// ── 6. Story parents ───────────────────────────────────────────── +for (const cs of categoryStories) ref(C, cs.categoryId, `category-story.categoryId`); +for (const ss of subcategoryStories) ref(S, ss.subcategoryId, `subcategory-story.subcategoryId`); + +// ── 7. Inline markup in prose ──────────────────────────────────── +// Walk every string in the data layer and resolve [[id|label]] / {{concept}}. +// Skip code-bearing keys (code samples legitimately contain [[ and {{ }} that +// are not cross-references), and require slug-shaped ids to avoid matching +// template syntax like `{{ user.name }}`. +const SKIP_KEYS = new Set(['codeExample', 'code', 'wireshark', 'definition']); +const SLUG = /^[a-z0-9][a-z0-9:/-]*$/i; +const BRACKET_RE = /\[\[([^\][|]+?)(?:\|[^\]]*)?\]\]/g; +const BRACE_RE = /\{\{([^}{|]+?)(?:\|[^}]*)?\}\}/g; + +function resolveBracket(rawId: string, where: string) { + const colon = rawId.indexOf(':'); + const prefix = colon === -1 ? 'protocol' : rawId.slice(0, colon); + const id = colon === -1 ? rawId : rawId.slice(colon + 1); + switch (prefix) { + case 'protocol': + if (!P.has(id)) errors.push(`inline [[${rawId}]] in ${where} β†’ unknown protocol`); + break; + case 'rfc': + // Unregistered RFCs are fine: RfcRef falls back to an external + // datatracker.ietf.org link by design. Nothing to validate. + break; + case 'outage': + if (!OUT.has(id)) errors.push(`inline [[outage:${id}]] in ${where} β†’ unknown outage`); + break; + case 'pioneer': + if (!PIO.has(id)) errors.push(`inline [[pioneer:${id}]] in ${where} β†’ unknown pioneer`); + break; + case 'glossary': + if (!CON.has(id)) errors.push(`inline [[glossary:${id}]] in ${where} β†’ unknown concept`); + break; + case 'frontier': + if (!FRO.has(id)) errors.push(`inline [[frontier:${id}]] in ${where} β†’ unknown frontier`); + break; + case 'chapter': { + const partId = id.split('/')[0]; + if (!PART.has(partId)) + errors.push(`inline [[chapter:${id}]] in ${where} β†’ unknown book part`); + break; + } + default: + // Unknown prefix renders as visible plain text by design; flag as a warning. + warnings.push(`inline [[${rawId}]] in ${where} β†’ unrecognized prefix "${prefix}"`); + } +} + +function scanString(str: string, where: string) { + for (const m of str.matchAll(BRACKET_RE)) { + const id = m[1].trim(); + if (SLUG.test(id)) resolveBracket(id, where); + } + for (const m of str.matchAll(BRACE_RE)) { + const id = m[1].trim(); + if (SLUG.test(id) && !CON.has(id)) { + errors.push(`inline {{${id}}} in ${where} β†’ unknown concept`); + } + } +} + +function walk(value: unknown, path: string, key?: string) { + if (key && SKIP_KEYS.has(key)) return; + if (typeof value === 'string') scanString(value, path); + else if (Array.isArray(value)) value.forEach((v, i) => walk(v, `${path}[${i}]`, key)); + else if (value && typeof value === 'object') { + for (const [k, v] of Object.entries(value)) walk(v, `${path}.${k}`, k); + } +} + +walk(allProtocols, 'protocols'); +walk(concepts, 'concepts'); +walk(journeys, 'journeys'); +walk(rfcs, 'rfcs'); +walk(outages, 'outages'); +walk(pioneers, 'pioneers'); +walk(frontierEntries, 'frontier'); +walk(categoryStories, 'category-stories'); +walk(subcategoryStories, 'subcategory-stories'); +walk(bookParts, 'book'); +walk(allPairs, 'comparison-pairs'); + +// ── Report ─────────────────────────────────────────────────────── +if (warnings.length) { + console.warn(`\n⚠️ ${warnings.length} warning(s):`); + for (const w of warnings) console.warn(` ${w}`); +} +if (errors.length) { + console.error(`\n❌ Cross-reference validation failed β€” ${errors.length} broken reference(s):\n`); + for (const e of errors) console.error(` ${e}`); + process.exit(1); +} +console.log( + `\nβœ… Cross-references valid: ${allProtocols.length} protocols, ${subcategories.length} subcategories, ` + + `${journeys.length} journeys, ${allPairs.length} pairs, ${rfcs.length} RFCs, ` + + `${outages.length} outages, ${pioneers.length} pioneers, ${frontierEntries.length} frontier, ` + + `${categoryStories.length}+${subcategoryStories.length} stories β€” plus all inline [[…]]/{{…}} markup.` +); diff --git a/scripts/wrap-bare-concepts.ts b/scripts/wrap-bare-concepts.ts index bff1750..88b07bc 100644 --- a/scripts/wrap-bare-concepts.ts +++ b/scripts/wrap-bare-concepts.ts @@ -1,4 +1,3 @@ -/* eslint-disable */ /** * wrap-bare-concepts.ts β€” Auto-wrap bare technical-term mentions * (RTT, handshake, retransmission, sliding window, …) into @@ -73,15 +72,7 @@ const PARSED_FIELDS = new Set([ 'body', 'content' ]); -const SKIP_FIELDS = new Set([ - 'alt', - 'name', - 'title', - 'org', - 'label', - 'attribution', - 'authors' -]); +const SKIP_FIELDS = new Set(['alt', 'name', 'title', 'org', 'label', 'attribution', 'authors']); // Concept terms that ARE technical concepts but whose surface form is a // generic English word or an extremely common technical word. Wrapping @@ -282,11 +273,7 @@ for (const file of walk(DATA_DIR)) { const acronymMatch = fullSurface.match(/^([A-Z][A-Z0-9/-]{1,})\s+\S/); if (acronymMatch) { const acr = acronymMatch[1]; - if ( - acr.length >= 2 && - !LOW_PRIORITY.has(acr.toLowerCase()) && - !surfaces.includes(acr) - ) + if (acr.length >= 2 && !LOW_PRIORITY.has(acr.toLowerCase()) && !surfaces.includes(acr)) surfaces.push(acr); } // Also if the term itself is a bare 2-3 char acronym, surface it @@ -320,7 +307,7 @@ for (const file of walk(DATA_DIR)) { // of "Three-Way Handshake"), keep the longer surface β€” the more // specific concept wins. Without this, sequential right-to-left // replacement corrupts the wrap by inserting markup mid-token. - allHits.sort((a, b) => (b.len - a.len) || (a.off - b.off)); + allHits.sort((a, b) => b.len - a.len || a.off - b.off); const claimed: Array<[number, number]> = []; // [start, end) ranges already claimed const nonOverlap: Hit[] = []; for (const h of allHits) { diff --git a/scripts/wrap-bare-protocols.ts b/scripts/wrap-bare-protocols.ts index 5e421c4..35cd640 100644 --- a/scripts/wrap-bare-protocols.ts +++ b/scripts/wrap-bare-protocols.ts @@ -59,15 +59,7 @@ const PARSED_FIELDS = new Set([ 'oneLiner', 'transition' ]); -const SKIP_FIELDS = new Set([ - 'alt', - 'name', - 'title', - 'org', - 'label', - 'attribution', - 'authors' -]); +const SKIP_FIELDS = new Set(['alt', 'name', 'title', 'org', 'label', 'attribution', 'authors']); const dry = process.argv.includes('--dry'); @@ -242,7 +234,7 @@ for (const file of walk(DATA_DIR)) { // the longer surface (e.g. "HTTP/2" beats "HTTP" if both could ever // match the same place). Defensive β€” should be rare for protocols // but the rule is uniform with the concept wrapper. - wrappable.sort((a, b) => (b.len - a.len) || (a.off - b.off)); + wrappable.sort((a, b) => b.len - a.len || a.off - b.off); const claimed: Array<[number, number]> = []; const nonOverlap: Hit[] = []; for (const h of wrappable) { diff --git a/scripts/wrap-bare-rfcs.ts b/scripts/wrap-bare-rfcs.ts index 31396c4..a23ae7b 100644 --- a/scripts/wrap-bare-rfcs.ts +++ b/scripts/wrap-bare-rfcs.ts @@ -232,11 +232,12 @@ for (const r of reports.filter((x) => x.touched > 0).sort((a, b) => b.touched - console.log('\nSkipped (sample):'); const skippedByReason = new Map<string, number>(); for (const r of reports) - for (const h of r.skipped) - skippedByReason.set(h.skip!, (skippedByReason.get(h.skip!) ?? 0) + 1); + for (const h of r.skipped) skippedByReason.set(h.skip!, (skippedByReason.get(h.skip!) ?? 0) + 1); for (const [reason, count] of skippedByReason) console.log(` ${reason}: ${count}`); const sampleUnwrappedField = reports - .flatMap((r) => r.skipped.filter((h) => h.skip === 'unwrappedField').map((h) => ({ ...h, file: r.file }))) + .flatMap((r) => + r.skipped.filter((h) => h.skip === 'unwrappedField').map((h) => ({ ...h, file: r.file })) + ) .slice(0, 8); for (const h of sampleUnwrappedField) { console.log(` ${h.file}:${h.line} field=${h.field} ${h.match}`); diff --git a/src/app.d.ts b/src/app.d.ts index da08e6d..29cc8c9 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -8,6 +8,13 @@ declare global { // interface PageState {} // interface Platform {} } + + interface Window { + /** Dev-only navigation/testing helper, attached in dev mode (see AppShell). */ + __dev?: Record<string, unknown>; + /** Dev-only handle to the active guided-tour driver instance. */ + __tourDriver?: unknown; + } } export {}; diff --git a/src/lib/components/AppShell.svelte b/src/lib/components/AppShell.svelte index 9748fed..9bd4ac5 100644 --- a/src/lib/components/AppShell.svelte +++ b/src/lib/components/AppShell.svelte @@ -43,7 +43,7 @@ // the same code path users hit when they click a node. if (dev) { const allNodes = buildGraphNodes(); - (window as any).__dev = { + window.__dev = { appState, nodes: allNodes, /** Navigate to a protocol or category by ID, optionally open simulate tab */ diff --git a/src/lib/components/comparison/ComparisonCard.svelte b/src/lib/components/comparison/ComparisonCard.svelte index 60543a0..771cb7d 100644 --- a/src/lib/components/comparison/ComparisonCard.svelte +++ b/src/lib/components/comparison/ComparisonCard.svelte @@ -66,10 +66,15 @@ <div class="overflow-hidden rounded-lg border border-s-border"> {#each diffs as diff, i (diff.aspect)} <div class="flex text-xs {i % 2 === 0 ? 'bg-s-glass' : 'bg-transparent'}"> - <div class="w-[30%] shrink-0 border-r border-s-border px-3 py-2 font-medium text-t-secondary"> + <div + class="w-[30%] shrink-0 border-r border-s-border px-3 py-2 font-medium text-t-secondary" + > {diff.aspect} </div> - <div class="w-[35%] border-r border-s-border px-3 py-2 text-t-primary" style="border-left-color: {leftColor}30"> + <div + class="w-[35%] border-r border-s-border px-3 py-2 text-t-primary" + style="border-left-color: {leftColor}30" + > <LinkedText text={diff.left} {color} /> </div> <div class="w-[35%] px-3 py-2 text-t-primary"> @@ -89,26 +94,26 @@ <!-- Performance Comparison --> <section> - <h3 class="mb-2 text-xs font-semibold tracking-wider text-t-muted uppercase"> - Performance - </h3> + <h3 class="mb-2 text-xs font-semibold tracking-wider text-t-muted uppercase">Performance</h3> <div class="space-y-2"> - {#each [ - { label: 'Latency', left: leftProto.performance.latency, right: rightProto.performance.latency }, - { label: 'Throughput', left: leftProto.performance.throughput, right: rightProto.performance.throughput }, - { label: 'Overhead', left: leftProto.performance.overhead, right: rightProto.performance.overhead } - ] as stat (stat.label)} + {#each [{ label: 'Latency', left: leftProto.performance.latency, right: rightProto.performance.latency }, { label: 'Throughput', left: leftProto.performance.throughput, right: rightProto.performance.throughput }, { label: 'Overhead', left: leftProto.performance.overhead, right: rightProto.performance.overhead }] as stat (stat.label)} <div class="rounded-lg border border-s-border bg-s-glass p-3"> - <div class="mb-1.5 text-center text-[10px] font-semibold tracking-wider text-t-muted uppercase"> + <div + class="mb-1.5 text-center text-[10px] font-semibold tracking-wider text-t-muted uppercase" + > {stat.label} </div> <div class="flex gap-3"> <div class="flex-1 rounded border border-s-border bg-s-glass px-2.5 py-1.5"> - <div class="mb-0.5 text-[10px] font-medium" style="color: {leftColor}">{leftProto.abbreviation}</div> + <div class="mb-0.5 text-[10px] font-medium" style="color: {leftColor}"> + {leftProto.abbreviation} + </div> <div class="text-[11px] leading-relaxed text-t-secondary">{stat.left}</div> </div> <div class="flex-1 rounded border border-s-border bg-s-glass px-2.5 py-1.5"> - <div class="mb-0.5 text-[10px] font-medium" style="color: {rightColor}">{rightProto.abbreviation}</div> + <div class="mb-0.5 text-[10px] font-medium" style="color: {rightColor}"> + {rightProto.abbreviation} + </div> <div class="text-[11px] leading-relaxed text-t-secondary">{stat.right}</div> </div> </div> @@ -120,31 +125,41 @@ <!-- When to Use --> {#if useLeftWhen && useRightWhen} <section> - <h3 class="mb-2 text-xs font-semibold tracking-wider text-t-muted uppercase"> - When to Use - </h3> + <h3 class="mb-2 text-xs font-semibold tracking-wider text-t-muted uppercase">When to Use</h3> <div class="space-y-3"> - <div class="rounded-lg border px-3 py-2.5" style="border-color: {leftColor}20; background-color: {leftColor}08"> + <div + class="rounded-lg border px-3 py-2.5" + style="border-color: {leftColor}20; background-color: {leftColor}08" + > <div class="mb-1.5 text-xs font-medium" style="color: {leftColor}"> Use {leftProto.abbreviation} when: </div> <ul class="space-y-1"> {#each useLeftWhen as bullet, i (i)} <li class="flex items-start gap-2 text-xs leading-relaxed text-t-primary"> - <span class="mt-1.5 h-1 w-1 shrink-0 rounded-full" style="background-color: {leftColor}"></span> + <span + class="mt-1.5 h-1 w-1 shrink-0 rounded-full" + style="background-color: {leftColor}" + ></span> <LinkedText text={bullet} {color} /> </li> {/each} </ul> </div> - <div class="rounded-lg border px-3 py-2.5" style="border-color: {rightColor}20; background-color: {rightColor}08"> + <div + class="rounded-lg border px-3 py-2.5" + style="border-color: {rightColor}20; background-color: {rightColor}08" + > <div class="mb-1.5 text-xs font-medium" style="color: {rightColor}"> Use {rightProto.abbreviation} when: </div> <ul class="space-y-1"> {#each useRightWhen as bullet, i (i)} <li class="flex items-start gap-2 text-xs leading-relaxed text-t-primary"> - <span class="mt-1.5 h-1 w-1 shrink-0 rounded-full" style="background-color: {rightColor}"></span> + <span + class="mt-1.5 h-1 w-1 shrink-0 rounded-full" + style="background-color: {rightColor}" + ></span> <LinkedText text={bullet} {color} /> </li> {/each} @@ -153,5 +168,4 @@ </div> </section> {/if} - </div> diff --git a/src/lib/components/comparison/ComparisonPicker.svelte b/src/lib/components/comparison/ComparisonPicker.svelte index c9c2aa5..045145c 100644 --- a/src/lib/components/comparison/ComparisonPicker.svelte +++ b/src/lib/components/comparison/ComparisonPicker.svelte @@ -16,14 +16,16 @@ const pairs = $derived(getPairsForProtocol(protocolId)); const allPairs = $derived( - [...pairs.vs, ...pairs.relationships].map((pair) => { - const otherId = getOtherProtocol(pair, protocolId); - const proto = getProtocolById(otherId); - const cat = proto ? getCategoryById(proto.categoryId) : null; - return { pair, proto, cat }; - }).filter((e) => e.proto) - // Deduplicate by proto ID β€” prefer VS pairs (listed first) over relationship duplicates - .filter((e, i, arr) => arr.findIndex((x) => x.proto!.id === e.proto!.id) === i) + [...pairs.vs, ...pairs.relationships] + .map((pair) => { + const otherId = getOtherProtocol(pair, protocolId); + const proto = getProtocolById(otherId); + const cat = proto ? getCategoryById(proto.categoryId) : null; + return { pair, proto, cat }; + }) + .filter((e) => e.proto) + // Deduplicate by proto ID β€” prefer VS pairs (listed first) over relationship duplicates + .filter((e, i, arr) => arr.findIndex((x) => x.proto!.id === e.proto!.id) === i) ); </script> @@ -35,14 +37,28 @@ onclick={() => (appState.compareTargetId = proto.id)} > <div class="flex items-baseline gap-2"> - <span class="text-sm font-medium" style="color: {themedDomColor(cat?.color ?? '#FFFFFF', appState.theme)}">{proto.abbreviation}</span> + <span + class="text-sm font-medium" + style="color: {themedDomColor(cat?.color ?? '#FFFFFF', appState.theme)}" + >{proto.abbreviation}</span + > <span class="text-[10px] text-t-muted">{proto.year}</span> - <span class="rounded-full px-1.5 py-0.5 text-[9px] font-medium" style="background-color: {pair.type === 'vs' ? color + '15' : 'rgb(255 255 255 / 0.04)'}; color: {pair.type === 'vs' ? color : 'rgb(148 163 184)'}"> + <span + class="rounded-full px-1.5 py-0.5 text-[9px] font-medium" + style="background-color: {pair.type === 'vs' + ? color + '15' + : 'rgb(255 255 255 / 0.04)'}; color: {pair.type === 'vs' + ? color + : 'rgb(148 163 184)'}" + > {pair.type === 'vs' ? 'vs' : 'works with'} </span> </div> <p class="text-xs leading-relaxed text-t-secondary"> - <LinkedText text={pair.summary} color={themedDomColor(cat?.color ?? color, appState.theme)} /> + <LinkedText + text={pair.summary} + color={themedDomColor(cat?.color ?? color, appState.theme)} + /> </p> </button> {/if} diff --git a/src/lib/components/comparison/RelationshipCard.svelte b/src/lib/components/comparison/RelationshipCard.svelte index daa4fa1..9947ece 100644 --- a/src/lib/components/comparison/RelationshipCard.svelte +++ b/src/lib/components/comparison/RelationshipCard.svelte @@ -59,7 +59,9 @@ <h3 class="mb-2 text-xs font-semibold tracking-wider text-t-muted uppercase"> How They Work Together </h3> - <p class="text-xs leading-relaxed text-t-secondary"><LinkedText text={pair.howTheyWork} {color} /></p> + <p class="text-xs leading-relaxed text-t-secondary"> + <LinkedText text={pair.howTheyWork} {color} /> + </p> </section> {/if} @@ -71,19 +73,29 @@ </h3> <div class="space-y-2"> {#if leftRoleText} - <div class="rounded-lg border px-3 py-2.5" style="border-color: {leftColor}20; background-color: {leftColor}08"> + <div + class="rounded-lg border px-3 py-2.5" + style="border-color: {leftColor}20; background-color: {leftColor}08" + > <div class="mb-1 text-xs font-medium" style="color: {leftColor}"> {leftProto.abbreviation} </div> - <p class="text-xs leading-relaxed text-t-primary"><LinkedText text={leftRoleText} {color} /></p> + <p class="text-xs leading-relaxed text-t-primary"> + <LinkedText text={leftRoleText} {color} /> + </p> </div> {/if} {#if rightRoleText} - <div class="rounded-lg border px-3 py-2.5" style="border-color: {rightColor}20; background-color: {rightColor}08"> + <div + class="rounded-lg border px-3 py-2.5" + style="border-color: {rightColor}20; background-color: {rightColor}08" + > <div class="mb-1 text-xs font-medium" style="color: {rightColor}"> {rightProto.abbreviation} </div> - <p class="text-xs leading-relaxed text-t-primary"><LinkedText text={rightRoleText} {color} /></p> + <p class="text-xs leading-relaxed text-t-primary"> + <LinkedText text={rightRoleText} {color} /> + </p> </div> {/if} </div> @@ -92,26 +104,26 @@ <!-- Performance Comparison --> <section> - <h3 class="mb-2 text-xs font-semibold tracking-wider text-t-muted uppercase"> - Performance - </h3> + <h3 class="mb-2 text-xs font-semibold tracking-wider text-t-muted uppercase">Performance</h3> <div class="space-y-2"> - {#each [ - { label: 'Latency', left: leftProto.performance.latency, right: rightProto.performance.latency }, - { label: 'Throughput', left: leftProto.performance.throughput, right: rightProto.performance.throughput }, - { label: 'Overhead', left: leftProto.performance.overhead, right: rightProto.performance.overhead } - ] as stat (stat.label)} + {#each [{ label: 'Latency', left: leftProto.performance.latency, right: rightProto.performance.latency }, { label: 'Throughput', left: leftProto.performance.throughput, right: rightProto.performance.throughput }, { label: 'Overhead', left: leftProto.performance.overhead, right: rightProto.performance.overhead }] as stat (stat.label)} <div class="rounded-lg border border-s-border bg-s-glass p-3"> - <div class="mb-1.5 text-center text-[10px] font-semibold tracking-wider text-t-muted uppercase"> + <div + class="mb-1.5 text-center text-[10px] font-semibold tracking-wider text-t-muted uppercase" + > {stat.label} </div> <div class="flex gap-3"> <div class="flex-1 rounded border border-s-border bg-s-glass px-2.5 py-1.5"> - <div class="mb-0.5 text-[10px] font-medium" style="color: {leftColor}">{leftProto.abbreviation}</div> + <div class="mb-0.5 text-[10px] font-medium" style="color: {leftColor}"> + {leftProto.abbreviation} + </div> <div class="text-[11px] leading-relaxed text-t-secondary">{stat.left}</div> </div> <div class="flex-1 rounded border border-s-border bg-s-glass px-2.5 py-1.5"> - <div class="mb-0.5 text-[10px] font-medium" style="color: {rightColor}">{rightProto.abbreviation}</div> + <div class="mb-0.5 text-[10px] font-medium" style="color: {rightColor}"> + {rightProto.abbreviation} + </div> <div class="text-[11px] leading-relaxed text-t-secondary">{stat.right}</div> </div> </div> @@ -119,5 +131,4 @@ {/each} </div> </section> - </div> diff --git a/src/lib/components/desktop/AppHeader.svelte b/src/lib/components/desktop/AppHeader.svelte index 1ce0e1e..daceac4 100644 --- a/src/lib/components/desktop/AppHeader.svelte +++ b/src/lib/components/desktop/AppHeader.svelte @@ -3,20 +3,48 @@ import SearchBar from '$lib/search/SearchBar.svelte'; import { getAppState } from '$lib/state/context'; - let { onhelp, onguide, panelOpen = false }: { onhelp?: () => void; onguide?: () => void; panelOpen?: boolean } = $props(); + let { + onhelp, + onguide, + panelOpen = false + }: { onhelp?: () => void; onguide?: () => void; panelOpen?: boolean } = $props(); const appState = getAppState(); const isLight = $derived(appState.theme === 'light'); </script> -<div class="absolute left-3 top-3 z-[55] flex items-center gap-1 md:left-4 md:top-4 md:gap-1.5"> +<div class="absolute top-3 left-3 z-[55] flex items-center gap-1 md:top-4 md:left-4 md:gap-1.5"> <!-- App branding --> <div class="flex items-center gap-2.5 px-1"> <!-- Network constellation icon --> <svg viewBox="0 0 20 20" class="h-5 w-5 shrink-0" fill="none"> <!-- Connecting lines (behind nodes) --> - <line x1="10" y1="8.5" x2="10" y2="5" stroke={isLight ? '#16A34A' : '#6ee7b7'} stroke-width="1.2" opacity={isLight ? 0.7 : 0.5} /> - <line x1="8.8" y1="10.8" x2="5.6" y2="12.3" stroke={isLight ? '#7C3AED' : '#c4b5fd'} stroke-width="1.2" opacity={isLight ? 0.7 : 0.5} /> - <line x1="11.2" y1="10.8" x2="14.4" y2="12.3" stroke={isLight ? '#0284C7' : '#7dd3fc'} stroke-width="1.2" opacity={isLight ? 0.7 : 0.5} /> + <line + x1="10" + y1="8.5" + x2="10" + y2="5" + stroke={isLight ? '#16A34A' : '#6ee7b7'} + stroke-width="1.2" + opacity={isLight ? 0.7 : 0.5} + /> + <line + x1="8.8" + y1="10.8" + x2="5.6" + y2="12.3" + stroke={isLight ? '#7C3AED' : '#c4b5fd'} + stroke-width="1.2" + opacity={isLight ? 0.7 : 0.5} + /> + <line + x1="11.2" + y1="10.8" + x2="14.4" + y2="12.3" + stroke={isLight ? '#0284C7' : '#7dd3fc'} + stroke-width="1.2" + opacity={isLight ? 0.7 : 0.5} + /> <!-- Outer nodes β€” equilateral triangle --> <circle cx="10" cy="3" r="2" fill={isLight ? '#16A34A' : '#6ee7b7'} /> <circle cx="4" cy="13.5" r="2" fill={isLight ? '#7C3AED' : '#c4b5fd'} /> diff --git a/src/lib/components/desktop/GraphCanvas.svelte b/src/lib/components/desktop/GraphCanvas.svelte index e274b5a..40afbb9 100644 --- a/src/lib/components/desktop/GraphCanvas.svelte +++ b/src/lib/components/desktop/GraphCanvas.svelte @@ -1,14 +1,27 @@ <script lang="ts"> import { onMount, untrack } from 'svelte'; import { prefersReducedMotion } from 'svelte/motion'; - import { buildGraphNodes, buildGraphEdges, buildMeshEdges, getProtocolById, allProtocols, categories, subcategories } from '$lib/data/index'; + import { + buildGraphNodes, + buildGraphEdges, + buildMeshEdges, + getProtocolById, + allProtocols, + categories, + subcategories + } from '$lib/data/index'; import type { GraphNode } from '$lib/data/types'; import { createSimulation, warmUpSimulation, syncPositions } from '$lib/engine/simulation'; import { render, findNodeAtPosition } from '$lib/engine/canvas-renderer'; import { RenderLoop } from '$lib/engine/render-loop.svelte'; import { getAppState } from '$lib/state/context'; - import { computeRadialPositions, computeTimelinePositions, computeMeshPositions, TIMELINE_PARAMS } from '$lib/engine/layouts'; + import { + computeRadialPositions, + computeTimelinePositions, + computeMeshPositions, + TIMELINE_PARAMS + } from '$lib/engine/layouts'; import type { LayoutMode } from '$lib/engine/layouts'; import { getThemeColors } from '$lib/utils/colors'; import { navigateToNode, navigateToHub } from '$lib/utils/navigation'; @@ -90,7 +103,7 @@ h ^= id.charCodeAt(i); h = Math.imul(h, 0x01000193); } - return ((h >>> 0) % 1000) / 1000 * BLOOM_JITTER_MAX_MS; + return (((h >>> 0) % 1000) / 1000) * BLOOM_JITTER_MAX_MS; } function computeChronologicalDelays(): Map<string, number> { @@ -160,7 +173,7 @@ h ^= id.charCodeAt(i); h = Math.imul(h, 0x01000193); } - return ((h >>> 0) % 1000) / 1000 * SPRING_STAGGER_MAX_MS; + return (((h >>> 0) % 1000) / 1000) * SPRING_STAGGER_MAX_MS; } /** @@ -251,14 +264,14 @@ function isPanelOccupied(): boolean { return Boolean( appState.selectedNode || - appState.activeBookChapter || - appState.activeBookPart || - appState.activeBookPartToc || - appState.activePioneer || - appState.activeRfc || - appState.activeOutage || - appState.activeFrontier || - appState.activeRegistryIndex + appState.activeBookChapter || + appState.activeBookPart || + appState.activeBookPartToc || + appState.activePioneer || + appState.activeRfc || + appState.activeOutage || + appState.activeFrontier || + appState.activeRegistryIndex ); } @@ -297,13 +310,13 @@ $effect(() => { const open = Boolean( appState.activeBookChapter || - appState.activeBookPart || - appState.activeBookPartToc || - appState.activePioneer || - appState.activeRfc || - appState.activeOutage || - appState.activeFrontier || - appState.activeRegistryIndex + appState.activeBookPart || + appState.activeBookPartToc || + appState.activePioneer || + appState.activeRfc || + appState.activeOutage || + appState.activeFrontier || + appState.activeRegistryIndex ); const selected = appState.selectedNode; @@ -426,12 +439,7 @@ const t = forceTargets.get(n.id); return t ? { ...n, x: t.x, y: t.y } : n; }); - appState.focusOnSubgraph( - targetNodes, - width, - height, - isPanelOccupied() ? undefined : 0 - ); + appState.focusOnSubgraph(targetNodes, width, height, isPanelOccupied() ? undefined : 0); } else { layoutTargets = null; springStates.clear(); @@ -461,12 +469,7 @@ mode === 'mesh' ? targetNodes.filter((n) => n.type === 'protocol' || n.type === 'subcategory') : targetNodes; - appState.focusOnSubgraph( - focusNodes, - width, - height, - isPanelOccupied() ? undefined : 0 - ); + appState.focusOnSubgraph(focusNodes, width, height, isPanelOccupied() ? undefined : 0); }); } prevLayout = mode; @@ -598,10 +601,7 @@ ); if (dist < 10) { // Tap β€” select node or reset to default - const world = screenToWorld( - e.changedTouches[0].clientX, - e.changedTouches[0].clientY - ); + const world = screenToWorld(e.changedTouches[0].clientX, e.changedTouches[0].clientY); const node = findNodeAtPosition(hitNodes(), world.x, world.y, appState.viewport.scale); if (node) { navigateToNode(node); @@ -739,11 +739,11 @@ if (!bloomSpawned.has(node.id)) { bloomSpawned.add(node.id); const parentId = - node.type === 'category' - ? 'hub' - : node.type === 'subcategory' - ? node.categoryId - : (node.subcategoryId ?? node.categoryId); + node.type === 'category' + ? 'hub' + : node.type === 'subcategory' + ? node.categoryId + : (node.subcategoryId ?? node.categoryId); const parent = parentId ? nodes.find((n) => n.id === parentId) : undefined; const px = parent?.x ?? 0; const py = parent?.y ?? 0; @@ -758,10 +758,8 @@ // Critically-damped spring β†’ smooth glide to target. for (let s = 0; s < SUBSTEPS; s++) { - const ax = - BLOOM_SPRING_STIFFNESS * (target.x - node.x) - BLOOM_SPRING_DAMPING * vel.vx; - const ay = - BLOOM_SPRING_STIFFNESS * (target.y - node.y) - BLOOM_SPRING_DAMPING * vel.vy; + const ax = BLOOM_SPRING_STIFFNESS * (target.x - node.x) - BLOOM_SPRING_DAMPING * vel.vx; + const ay = BLOOM_SPRING_STIFFNESS * (target.y - node.y) - BLOOM_SPRING_DAMPING * vel.vy; vel.vx += ax * subDt; vel.vy += ay * subDt; node.x += vel.vx * subDt; diff --git a/src/lib/components/desktop/HelpModal.svelte b/src/lib/components/desktop/HelpModal.svelte index 46e0912..db93326 100644 --- a/src/lib/components/desktop/HelpModal.svelte +++ b/src/lib/components/desktop/HelpModal.svelte @@ -8,22 +8,45 @@ role="dialog" aria-modal="true" > - <div class="relative mx-4 max-w-md rounded-2xl border border-s-border bg-bg-deep/95 p-6 shadow-2xl backdrop-blur-xl"> + <div + class="relative mx-4 max-w-md rounded-2xl border border-s-border bg-bg-deep/95 p-6 shadow-2xl backdrop-blur-xl" + > <button class="absolute top-3 right-3 flex h-7 w-7 items-center justify-center rounded-lg text-t-secondary transition-colors hover:bg-s-glass-hover hover:text-t-primary" onclick={onclose} aria-label="Close" > <svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> - <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" /> + <path + stroke-linecap="round" + stroke-linejoin="round" + stroke-width="2" + d="M6 18L18 6M6 6l12 12" + /> </svg> </button> <h2 class="text-lg font-bold text-t-primary">Keyboard Shortcuts</h2> <div class="mt-4 space-y-2 text-sm text-t-primary"> - <div class="flex justify-between"><span>Zoom in/out</span><kbd class="rounded bg-s-glass px-1.5 py-0.5 text-xs text-t-secondary">Scroll</kbd></div> - <div class="flex justify-between"><span>Pan</span><kbd class="rounded bg-s-glass px-1.5 py-0.5 text-xs text-t-secondary">Drag</kbd></div> - <div class="flex justify-between"><span>Select node</span><kbd class="rounded bg-s-glass px-1.5 py-0.5 text-xs text-t-secondary">Click</kbd></div> - <div class="flex justify-between"><span>Deselect</span><kbd class="rounded bg-s-glass px-1.5 py-0.5 text-xs text-t-secondary">Click empty</kbd></div> + <div class="flex justify-between"> + <span>Zoom in/out</span><kbd + class="rounded bg-s-glass px-1.5 py-0.5 text-xs text-t-secondary">Scroll</kbd + > + </div> + <div class="flex justify-between"> + <span>Pan</span><kbd class="rounded bg-s-glass px-1.5 py-0.5 text-xs text-t-secondary" + >Drag</kbd + > + </div> + <div class="flex justify-between"> + <span>Select node</span><kbd + class="rounded bg-s-glass px-1.5 py-0.5 text-xs text-t-secondary">Click</kbd + > + </div> + <div class="flex justify-between"> + <span>Deselect</span><kbd + class="rounded bg-s-glass px-1.5 py-0.5 text-xs text-t-secondary">Click empty</kbd + > + </div> </div> </div> </div> diff --git a/src/lib/components/desktop/LayoutPicker.svelte b/src/lib/components/desktop/LayoutPicker.svelte index f20a2f8..06ce00a 100644 --- a/src/lib/components/desktop/LayoutPicker.svelte +++ b/src/lib/components/desktop/LayoutPicker.svelte @@ -40,7 +40,10 @@ ></button> {/if} -<div class="layout-picker absolute bottom-3 left-3 z-40 flex items-center gap-1.5 md:bottom-4 md:left-4 md:gap-2" data-tour="layout-picker"> +<div + class="layout-picker absolute bottom-3 left-3 z-40 flex items-center gap-1.5 md:bottom-4 md:left-4 md:gap-2" + data-tour="layout-picker" +> <!-- Compact zoom controls --> <div class="flex items-center gap-0.5 rounded-full border border-s-border bg-bg-deep/80 p-0.5 shadow-lg backdrop-blur-xl" @@ -72,51 +75,61 @@ <!-- Layout selector wrapper (relative for dropdown positioning) --> <div class="relative"> - <!-- Floating menu β€” opens upward --> - {#if open} - <div - class="absolute bottom-full left-0 mb-2 overflow-hidden rounded-xl border border-s-border bg-bg-deep/95 shadow-2xl backdrop-blur-xl" - role="menu" + <!-- Floating menu β€” opens upward --> + {#if open} + <div + class="absolute bottom-full left-0 mb-2 overflow-hidden rounded-xl border border-s-border bg-bg-deep/95 shadow-2xl backdrop-blur-xl" + role="menu" + > + {#each layouts as layout (layout.id)} + {@const isActive = appState.layoutMode === layout.id} + <button + class="flex w-full items-center gap-2.5 px-4 py-2.5 text-left text-xs transition-colors {isActive + ? 'bg-s-glass text-t-primary' + : 'text-t-secondary hover:bg-s-glass-hover hover:text-t-primary'}" + onclick={() => select(layout.id)} + role="menuitem" + > + <!-- Icon β€” shared with the guided tour via $lib/utils/layout-icons --> + <span class="layout-glyph flex h-4 w-4 shrink-0 items-center justify-center opacity-70"> + <!-- Trusted static SVG markup from $lib/utils/layout-icons --> + <!-- eslint-disable-next-line svelte/no-at-html-tags --> + {@html LAYOUT_ICON_SVG[layout.id]} + </span> + <span class="w-16 font-medium tracking-wide">{layout.label}</span> + {#if isActive} + <svg + viewBox="0 0 16 16" + class="ml-auto h-3 w-3 shrink-0 text-t-primary" + fill="currentColor" + > + <path + d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.75.75 0 0 1 1.06-1.06L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0z" + /> + </svg> + {/if} + </button> + {/each} + </div> + {/if} + + <!-- Trigger pill β€” icon mirrors whichever layout is currently active --> + <button + class="flex items-center gap-2 rounded-full border border-s-border bg-bg-deep/80 px-3.5 py-1.5 text-xs font-medium text-t-primary shadow-lg backdrop-blur-xl transition-colors hover:border-s-border hover:text-t-primary" + onclick={() => (open = !open)} + aria-haspopup="true" + aria-expanded={open} > - {#each layouts as layout (layout.id)} - {@const isActive = appState.layoutMode === layout.id} - <button - class="flex w-full items-center gap-2.5 px-4 py-2.5 text-left text-xs transition-colors {isActive - ? 'bg-s-glass text-t-primary' - : 'text-t-secondary hover:bg-s-glass-hover hover:text-t-primary'}" - onclick={() => select(layout.id)} - role="menuitem" - > - <!-- Icon β€” shared with the guided tour via $lib/utils/layout-icons --> - <span class="layout-glyph flex h-4 w-4 shrink-0 items-center justify-center opacity-70"> - {@html LAYOUT_ICON_SVG[layout.id]} - </span> - <span class="w-16 font-medium tracking-wide">{layout.label}</span> - {#if isActive} - <svg viewBox="0 0 16 16" class="ml-auto h-3 w-3 shrink-0 text-t-primary" fill="currentColor"> - <path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.75.75 0 0 1 1.06-1.06L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0z"/> - </svg> - {/if} - </button> - {/each} - </div> - {/if} - - <!-- Trigger pill β€” icon mirrors whichever layout is currently active --> - <button - class="flex items-center gap-2 rounded-full border border-s-border bg-bg-deep/80 px-3.5 py-1.5 text-xs font-medium text-t-primary shadow-lg backdrop-blur-xl transition-colors hover:border-s-border hover:text-t-primary" - onclick={() => (open = !open)} - aria-haspopup="true" - aria-expanded={open} - > - <span class="layout-glyph flex h-3.5 w-3.5 shrink-0 items-center justify-center opacity-70"> - {@html LAYOUT_ICON_SVG[appState.layoutMode]} - </span> - <span>{layouts.find((l) => l.id === appState.layoutMode)?.label ?? 'Layout'}</span> - <span class="opacity-50 transition-transform" class:rotate-180={open}> - <ChevronUp size={12} strokeWidth={2} /> - </span> - </button> + <span class="layout-glyph flex h-3.5 w-3.5 shrink-0 items-center justify-center opacity-70"> + <!-- Trusted static SVG markup from $lib/utils/layout-icons --> + <!-- eslint-disable-next-line svelte/no-at-html-tags --> + {@html LAYOUT_ICON_SVG[appState.layoutMode]} + </span> + <span>{layouts.find((l) => l.id === appState.layoutMode)?.label ?? 'Layout'}</span> + <span class="opacity-50 transition-transform" class:rotate-180={open}> + <ChevronUp size={12} strokeWidth={2} /> + </span> + </button> </div> <!-- Theme toggle --> @@ -131,7 +144,9 @@ aria-label="View on GitHub" > <svg viewBox="0 0 16 16" class="h-3.5 w-3.5" fill="currentColor"> - <path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/> + <path + d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z" + /> </svg> </a> </div> diff --git a/src/lib/components/desktop/NodeTooltip.svelte b/src/lib/components/desktop/NodeTooltip.svelte index 67e6db7..0dbe7b8 100644 --- a/src/lib/components/desktop/NodeTooltip.svelte +++ b/src/lib/components/desktop/NodeTooltip.svelte @@ -16,7 +16,6 @@ let tooltipX = $state(0); let tooltipY = $state(0); let windowWidth = $state(typeof window !== 'undefined' ? window.innerWidth : 1920); - let windowHeight = $state(typeof window !== 'undefined' ? window.innerHeight : 1080); $effect(() => { if (!appState.hoveredNode) return; @@ -28,7 +27,6 @@ function onResize() { windowWidth = window.innerWidth; - windowHeight = window.innerHeight; } // Cursor-following only matters when there's no anchor element. @@ -152,7 +150,10 @@ </div> {#if hoveredInfo.nameSegments} <p class="mt-0.5 text-[11px] text-t-secondary"> - {#each hoveredInfo.nameSegments as seg, k (k)}{#if seg.highlight}<span class="font-bold" style="color: {tc(hoveredInfo.color)}">{seg.text}</span>{:else}{seg.text}{/if}{/each} + {#each hoveredInfo.nameSegments as seg, k (k)}{#if seg.highlight}<span + class="font-bold" + style="color: {tc(hoveredInfo.color)}">{seg.text}</span + >{:else}{seg.text}{/if}{/each} </p> {/if} <p class="mt-1 text-xs leading-relaxed text-t-primary">{hoveredInfo.description}</p> diff --git a/src/lib/components/detail/BookPartView.svelte b/src/lib/components/detail/BookPartView.svelte index 0810244..0a97911 100644 --- a/src/lib/components/detail/BookPartView.svelte +++ b/src/lib/components/detail/BookPartView.svelte @@ -76,10 +76,7 @@ > Part {part.label ?? ''} </div> - <h1 - class="mt-2 text-2xl leading-tight font-bold tracking-tight" - style="color: {accent};" - > + <h1 class="mt-2 text-2xl leading-tight font-bold tracking-tight" style="color: {accent};"> {part.title} </h1> {#if part.description} @@ -99,9 +96,7 @@ style="border-color: {accent}30;" onclick={() => navigateToBookChapter(part.id, chapter.id)} > - <span - class="shrink-0 font-mono text-[10px] tabular-nums" - style="color: {accent};" + <span class="shrink-0 font-mono text-[10px] tabular-nums" style="color: {accent};" >{(i + 1).toString().padStart(2, '0')}</span > <div class="min-w-0 flex-1"> @@ -122,7 +117,7 @@ <div class="flex items-baseline gap-3 rounded-lg border border-dashed border-s-border/60 px-3 py-2.5" > - <span class="shrink-0 font-mono text-[10px] tabular-nums text-t-muted/60" + <span class="shrink-0 font-mono text-[10px] text-t-muted/60 tabular-nums" >{(i + 1).toString().padStart(2, '0')}</span > <div class="min-w-0 flex-1 opacity-70"> @@ -135,8 +130,7 @@ </div> <span class="shrink-0 rounded px-1.5 py-0.5 text-[9px] font-medium tracking-wider text-t-muted/70 uppercase" - style="background-color: rgba(148, 163, 184, 0.1);" - >Coming soon</span + style="background-color: rgba(148, 163, 184, 0.1);">Coming soon</span > </div> {/if} diff --git a/src/lib/components/detail/CategoryAdvancedView.svelte b/src/lib/components/detail/CategoryAdvancedView.svelte index c77d71f..1a11394 100644 --- a/src/lib/components/detail/CategoryAdvancedView.svelte +++ b/src/lib/components/detail/CategoryAdvancedView.svelte @@ -14,14 +14,14 @@ <div class="flex flex-col gap-5"> {#each deepDive.sections as section, i (i)} {#if section.type === 'narrative'} - <StoryNarrative text={section.text} color={color} title={section.title} /> + <StoryNarrative text={section.text} {color} title={section.title} /> {:else if section.type === 'callout'} - <StoryCallout title={section.title} text={section.text} color={color} /> + <StoryCallout title={section.title} text={section.text} {color} /> {:else if section.type === 'diagram'} <StoryDiagram definition={section.definition} caption={section.caption} - color={color} + {color} title={section.title} /> {/if} diff --git a/src/lib/components/detail/CategoryReferences.svelte b/src/lib/components/detail/CategoryReferences.svelte index d10adc4..bf2e941 100644 --- a/src/lib/components/detail/CategoryReferences.svelte +++ b/src/lib/components/detail/CategoryReferences.svelte @@ -132,9 +132,8 @@ class="flex items-baseline gap-3 rounded-lg border border-s-border bg-s-glass px-3 py-1.5 text-left transition-all hover:bg-s-glass-hover" onclick={() => navigateToRfc(r.number)} > - <code - class="shrink-0 rounded font-mono text-[11px] font-bold" - style="color: {color};">RFC {r.number}</code + <code class="shrink-0 rounded font-mono text-[11px] font-bold" style="color: {color};" + >RFC {r.number}</code > <span class="flex-1 text-xs text-t-primary">{r.title}</span> <span class="shrink-0 text-[10px] text-t-muted tabular-nums">{r.year}</span> diff --git a/src/lib/components/detail/ChapterView.svelte b/src/lib/components/detail/ChapterView.svelte index 286ba96..9ae2ac9 100644 --- a/src/lib/components/detail/ChapterView.svelte +++ b/src/lib/components/detail/ChapterView.svelte @@ -110,7 +110,8 @@ style="color: {ACCENT};" onclick={() => navigateToBookPart(partId)} > - {partLabel(partId)}{#if part} β€” {part.title}{/if} + {partLabel(partId)}{#if part} + β€” {part.title}{/if} </button> {#if currentIndex >= 0} <span>Β·</span> @@ -151,11 +152,7 @@ title={storySection.title} /> {:else if storySection.type === 'callout'} - <StoryCallout - title={storySection.title} - text={storySection.text} - color={ACCENT} - /> + <StoryCallout title={storySection.title} text={storySection.text} color={ACCENT} /> {:else if storySection.type === 'diagram'} <StoryDiagram definition={storySection.definition} @@ -186,17 +183,9 @@ {:else if slot.kind === 'prose'} {#each slot.sections as storySection, j (`prose-${i}-${j}`)} {#if storySection.type === 'narrative'} - <StoryNarrative - text={storySection.text} - color={ACCENT} - title={storySection.title} - /> + <StoryNarrative text={storySection.text} color={ACCENT} title={storySection.title} /> {:else if storySection.type === 'callout'} - <StoryCallout - title={storySection.title} - text={storySection.text} - color={ACCENT} - /> + <StoryCallout title={storySection.title} text={storySection.text} color={ACCENT} /> {:else if storySection.type === 'diagram'} <StoryDiagram definition={storySection.definition} @@ -216,18 +205,11 @@ {:else if storySection.type === 'timeline'} <StoryTimeline entries={storySection.entries} color={ACCENT} /> {:else if storySection.type === 'pioneers'} - <PioneerGrid - people={storySection.people} - color={ACCENT} - title={storySection.title} - /> + <PioneerGrid people={storySection.people} color={ACCENT} title={storySection.title} /> {/if} {/each} {:else if slot.kind === 'pull-quote'} - <aside - class="my-2 border-l-2 pl-4" - style="border-color: {ACCENT};" - > + <aside class="my-2 border-l-2 pl-4" style="border-color: {ACCENT};"> <blockquote class="text-base leading-relaxed font-medium text-t-primary italic" style="color: {ACCENT};" @@ -258,13 +240,9 @@ <div class="min-w-0 flex-1"> <div class="flex items-baseline gap-2"> <div class="text-sm font-semibold text-t-primary">{proto.name}</div> - <div class="text-[10px] tracking-wider text-t-muted uppercase"> - open protocol - </div> + <div class="text-[10px] tracking-wider text-t-muted uppercase">open protocol</div> </div> - <div - class="mt-0.5 line-clamp-2 text-[12px] leading-relaxed text-t-secondary" - > + <div class="mt-0.5 line-clamp-2 text-[12px] leading-relaxed text-t-secondary"> <RichText segments={parseRichText(proto.oneLiner)} color={ACCENT} /> </div> </div> @@ -289,7 +267,10 @@ > <PlayCircle size={28} style="color: {pc};" /> <div class="min-w-0 flex-1"> - <div class="text-[10px] font-semibold tracking-wider uppercase" style="color: {pc};"> + <div + class="text-[10px] font-semibold tracking-wider uppercase" + style="color: {pc};" + > Try the simulation </div> <div class="text-sm font-semibold text-t-primary"> @@ -316,7 +297,10 @@ <AlertTriangle size={20} class="mt-0.5 shrink-0" style="color: #fb923c;" /> <div class="min-w-0 flex-1"> <div class="flex items-baseline gap-2"> - <div class="text-[10px] font-semibold tracking-wider uppercase" style="color: #fb923c;"> + <div + class="text-[10px] font-semibold tracking-wider uppercase" + style="color: #fb923c;" + > Famous outage Β· {outage.date ?? ''} </div> </div> @@ -380,7 +364,10 @@ > <Compass size={20} class="mt-0.5 shrink-0" style="color: #a78bfa;" /> <div class="min-w-0 flex-1"> - <div class="text-[10px] font-semibold tracking-wider uppercase" style="color: #a78bfa;"> + <div + class="text-[10px] font-semibold tracking-wider uppercase" + style="color: #a78bfa;" + > Frontier Β· {fe.status} </div> <div class="text-sm font-semibold text-t-primary">{fe.title}</div> @@ -403,13 +390,16 @@ > <FileText size={20} class="mt-0.5 shrink-0" style="color: {ACCENT};" /> <div class="min-w-0 flex-1"> - <div class="text-[10px] font-semibold tracking-wider uppercase" style="color: {ACCENT};"> + <div + class="text-[10px] font-semibold tracking-wider uppercase" + style="color: {ACCENT};" + > RFC {rfc.number} Β· {rfc.year} </div> <div class="text-sm font-semibold text-t-primary">{rfc.title}</div> <div class="mt-0.5 text-[11px] tracking-wide text-t-muted"> {rfc.status}{#if rfc.authors} - Β· {rfc.authors}{/if} + Β· {rfc.authors}{/if} </div> </div> <ArrowRight @@ -428,7 +418,10 @@ class="rounded-xl border p-3.5" style="border-color: {ACCENT}66; background-color: {ACCENT}08;" > - <div class="mb-2 flex items-center gap-1.5 text-[10px] font-semibold tracking-wider uppercase" style="color: {ACCENT};"> + <div + class="mb-2 flex items-center gap-1.5 text-[10px] font-semibold tracking-wider uppercase" + style="color: {ACCENT};" + > <ArrowLeftRight size={11} /> Compare </div> diff --git a/src/lib/components/detail/CodeExample.svelte b/src/lib/components/detail/CodeExample.svelte index 9e57343..0ef37d3 100644 --- a/src/lib/components/detail/CodeExample.svelte +++ b/src/lib/components/detail/CodeExample.svelte @@ -1,34 +1,52 @@ <script lang="ts"> + import { onMount } from 'svelte'; import type { CodeExample as CodeExampleType } from '$lib/data/types'; import RichText from '$lib/components/detail/inline/RichText.svelte'; import { parseRichText } from '$lib/utils/text-parser'; - import hljs from 'highlight.js/lib/core'; - import python from 'highlight.js/lib/languages/python'; - import javascript from 'highlight.js/lib/languages/javascript'; - import typescript from 'highlight.js/lib/languages/typescript'; - import bash from 'highlight.js/lib/languages/bash'; - import http from 'highlight.js/lib/languages/http'; - import protobuf from 'highlight.js/lib/languages/protobuf'; - import xml from 'highlight.js/lib/languages/xml'; - import json from 'highlight.js/lib/languages/json'; - hljs.registerLanguage('python', python); - hljs.registerLanguage('javascript', javascript); - hljs.registerLanguage('typescript', typescript); - hljs.registerLanguage('bash', bash); - hljs.registerLanguage('http', http); - hljs.registerLanguage('protobuf', protobuf); - hljs.registerLanguage('xml', xml); - hljs.registerLanguage('json', json); + // highlight.js (core + 8 grammars) is ~150 KB. Load it lazily on mount so it + // only enters the bundle when a code example actually renders. Until it + // resolves, code shows as escaped plain text; `highlightedCode` re-derives + // once `hljs` is set. + type Hljs = typeof import('highlight.js/lib/core').default; + let hljs = $state<Hljs | null>(null); + + onMount(async () => { + const [core, python, javascript, typescript, bash, http, protobuf, xml, json] = + await Promise.all([ + import('highlight.js/lib/core'), + import('highlight.js/lib/languages/python'), + import('highlight.js/lib/languages/javascript'), + import('highlight.js/lib/languages/typescript'), + import('highlight.js/lib/languages/bash'), + import('highlight.js/lib/languages/http'), + import('highlight.js/lib/languages/protobuf'), + import('highlight.js/lib/languages/xml'), + import('highlight.js/lib/languages/json') + ]); + const h = core.default; + h.registerLanguage('python', python.default); + h.registerLanguage('javascript', javascript.default); + h.registerLanguage('typescript', typescript.default); + h.registerLanguage('bash', bash.default); + h.registerLanguage('http', http.default); + h.registerLanguage('protobuf', protobuf.default); + h.registerLanguage('xml', xml.default); + h.registerLanguage('json', json.default); + hljs = h; + }); + + function escapeHtml(code: string): string { + return code.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); + } let { example, color = '#FFFFFF' }: { example: CodeExampleType; color?: string } = $props(); let copied = $state(false); let activeTab = $state(0); const tabs = $derived.by(() => { - const list: { language: string; code: string; sections?: { title: string; code: string }[] }[] = [ - { language: example.language, code: example.code } - ]; + const list: { language: string; code: string; sections?: { title: string; code: string }[] }[] = + [{ language: example.language, code: example.code }]; if (example.alternatives) { for (const alt of example.alternatives) { list.push(alt); @@ -57,6 +75,8 @@ } function highlightCode(code: string, language: string): string { + // Until hljs finishes loading, render escaped plain text. + if (!hljs) return escapeHtml(code); const hljsLang = resolveHljsLang(language); try { if (hljs.getLanguage(hljsLang)) { @@ -64,7 +84,7 @@ } return hljs.highlightAuto(code).value; } catch { - return code.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); + return escapeHtml(code); } } @@ -111,21 +131,33 @@ } </script> +<!-- + This component renders highlight.js output. The highlighted HTML is produced + at runtime from code samples that ship in the protocol data files (trusted, + build-time content β€” never user input), so {@html} is safe here. Disabled + file-wide because the {@html} sits inside <pre> blocks where an inline + disable comment would inject stray whitespace into the rendered code. +--> +<!-- eslint-disable svelte/no-at-html-tags --> <section data-tour="code-example"> <h3 class="mb-2 text-xs font-semibold tracking-wider text-t-muted uppercase">Code Example</h3> <div class="code-block overflow-hidden rounded-xl border bg-[var(--theme-code-bg)]" style="border-color: {color}25;" > - <div class="flex items-center justify-between border-b px-3 py-2" style="border-color: {color}20;"> + <div + class="flex items-center justify-between border-b px-3 py-2" + style="border-color: {color}20;" + > {#if tabs.length > 1} <div class="flex gap-1"> {#each tabs as tab, i (tab.language)} <button - class="rounded-md px-2.5 py-1 text-[10px] font-medium tracking-wider uppercase transition-colors {activeTab !== i ? 'text-t-muted hover:bg-s-glass-hover hover:text-t-primary' : ''}" - style={activeTab === i - ? `background-color: ${color}18; color: ${color}` - : ''} + class="rounded-md px-2.5 py-1 text-[10px] font-medium tracking-wider uppercase transition-colors {activeTab !== + i + ? 'text-t-muted hover:bg-s-glass-hover hover:text-t-primary' + : ''}" + style={activeTab === i ? `background-color: ${color}18; color: ${color}` : ''} onclick={() => (activeTab = i)} > {displayLang(tab.language)} @@ -174,7 +206,10 @@ > {section.title} </div> - <pre class="custom-scrollbar overflow-x-auto px-3 py-2 text-[11px] leading-5 text-t-primary"><code class="hljs">{@html section.html}</code></pre> + <pre + class="custom-scrollbar overflow-x-auto px-3 py-2 text-[11px] leading-5 text-t-primary"><code + class="hljs">{@html section.html}</code + ></pre> </div> {#if i < highlightedSections.length - 1} <div style="border-bottom: 1px solid {color}12;"></div> diff --git a/src/lib/components/detail/ConceptTrigger.svelte b/src/lib/components/detail/ConceptTrigger.svelte index c940cc2..e436c47 100644 --- a/src/lib/components/detail/ConceptTrigger.svelte +++ b/src/lib/components/detail/ConceptTrigger.svelte @@ -33,16 +33,40 @@ showTooltip(); } } + + function applyHoverStyle(el: HTMLElement) { + el.style.borderBottomColor = isLight ? '#0369a1' : '#7dd3fc'; + el.style.color = isLight ? '#0369a1' : '#e0f2fe'; + } + + function clearHoverStyle(el: HTMLElement) { + el.style.borderBottomColor = isLight ? '#0284c7' : 'rgba(56, 189, 248, 0.7)'; + el.style.color = ''; + } </script> <button bind:this={triggerEl} - class="concept-trigger inline cursor-help border-b-[1.5px] border-dotted text-t-primary transition-all {bold ? 'font-semibold' : ''}" + class="concept-trigger inline cursor-help border-b-[1.5px] border-dotted text-t-primary transition-all {bold + ? 'font-semibold' + : ''}" style="border-bottom-color: {isLight ? '#0284c7' : 'rgba(56, 189, 248, 0.7)'};" - onmouseover={(e) => { e.currentTarget.style.borderBottomColor = isLight ? '#0369a1' : '#7dd3fc'; e.currentTarget.style.color = isLight ? '#0369a1' : '#e0f2fe'; }} - onmouseout={(e) => { e.currentTarget.style.borderBottomColor = isLight ? '#0284c7' : 'rgba(56, 189, 248, 0.7)'; e.currentTarget.style.color = ''; }} - onmouseenter={showTooltip} - onmouseleave={scheduleHide} + onmouseenter={(e) => { + applyHoverStyle(e.currentTarget); + showTooltip(); + }} + onmouseleave={(e) => { + clearHoverStyle(e.currentTarget); + scheduleHide(); + }} + onfocus={(e) => { + applyHoverStyle(e.currentTarget); + showTooltip(); + }} + onblur={(e) => { + clearHoverStyle(e.currentTarget); + scheduleHide(); + }} onclick={handleClick} > {label} diff --git a/src/lib/components/detail/DetailPanel.svelte b/src/lib/components/detail/DetailPanel.svelte index b835342..f095144 100644 --- a/src/lib/components/detail/DetailPanel.svelte +++ b/src/lib/components/detail/DetailPanel.svelte @@ -13,10 +13,8 @@ navigateToProtocol, navigateToCategory, navigateToHub, - navigateToBookChapter, navigateToBookPart } from '$lib/utils/navigation'; - import { foundationSections } from '$lib/data/concept-foundations'; import { bookParts, listChapters } from '$lib/data/book/chapters'; import GlossaryView from './GlossaryView.svelte'; import ChapterView from './ChapterView.svelte'; @@ -46,11 +44,6 @@ } from '$lib/utils/navigation'; import { Users, FileText, AlertTriangle, Compass as CompassIcon } from 'lucide-svelte'; - /** - * Hand-written teasers for the Foundation chapter cards on the Home - * tab. Each gives the reader a one-line reason to click in. Order - * matches `foundationSections` so we can zip them together. - */ /** * Per-part accent colors β€” must mirror BookTocView and ChapterView so a * part has the same hue everywhere it appears in the UI. @@ -70,22 +63,8 @@ 'how-to-learn-more': '#94a3b8' }; - const totalParts = bookParts.length; const totalChapters = listChapters().length; - const FOUNDATION_TEASERS: Record<string, string> = { - 'what-is-a-protocol': - 'What a protocol is, and why every machine on the planet agrees to follow them.', - 'layer-model': - 'Seven layers, the standards war that decided their fate, and where the layers blur.', - addressing: 'How a packet finds your laptop β€” hostnames, IPs, MACs, and ports.', - packets: 'Encapsulation in pictures β€” frames inside packets inside segments.', - 'ports-sockets': 'How one machine runs a hundred services without confusing them.', - 'reliability-speed': 'The defining tradeoff: TCP vs UDP, and why QUIC tries to have both.', - 'client-server-p2p': 'Two communication patterns and what each makes easy or hard.', - 'encryption-basics': "What HTTPS actually protects β€” and what it doesn't.", - 'ai-protocols': 'MCP and A2A β€” the new layer of protocols designed for AI agents.' - }; import ProtocolHeader from './ProtocolHeader.svelte'; import ProtocolDiagram from './ProtocolDiagram.svelte'; import HowItWorksSteps from './HowItWorksSteps.svelte'; @@ -269,7 +248,7 @@ <!-- Content layer --> <div - class="custom-scrollbar relative flex w-full min-h-0 flex-1 flex-col overflow-y-auto" + class="custom-scrollbar relative flex min-h-0 w-full flex-1 flex-col overflow-y-auto" bind:this={scrollerEl} > {#if appState.activeJourney} @@ -280,10 +259,7 @@ {#if appState.activeBookChapter && appState.activeBookPart} <div class="p-6"> - <ChapterView - partId={appState.activeBookPart} - chapterId={appState.activeBookChapter} - /> + <ChapterView partId={appState.activeBookPart} chapterId={appState.activeBookChapter} /> </div> {:else if appState.activePioneer} <div class="p-6"> @@ -349,7 +325,9 @@ <h3 class="text-xs font-semibold tracking-wider text-t-muted uppercase"> The book β€” thirteen parts </h3> - <span class="text-[10px] text-t-muted">{totalChapters} chapters Β· jump in anywhere</span> + <span class="text-[10px] text-t-muted" + >{totalChapters} chapters Β· jump in anywhere</span + > </div> <div data-tour="book-toc" class="space-y-1.5"> {#each bookParts as part (part.id)} @@ -368,7 +346,7 @@ <div class="min-w-0 flex-1"> <div class="flex items-baseline justify-between gap-2"> <div class="text-sm font-semibold text-t-primary">{part.title}</div> - <span class="shrink-0 font-mono text-[10px] tabular-nums text-t-muted" + <span class="shrink-0 font-mono text-[10px] text-t-muted tabular-nums" >{part.chapters.length} ch</span > </div> @@ -409,7 +387,9 @@ </span> <div class="min-w-0"> <div class="text-sm font-medium text-t-primary">Pioneers</div> - <div class="text-[10px] text-t-muted">{pioneers.length} architects of the field</div> + <div class="text-[10px] text-t-muted"> + {pioneers.length} architects of the field + </div> </div> </button> <button @@ -454,7 +434,9 @@ </span> <div class="min-w-0"> <div class="text-sm font-medium text-t-primary">The Frontier</div> - <div class="text-[10px] text-t-muted">{frontierEntries.length} developments, 2024-2026</div> + <div class="text-[10px] text-t-muted"> + {frontierEntries.length} developments, 2024-2026 + </div> </div> </button> </div> @@ -488,10 +470,7 @@ <span class="ml-1 text-[10px] text-t-muted">{count} protocols</span> </div> <div class="mt-0.5 text-xs text-t-secondary"> - <RichText - segments={parseRichText(cat.description)} - color={dc(cat.color)} - /> + <RichText segments={parseRichText(cat.description)} color={dc(cat.color)} /> </div> </div> </button> @@ -675,8 +654,8 @@ <span class="text-[10px] text-t-muted">{proto.year}</span> </div> <div class="text-xs text-t-secondary"> - <RichText segments={parseRichText(proto.oneLiner)} {color} /> - </div> + <RichText segments={parseRichText(proto.oneLiner)} {color} /> + </div> </button> {/each} </div> @@ -692,7 +671,7 @@ </div> {:else if appState.categoryViewMode === 'journeys'} <div class="p-6"> - <JourneyListView scope={cat.id} {color} /> + <JourneyListView scope={cat.id} /> </div> {/if} {:else if selectedData?.type === 'subcategory' && selectedData.subcategory} @@ -746,7 +725,9 @@ onclick={() => navigateToProtocol(proto.id)} > <div class="flex items-baseline gap-2"> - <span class="text-sm font-medium" style="color: {color}">{proto.abbreviation}</span> + <span class="text-sm font-medium" style="color: {color}" + >{proto.abbreviation}</span + > <span class="text-[10px] text-t-muted">{proto.year}</span> </div> <div class="text-xs text-t-secondary"> diff --git a/src/lib/components/detail/DiagramModal.svelte b/src/lib/components/detail/DiagramModal.svelte index 97c6970..3b1c53c 100644 --- a/src/lib/components/detail/DiagramModal.svelte +++ b/src/lib/components/detail/DiagramModal.svelte @@ -46,14 +46,18 @@ onclick={handleBackdropClick} > <!-- Backdrop --> - <div class="pointer-events-none absolute inset-0 bg-[var(--theme-overlay)] backdrop-blur-md"></div> + <div + class="pointer-events-none absolute inset-0 bg-[var(--theme-overlay)] backdrop-blur-md" + ></div> <!-- Modal card --> <div - class="modal-card relative z-10 flex max-h-[96vh] sm:max-h-[92vh] w-full max-w-6xl flex-col overflow-hidden rounded-2xl border border-s-border bg-bg-deep shadow-2xl" + class="modal-card relative z-10 flex max-h-[96vh] w-full max-w-6xl flex-col overflow-hidden rounded-2xl border border-s-border bg-bg-deep shadow-2xl sm:max-h-[92vh]" > <!-- Header --> - <div class="flex shrink-0 items-center justify-between border-b border-s-border px-4 py-3 sm:px-6 sm:py-4"> + <div + class="flex shrink-0 items-center justify-between border-b border-s-border px-4 py-3 sm:px-6 sm:py-4" + > <div class="flex items-center gap-2 sm:gap-3"> <div class="h-2 w-2 rounded-full" style="background-color: {color}"></div> <h3 class="text-sm font-semibold text-t-primary sm:text-base"> @@ -67,7 +71,12 @@ aria-label="Close" > <svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> - <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" /> + <path + stroke-linecap="round" + stroke-linejoin="round" + stroke-width="2" + d="M6 18L18 6M6 6l12 12" + /> </svg> </button> </div> diff --git a/src/lib/components/detail/FrontierView.svelte b/src/lib/components/detail/FrontierView.svelte index 05daf86..d9047c1 100644 --- a/src/lib/components/detail/FrontierView.svelte +++ b/src/lib/components/detail/FrontierView.svelte @@ -63,10 +63,7 @@ {STATUS_LABEL[entry.status] ?? entry.status} <span class="opacity-70">Β· {entry.date}</span> </div> - <h1 - class="mt-2 text-xl leading-tight font-bold tracking-tight" - style="color: {ACCENT};" - > + <h1 class="mt-2 text-xl leading-tight font-bold tracking-tight" style="color: {ACCENT};"> {entry.title} </h1> <p class="mt-2 text-sm leading-relaxed text-t-primary italic"> diff --git a/src/lib/components/detail/GlossaryView.svelte b/src/lib/components/detail/GlossaryView.svelte index 71155ad..2408749 100644 --- a/src/lib/components/detail/GlossaryView.svelte +++ b/src/lib/components/detail/GlossaryView.svelte @@ -223,11 +223,7 @@ {:else if seg.type === 'bold'} <strong class="font-semibold text-t-primary">{seg.value}</strong> {:else if seg.type === 'protocol-link' || seg.type === 'bold-protocol-link'} - <ProtocolLink - protocolId={seg.protocolId} - label={seg.label} - color="#38bdf8" - /> + <ProtocolLink protocolId={seg.protocolId} label={seg.label} color="#38bdf8" /> {:else if seg.type === 'concept' || seg.type === 'bold-concept'} <span class="font-medium text-t-primary">{seg.label}</span> {/if} diff --git a/src/lib/components/detail/JourneyListView.svelte b/src/lib/components/detail/JourneyListView.svelte index b100a05..68cecd2 100644 --- a/src/lib/components/detail/JourneyListView.svelte +++ b/src/lib/components/detail/JourneyListView.svelte @@ -8,7 +8,7 @@ import { parseRichText } from '$lib/utils/text-parser'; import RichText from '$lib/components/detail/inline/RichText.svelte'; - let { scope, color = '#FFFFFF' }: { scope: string; color?: string } = $props(); + let { scope }: { scope: string } = $props(); const appState = getAppState(); diff --git a/src/lib/components/detail/MermaidDiagram.svelte b/src/lib/components/detail/MermaidDiagram.svelte index bf401b5..d3c48ca 100644 --- a/src/lib/components/detail/MermaidDiagram.svelte +++ b/src/lib/components/detail/MermaidDiagram.svelte @@ -1,7 +1,7 @@ <script lang="ts"> import { onMount } from 'svelte'; import { diagramDefinitions } from '$lib/data/diagram-definitions'; - import { buildThemedDefinition, styleCrossArrows } from '$lib/utils/mermaid-helpers'; + import { buildThemedDefinition, styleCrossArrows, loadMermaid } from '$lib/utils/mermaid-helpers'; import { getAppState } from '$lib/state/context'; let { @@ -17,12 +17,7 @@ let renderCounter = 0; onMount(async () => { - const mod = await import('mermaid'); - mod.default.initialize({ - startOnLoad: false, - theme: 'dark', - securityLevel: 'loose', - fontFamily: 'ui-sans-serif, system-ui, -apple-system, sans-serif', + mermaidApi = await loadMermaid({ sequence: { actorMargin: 50, messageMargin: 25, @@ -44,7 +39,6 @@ padding: 12 } }); - mermaidApi = mod.default; }); const definition = $derived(diagramDefinitions[protocolId]); @@ -59,13 +53,16 @@ mermaidApi .render(id, fullDef) .then(({ svg }) => { + // Mermaid emits an SVG string; inject it into our empty bind:this + // container, which Svelte does not otherwise render into. + // eslint-disable-next-line svelte/no-dom-manipulating containerEl.innerHTML = svg; styleCrossArrows(containerEl); }) .catch((err) => { console.error(`Mermaid render error [${protocolId}]:`, err); - containerEl.innerHTML = - '<p class="text-xs text-t-muted py-4">Diagram unavailable</p>'; + // eslint-disable-next-line svelte/no-dom-manipulating + containerEl.innerHTML = '<p class="text-xs text-t-muted py-4">Diagram unavailable</p>'; }); }); </script> @@ -82,7 +79,7 @@ </div> </div> {#if definition?.caption && !hideCaption} - <p class="mt-3 text-center text-[11px] italic text-t-muted">{definition.caption}</p> + <p class="mt-3 text-center text-[11px] text-t-muted italic">{definition.caption}</p> {/if} </div> diff --git a/src/lib/components/detail/OutageView.svelte b/src/lib/components/detail/OutageView.svelte index bcb43aa..26cf7b8 100644 --- a/src/lib/components/detail/OutageView.svelte +++ b/src/lib/components/detail/OutageView.svelte @@ -1,10 +1,7 @@ <script lang="ts"> import { getOutageById, getProtocolById, getCategoryById } from '$lib/data/index'; import { parseRichText } from '$lib/utils/text-parser'; - import { - navigateToProtocol, - navigateToOutage as navigateToOutageUrl - } from '$lib/utils/navigation'; + import { navigateToProtocol } from '$lib/utils/navigation'; import { ExternalLink, AlertTriangle, Clock, Users, Lightbulb } from 'lucide-svelte'; import { themedDomColor } from '$lib/utils/colors'; import { getAppState } from '$lib/state/context'; @@ -60,10 +57,7 @@ {CATEGORY_LABEL[outage.category] ?? outage.category} </div> {/if} - <h1 - class="mt-2 text-2xl leading-tight font-bold tracking-tight" - style="color: {ACCENT};" - > + <h1 class="mt-2 text-2xl leading-tight font-bold tracking-tight" style="color: {ACCENT};"> {outage.title} </h1> <p class="mt-2 text-sm leading-relaxed text-t-primary italic"> @@ -115,9 +109,7 @@ <!-- Mistake --> <section> - <h2 class="mb-2 text-[11px] font-semibold tracking-wider text-t-muted uppercase"> - Mistake - </h2> + <h2 class="mb-2 text-[11px] font-semibold tracking-wider text-t-muted uppercase">Mistake</h2> <p class="text-sm leading-relaxed text-t-primary"> <RichText segments={renderRich(outage.mistake)} color={ACCENT} /> </p> @@ -137,7 +129,10 @@ style="background-color: {ACCENT};" ></div> {#if beat.time} - <div class="text-[10px] font-bold tracking-wider uppercase" style="color: {ACCENT};"> + <div + class="text-[10px] font-bold tracking-wider uppercase" + style="color: {ACCENT};" + > {beat.time} </div> {/if} diff --git a/src/lib/components/detail/PioneerView.svelte b/src/lib/components/detail/PioneerView.svelte index be5e82b..376c210 100644 --- a/src/lib/components/detail/PioneerView.svelte +++ b/src/lib/components/detail/PioneerView.svelte @@ -1,10 +1,5 @@ <script lang="ts"> - import { - getPioneerById, - getProtocolById, - getCategoryById, - categories - } from '$lib/data/index'; + import { getPioneerById, getProtocolById, getCategoryById, categories } from '$lib/data/index'; import { ExternalLink, Award, Quote } from 'lucide-svelte'; import { parseRichText } from '$lib/utils/text-parser'; import RichText from '$lib/components/detail/inline/RichText.svelte'; @@ -90,11 +85,7 @@ {:else if seg.type === 'bold'} <strong class="font-semibold text-t-primary">{seg.value}</strong> {:else if seg.type === 'protocol-link' || seg.type === 'bold-protocol-link'} - <ProtocolLink - protocolId={seg.protocolId} - label={seg.label} - color={accent} - /> + <ProtocolLink protocolId={seg.protocolId} label={seg.label} color={accent} /> {:else if seg.type === 'concept' || seg.type === 'bold-concept'} <span class="font-medium text-t-primary">{seg.label}</span> {/if} @@ -184,9 +175,7 @@ <!-- Category links --> {#if pioneer.categories && pioneer.categories.length > 0} <section> - <h3 class="mb-2 text-[10px] font-semibold tracking-wider text-t-muted uppercase"> - Areas - </h3> + <h3 class="mb-2 text-[10px] font-semibold tracking-wider text-t-muted uppercase">Areas</h3> <div class="flex flex-wrap gap-2"> {#each pioneer.categories as catId (catId)} {@const cat = getCategoryById(catId)} diff --git a/src/lib/components/detail/ProtocolDiagram.svelte b/src/lib/components/detail/ProtocolDiagram.svelte index 1822508..fa210d1 100644 --- a/src/lib/components/detail/ProtocolDiagram.svelte +++ b/src/lib/components/detail/ProtocolDiagram.svelte @@ -19,8 +19,18 @@ aria-label="Expand diagram" title="View larger" > - <svg class="h-3.5 w-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2"> - <path stroke-linecap="round" stroke-linejoin="round" d="M3.75 3.75v4.5m0-4.5h4.5m-4.5 0L9 9M3.75 20.25v-4.5m0 4.5h4.5m-4.5 0L9 15M20.25 3.75h-4.5m4.5 0v4.5m0-4.5L15 9m5.25 11.25h-4.5m4.5 0v-4.5m0 4.5L15 15" /> + <svg + class="h-3.5 w-3.5" + fill="none" + stroke="currentColor" + viewBox="0 0 24 24" + stroke-width="2" + > + <path + stroke-linecap="round" + stroke-linejoin="round" + d="M3.75 3.75v4.5m0-4.5h4.5m-4.5 0L9 9M3.75 20.25v-4.5m0 4.5h4.5m-4.5 0L9 15M20.25 3.75h-4.5m4.5 0v4.5m0-4.5L15 9m5.25 11.25h-4.5m4.5 0v-4.5m0 4.5L15 15" + /> </svg> </button> </div> diff --git a/src/lib/components/detail/ProtocolHeader.svelte b/src/lib/components/detail/ProtocolHeader.svelte index dc277c1..9b98bf2 100644 --- a/src/lib/components/detail/ProtocolHeader.svelte +++ b/src/lib/components/detail/ProtocolHeader.svelte @@ -5,7 +5,11 @@ import { parseRichText } from '$lib/utils/text-parser'; import RichText from '$lib/components/detail/inline/RichText.svelte'; - let { proto, cat, color = cat?.color ?? '#fff' }: { proto: Protocol; cat: Category | undefined; color?: string } = $props(); + let { + proto, + cat, + color = cat?.color ?? '#fff' + }: { proto: Protocol; cat: Category | undefined; color?: string } = $props(); const nameSegments = $derived(getHighlightedName(proto.id, proto.name)); </script> @@ -25,7 +29,10 @@ {/if} </div> <p class="mt-0.5 text-xs text-t-secondary"> - {#each nameSegments as seg}{#if seg.highlight}<span class="font-bold" style="color: {color}">{seg.text}</span>{:else}{seg.text}{/if}{/each} + {#each nameSegments as seg, i (i)}{#if seg.highlight}<span + class="font-bold" + style="color: {color}">{seg.text}</span + >{:else}{seg.text}{/if}{/each} </p> </div> </div> @@ -135,7 +142,7 @@ {/if} <p - class="mt-3 rounded-lg border py-2 px-3 text-sm leading-relaxed text-t-primary" + class="mt-3 rounded-lg border px-3 py-2 text-sm leading-relaxed text-t-primary" style="border-color: {color}30; background-color: {color}08" > <RichText segments={parseRichText(proto.oneLiner)} {color} /> diff --git a/src/lib/components/detail/ProtocolReferences.svelte b/src/lib/components/detail/ProtocolReferences.svelte index d5c93e9..d624697 100644 --- a/src/lib/components/detail/ProtocolReferences.svelte +++ b/src/lib/components/detail/ProtocolReferences.svelte @@ -35,13 +35,24 @@ * this protocolId. */ const chapters = $derived.by(() => { - const out: { partId: string; partTitle: string; partLabel: string; chapterId: string; chapterTitle: string; synopsis?: string }[] = []; + const out: { + partId: string; + partTitle: string; + partLabel: string; + chapterId: string; + chapterTitle: string; + synopsis?: string; + }[] = []; for (const { part, chapter } of listChapters()) { let mentions = false; for (const slot of chapter.slots) { if (slot.kind === 'protocol' && slot.id === protocolId) mentions = true; if (slot.kind === 'simulation' && slot.protocolId === protocolId) mentions = true; - if (slot.kind === 'comparison' && (slot.pairIds[0] === protocolId || slot.pairIds[1] === protocolId)) mentions = true; + if ( + slot.kind === 'comparison' && + (slot.pairIds[0] === protocolId || slot.pairIds[1] === protocolId) + ) + mentions = true; } if (mentions) { out.push({ @@ -156,9 +167,8 @@ class="flex items-baseline gap-3 rounded-lg border border-s-border bg-s-glass px-3 py-1.5 text-left transition-all hover:bg-s-glass-hover" onclick={() => navigateToRfc(r.number)} > - <code - class="shrink-0 rounded font-mono text-[11px] font-bold" - style="color: {color};">RFC {r.number}</code + <code class="shrink-0 rounded font-mono text-[11px] font-bold" style="color: {color};" + >RFC {r.number}</code > <span class="flex-1 text-xs text-t-primary">{r.title}</span> <span class="shrink-0 text-[10px] text-t-muted tabular-nums">{r.year}</span> diff --git a/src/lib/components/detail/RfcView.svelte b/src/lib/components/detail/RfcView.svelte index 1b9f505..66f7aa0 100644 --- a/src/lib/components/detail/RfcView.svelte +++ b/src/lib/components/detail/RfcView.svelte @@ -186,7 +186,6 @@ </div> </section> {/if} - </article> {:else} <div class="rounded-xl border border-s-border bg-s-glass p-6 text-center"> @@ -195,7 +194,8 @@ href="https://datatracker.ietf.org/doc/html/rfc{number}" target="_blank" rel="noopener noreferrer" - class="mt-2 inline-block text-xs text-sky-400 hover:underline">Open on datatracker.ietf.org β†’</a + class="mt-2 inline-block text-xs text-sky-400 hover:underline" + >Open on datatracker.ietf.org β†’</a > </div> {/if} diff --git a/src/lib/components/detail/SequencePlayer.svelte b/src/lib/components/detail/SequencePlayer.svelte index dba05d1..2b0e1e8 100644 --- a/src/lib/components/detail/SequencePlayer.svelte +++ b/src/lib/components/detail/SequencePlayer.svelte @@ -1,9 +1,13 @@ <script lang="ts"> import { onMount } from 'svelte'; import { diagramDefinitions } from '$lib/data/diagram-definitions'; - import { buildThemedDefinition, styleCrossArrows } from '$lib/utils/mermaid-helpers'; + import { buildThemedDefinition, styleCrossArrows, loadMermaid } from '$lib/utils/mermaid-helpers'; import { getAppState } from '$lib/state/context'; - import { parseSequenceSteps, type SequenceStep, type VisibleStep } from '$lib/utils/sequence-parser'; + import { + parseSequenceSteps, + type SequenceStep, + type VisibleStep + } from '$lib/utils/sequence-parser'; import DiagramCaption from './DiagramCaption.svelte'; export interface InlineSequence { @@ -50,16 +54,10 @@ const total = $derived(bound.length); const definition = $derived(inline ?? (protocolId ? diagramDefinitions[protocolId] : undefined)); const overallCaption = $derived(definition?.caption ?? ''); - const currentStep = $derived(cursor >= 0 && cursor < bound.length ? bound[cursor] : null); const diagramKey = $derived(protocolId ?? 'inline'); onMount(async () => { - const mod = await import('mermaid'); - mod.default.initialize({ - startOnLoad: false, - theme: 'dark', - securityLevel: 'loose', - fontFamily: 'ui-sans-serif, system-ui, -apple-system, sans-serif', + mermaidApi = await loadMermaid({ sequence: { actorMargin: 50, messageMargin: 28, @@ -75,7 +73,6 @@ noteMargin: 8 } }); - mermaidApi = mod.default; }); $effect(() => { @@ -94,6 +91,9 @@ mermaidApi .render(id, fullDef) .then(({ svg }) => { + // Mermaid emits an SVG string; inject it into our empty bind:this + // container, which Svelte does not otherwise render into. + // eslint-disable-next-line svelte/no-dom-manipulating containerEl.innerHTML = svg; styleCrossArrows(containerEl); bindStepsToDom(); @@ -104,6 +104,7 @@ }) .catch((err) => { console.error(`SequencePlayer render error [${diagramKey}]:`, err); + // eslint-disable-next-line svelte/no-dom-manipulating containerEl.innerHTML = '<p class="text-xs text-t-muted py-4 text-center">Diagram unavailable</p>'; bound = []; @@ -117,12 +118,7 @@ intersectionObserver = new IntersectionObserver( (entries) => { for (const entry of entries) { - if ( - entry.isIntersecting && - entry.intersectionRatio >= 0.25 && - !autoStarted && - !playing - ) { + if (entry.isIntersecting && entry.intersectionRatio >= 0.25 && !autoStarted && !playing) { autoStarted = true; setTimeout(() => { if (!playing) play(); @@ -141,7 +137,7 @@ function bindStepsToDom() { const svg = containerEl.querySelector('svg'); - if (!svg) { + if (!svg || !definition) { bound = []; return; } @@ -157,9 +153,9 @@ const noteTexts = [...svg.querySelectorAll<SVGTextElement>('text.noteText')].sort( (a, b) => yOf(a) - yOf(b) ); - const msgLines = [...svg.querySelectorAll<SVGElement>('.messageLine0, .messageLine1')].sort( - (a, b) => yOf(a) - yOf(b) - ); + const msgLines = [ + ...svg.querySelectorAll<SVGGraphicsElement>('.messageLine0, .messageLine1') + ].sort((a, b) => yOf(a) - yOf(b)); const msgTexts = [...svg.querySelectorAll<SVGTextElement>('text.messageText')].sort( (a, b) => yOf(a) - yOf(b) ); @@ -198,7 +194,7 @@ bound = next; } - function yOf(el: SVGElement): number { + function yOf(el: SVGGraphicsElement): number { const yAttr = el.getAttribute('y') ?? el.getAttribute('y1') ?? el.getAttribute('y2'); if (yAttr !== null) { const n = parseFloat(yAttr); @@ -338,9 +334,20 @@ }); </script> -<div class="sequence-player flex flex-col" class:expanded class:gap-4={expanded} class:gap-3={!expanded}> +<div + class="sequence-player flex flex-col" + class:expanded + class:gap-4={expanded} + class:gap-3={!expanded} +> <!-- Player controls + caption β€” sits above the diagram, not sticky. --> - <div class="player-bar flex flex-col rounded-xl border border-s-border bg-s-glass" class:gap-3={expanded} class:gap-2={!expanded} class:p-4={expanded} class:p-3={!expanded}> + <div + class="player-bar flex flex-col rounded-xl border border-s-border bg-s-glass" + class:gap-3={expanded} + class:gap-2={!expanded} + class:p-4={expanded} + class:p-3={!expanded} + > <div class="flex items-center" class:gap-3={expanded} class:gap-2={!expanded}> <button class="player-btn" @@ -349,20 +356,41 @@ aria-label="Previous step" title="Previous" > - <svg viewBox="0 0 24 24" class="player-icon" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"> + <svg + viewBox="0 0 24 24" + class="player-icon" + fill="none" + stroke="currentColor" + stroke-width="2.2" + stroke-linecap="round" + stroke-linejoin="round" + > <polyline points="15 18 9 12 15 6"></polyline> </svg> </button> {#if playing} - <button class="player-btn player-btn-primary" onclick={pause} aria-label="Pause" title="Pause" style="--c: {color};"> + <button + class="player-btn player-btn-primary" + onclick={pause} + aria-label="Pause" + title="Pause" + style="--c: {color};" + > <svg viewBox="0 0 24 24" class="player-icon" fill="currentColor"> <rect x="6" y="5" width="4" height="14" rx="1"></rect> <rect x="14" y="5" width="4" height="14" rx="1"></rect> </svg> </button> {:else} - <button class="player-btn player-btn-primary" onclick={play} aria-label="Play" title="Play" disabled={total === 0} style="--c: {color};"> + <button + class="player-btn player-btn-primary" + onclick={play} + aria-label="Play" + title="Play" + disabled={total === 0} + style="--c: {color};" + > <svg viewBox="0 0 24 24" class="player-icon" fill="currentColor"> <polygon points="6 4 20 12 6 20 6 4"></polygon> </svg> @@ -376,19 +404,41 @@ aria-label="Next step" title="Next" > - <svg viewBox="0 0 24 24" class="player-icon" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"> + <svg + viewBox="0 0 24 24" + class="player-icon" + fill="none" + stroke="currentColor" + stroke-width="2.2" + stroke-linecap="round" + stroke-linejoin="round" + > <polyline points="9 18 15 12 9 6"></polyline> </svg> </button> - <button class="player-btn" onclick={restart} aria-label="Restart" title="Restart from beginning" disabled={total === 0}> - <svg viewBox="0 0 24 24" class="player-icon" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"> + <button + class="player-btn" + onclick={restart} + aria-label="Restart" + title="Restart from beginning" + disabled={total === 0} + > + <svg + viewBox="0 0 24 24" + class="player-icon" + fill="none" + stroke="currentColor" + stroke-width="2.2" + stroke-linecap="round" + stroke-linejoin="round" + > <polyline points="1 4 1 10 7 10"></polyline> <path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10"></path> </svg> </button> - <div class="counter ml-1 tabular-nums text-t-muted"> + <div class="counter ml-1 text-t-muted tabular-nums"> {cursor + 1} / {total || 'β€”'} </div> diff --git a/src/lib/components/detail/StoryDiagramModal.svelte b/src/lib/components/detail/StoryDiagramModal.svelte index cd4084c..144a8b0 100644 --- a/src/lib/components/detail/StoryDiagramModal.svelte +++ b/src/lib/components/detail/StoryDiagramModal.svelte @@ -1,6 +1,6 @@ <script lang="ts"> import { onMount } from 'svelte'; - import { buildThemedDefinition } from '$lib/utils/mermaid-helpers'; + import { buildThemedDefinition, loadMermaid } from '$lib/utils/mermaid-helpers'; import { getAppState } from '$lib/state/context'; let { @@ -20,30 +20,20 @@ } = $props(); const appState = getAppState(); - let containerEl: HTMLDivElement; + let containerEl = $state<HTMLDivElement>(); let mermaidApi: typeof import('mermaid').default | null = $state(null); let renderCounter = 0; onMount(async () => { - const mod = await import('mermaid'); - mod.default.initialize({ - startOnLoad: false, - theme: 'dark', - securityLevel: 'loose', - fontFamily: 'ui-sans-serif, system-ui, -apple-system, sans-serif', - flowchart: { - htmlLabels: true, - curve: 'basis', - useMaxWidth: true, - padding: 16 - } + mermaidApi = await loadMermaid({ + flowchart: { htmlLabels: true, curve: 'basis', useMaxWidth: true, padding: 16 } }); - mermaidApi = mod.default; }); $effect(() => { if (!open || !mermaidApi || !definition || !containerEl) return; + const el = containerEl; const theme = appState.theme; const fullDef = buildThemedDefinition(definition, color, true, theme); const id = `mmd-story-modal-${++renderCounter}`; @@ -51,12 +41,11 @@ mermaidApi .render(id, fullDef) .then(({ svg }) => { - containerEl.innerHTML = svg; + el.innerHTML = svg; }) .catch((err) => { console.error('Story diagram modal render error:', err); - containerEl.innerHTML = - '<p class="text-xs text-t-muted py-4 text-center">Diagram unavailable</p>'; + el.innerHTML = '<p class="text-xs text-t-muted py-4 text-center">Diagram unavailable</p>'; }); }); @@ -88,7 +77,9 @@ onclick={handleBackdropClick} > <!-- Backdrop --> - <div class="pointer-events-none absolute inset-0 bg-[var(--theme-overlay)] backdrop-blur-md"></div> + <div + class="pointer-events-none absolute inset-0 bg-[var(--theme-overlay)] backdrop-blur-md" + ></div> <!-- Modal card --> <div @@ -119,9 +110,7 @@ </div> <!-- Diagram content: align top so tall diagrams stay scrollable from the top --> - <div - class="custom-scrollbar flex flex-1 flex-col items-stretch overflow-y-auto px-8 py-6" - > + <div class="custom-scrollbar flex flex-1 flex-col items-stretch overflow-y-auto px-8 py-6"> <div class="diagram-container w-full flex-shrink-0" bind:this={containerEl}> <div class="flex h-24 items-center justify-center"> <span class="text-xs text-t-muted">Loading diagram...</span> diff --git a/src/lib/components/detail/StoryImageModal.svelte b/src/lib/components/detail/StoryImageModal.svelte index 1ca4874..018e36a 100644 --- a/src/lib/components/detail/StoryImageModal.svelte +++ b/src/lib/components/detail/StoryImageModal.svelte @@ -50,7 +50,9 @@ onclick={handleBackdropClick} > <!-- Backdrop --> - <div class="pointer-events-none absolute inset-0 bg-[var(--theme-overlay)] backdrop-blur-md"></div> + <div + class="pointer-events-none absolute inset-0 bg-[var(--theme-overlay)] backdrop-blur-md" + ></div> <!-- Modal card --> <div diff --git a/src/lib/components/detail/category-story/CategoryStoryView.svelte b/src/lib/components/detail/category-story/CategoryStoryView.svelte index b81abd7..aba8b72 100644 --- a/src/lib/components/detail/category-story/CategoryStoryView.svelte +++ b/src/lib/components/detail/category-story/CategoryStoryView.svelte @@ -1,5 +1,5 @@ <script lang="ts"> - import type { CategoryStory } from '$lib/data/category-stories/types'; + import type { StoryContent } from '$lib/data/category-stories/types'; import type { Category } from '$lib/data/types'; import StoryNarrative from './StoryNarrative.svelte'; import StoryTimeline from './StoryTimeline.svelte'; @@ -10,24 +10,28 @@ import StoryComparison from './StoryComparison.svelte'; import StoryAnimatedSequence from './StoryAnimatedSequence.svelte'; - let { story, cat, color = cat.color }: { story: CategoryStory; cat: Category; color?: string } = $props(); + let { + story, + cat, + color = cat.color + }: { story: StoryContent; cat: Category; color?: string } = $props(); </script> <div class="flex flex-col gap-5"> {#each story.sections as section, i (i)} {#if section.type === 'narrative'} - <StoryNarrative text={section.text} color={color} title={section.title} /> + <StoryNarrative text={section.text} {color} title={section.title} /> {:else if section.type === 'timeline'} - <StoryTimeline entries={section.entries} color={color} /> + <StoryTimeline entries={section.entries} {color} /> {:else if section.type === 'pioneers'} - <PioneerGrid people={section.people} color={color} title={section.title} /> + <PioneerGrid people={section.people} {color} title={section.title} /> {:else if section.type === 'callout'} - <StoryCallout title={section.title} text={section.text} color={color} /> + <StoryCallout title={section.title} text={section.text} {color} /> {:else if section.type === 'diagram'} <StoryDiagram definition={section.definition} caption={section.caption} - color={color} + {color} title={section.title} /> {:else if section.type === 'image'} @@ -36,7 +40,7 @@ alt={section.alt} caption={section.caption} credit={section.credit} - color={color} + {color} title={section.title} /> {:else if section.type === 'comparison'} @@ -45,7 +49,7 @@ axes={section.axes} rows={section.rows} note={section.note} - color={color} + {color} /> {:else if section.type === 'animated-sequence'} <StoryAnimatedSequence @@ -53,7 +57,7 @@ definition={section.definition} caption={section.caption} steps={section.steps} - color={color} + {color} /> {/if} {/each} diff --git a/src/lib/components/detail/category-story/PioneerCard.svelte b/src/lib/components/detail/category-story/PioneerCard.svelte index d0e742f..edcf546 100644 --- a/src/lib/components/detail/category-story/PioneerCard.svelte +++ b/src/lib/components/detail/category-story/PioneerCard.svelte @@ -19,9 +19,7 @@ /** Resolve the pioneer-registry id either from the inline `id` field * or by matching `name` against the registry. When neither resolves, * the card stays static (no dead-button affordance). */ - const targetId = $derived( - pioneer.id ?? pioneerRegistry.find((p) => p.name === pioneer.name)?.id - ); + const targetId = $derived(pioneer.id ?? pioneerRegistry.find((p) => p.name === pioneer.name)?.id); let imgFailed = $state(false); </script> diff --git a/src/lib/components/detail/category-story/PioneerGrid.svelte b/src/lib/components/detail/category-story/PioneerGrid.svelte index 84d9647..b9898e5 100644 --- a/src/lib/components/detail/category-story/PioneerGrid.svelte +++ b/src/lib/components/detail/category-story/PioneerGrid.svelte @@ -2,11 +2,7 @@ import type { Pioneer } from '$lib/data/category-stories/types'; import PioneerCard from './PioneerCard.svelte'; - let { - people, - color, - title - }: { people: Pioneer[]; color: string; title?: string } = $props(); + let { people, color, title }: { people: Pioneer[]; color: string; title?: string } = $props(); </script> <section> diff --git a/src/lib/components/detail/category-story/StoryCallout.svelte b/src/lib/components/detail/category-story/StoryCallout.svelte index 73295ec..357a2b8 100644 --- a/src/lib/components/detail/category-story/StoryCallout.svelte +++ b/src/lib/components/detail/category-story/StoryCallout.svelte @@ -18,8 +18,7 @@ <div class="text-xs font-semibold" style="color: {color}">{title}</div> <div class="mt-1.5 space-y-2 text-xs leading-relaxed text-t-secondary"> {#snippet seg(s: TextSegment)} - {#if s.type === 'text'}{s.value}{:else if s.type === 'italic'}<em class="italic" - >{s.value}</em + {#if s.type === 'text'}{s.value}{:else if s.type === 'italic'}<em class="italic">{s.value}</em >{:else if s.type === 'code'}<code class="rounded bg-s-glass px-1 py-px font-mono text-[0.92em] text-t-primary" >{s.value}</code @@ -69,8 +68,7 @@ {#each paragraphs as segments, i (i)} <p> {#each segments as s, j (j)} - {#if s.type === 'bold'}<strong class="font-semibold text-t-primary" - >{s.value}</strong + {#if s.type === 'bold'}<strong class="font-semibold text-t-primary">{s.value}</strong >{:else if s.type === 'bold-group'}<strong class="font-semibold text-t-primary" >{#each s.segments as inner, k (k)}{@render seg(inner)}{/each}</strong >{:else}{@render seg(s)}{/if} diff --git a/src/lib/components/detail/category-story/StoryComparison.svelte b/src/lib/components/detail/category-story/StoryComparison.svelte index 56a9214..86cbbdf 100644 --- a/src/lib/components/detail/category-story/StoryComparison.svelte +++ b/src/lib/components/detail/category-story/StoryComparison.svelte @@ -45,10 +45,7 @@ <tbody> {#each rows as row, i (i)} <tr class:border-t={i > 0} class="border-s-border align-top"> - <th - class="whitespace-nowrap px-3 py-2 text-left font-semibold" - style="color: {color}" - > + <th class="px-3 py-2 text-left font-semibold whitespace-nowrap" style="color: {color}"> <RichText segments={parseRichText(row.label)} {color} /> </th> {#each row.values as val, k (k)} diff --git a/src/lib/components/detail/category-story/StoryDiagram.svelte b/src/lib/components/detail/category-story/StoryDiagram.svelte index d2a9c91..7d13592 100644 --- a/src/lib/components/detail/category-story/StoryDiagram.svelte +++ b/src/lib/components/detail/category-story/StoryDiagram.svelte @@ -4,7 +4,7 @@ <script lang="ts"> import { onMount } from 'svelte'; - import { buildThemedDefinition } from '$lib/utils/mermaid-helpers'; + import { buildThemedDefinition, loadMermaid } from '$lib/utils/mermaid-helpers'; import { getAppState } from '$lib/state/context'; import RichText from '$lib/components/detail/inline/RichText.svelte'; import { parseRichText } from '$lib/utils/text-parser'; @@ -28,20 +28,9 @@ let localCounter = 0; onMount(async () => { - const mod = await import('mermaid'); - mod.default.initialize({ - startOnLoad: false, - theme: 'dark', - securityLevel: 'loose', - fontFamily: 'ui-sans-serif, system-ui, -apple-system, sans-serif', - flowchart: { - htmlLabels: true, - curve: 'basis', - useMaxWidth: true, - padding: 12 - } + mermaidApi = await loadMermaid({ + flowchart: { htmlLabels: true, curve: 'basis', useMaxWidth: true, padding: 12 } }); - mermaidApi = mod.default; }); $effect(() => { @@ -54,10 +43,14 @@ mermaidApi .render(id, fullDef) .then(({ svg }) => { + // Mermaid emits an SVG string; inject it into our empty bind:this + // container, which Svelte does not otherwise render into. + // eslint-disable-next-line svelte/no-dom-manipulating containerEl.innerHTML = svg; }) .catch((err) => { console.error('Story diagram render error:', err); + // eslint-disable-next-line svelte/no-dom-manipulating containerEl.innerHTML = '<p class="text-xs text-t-muted py-4 text-center">Diagram unavailable</p>'; }); diff --git a/src/lib/components/detail/category-story/StoryNarrative.svelte b/src/lib/components/detail/category-story/StoryNarrative.svelte index a0f5a7e..b296c92 100644 --- a/src/lib/components/detail/category-story/StoryNarrative.svelte +++ b/src/lib/components/detail/category-story/StoryNarrative.svelte @@ -15,14 +15,15 @@ const appState = getAppState(); - type Block = - | { kind: 'p'; segments: TextSegment[] } - | { kind: 'ul'; items: TextSegment[][] }; + type Block = { kind: 'p'; segments: TextSegment[] } | { kind: 'ul'; items: TextSegment[][] }; /** Split into paragraphs, detecting blocks of `- ` / `* ` lines as lists. */ function parseBlocks(raw: string): Block[] { return raw.split('\n\n').map((p): Block => { - const lines = p.split('\n').map((l) => l.trim()).filter(Boolean); + const lines = p + .split('\n') + .map((l) => l.trim()) + .filter(Boolean); if (lines.length > 0 && lines.every((l) => /^[-*]\s+/.test(l))) { return { kind: 'ul', @@ -52,10 +53,10 @@ {/if} <div class="space-y-3 text-sm leading-relaxed text-t-primary"> {#snippet seg(s: TextSegment)} - {#if s.type === 'text'}{s.value}{:else if s.type === 'italic'}<em class="italic" - >{s.value}</em + {#if s.type === 'text'}{s.value}{:else if s.type === 'italic'}<em class="italic">{s.value}</em >{:else if s.type === 'code'}<code - class="rounded bg-s-glass px-1 py-px font-mono text-[0.92em] text-t-primary">{s.value}</code + class="rounded bg-s-glass px-1 py-px font-mono text-[0.92em] text-t-primary" + >{s.value}</code >{:else if s.type === 'protocol-link'}<ProtocolLink protocolId={s.protocolId} label={s.label} @@ -72,7 +73,10 @@ conceptId={s.conceptId} label={s.label} bold - />{:else if s.type === 'rfc-ref'}<RfcRef number={s.number} label={s.label} {color} + />{:else if s.type === 'rfc-ref'}<RfcRef + number={s.number} + label={s.label} + {color} />{:else if s.type === 'outage-link'}<OutageLink outageId={s.outageId} label={s.label} diff --git a/src/lib/components/detail/inline/ChapterLink.svelte b/src/lib/components/detail/inline/ChapterLink.svelte index e714d40..49c40aa 100644 --- a/src/lib/components/detail/inline/ChapterLink.svelte +++ b/src/lib/components/detail/inline/ChapterLink.svelte @@ -33,5 +33,7 @@ onclick={(e) => e.stopPropagation()}>{label}</a > {:else} - <span class="inline italic" style="color: {displayColor}; opacity: 0.85;" title={tooltip}>{label}</span> + <span class="inline italic" style="color: {displayColor}; opacity: 0.85;" title={tooltip} + >{label}</span + > {/if} diff --git a/src/lib/components/detail/inline/FrontierLink.svelte b/src/lib/components/detail/inline/FrontierLink.svelte index c74ac1d..9274ce1 100644 --- a/src/lib/components/detail/inline/FrontierLink.svelte +++ b/src/lib/components/detail/inline/FrontierLink.svelte @@ -34,5 +34,7 @@ <!-- Registry not yet populated for this id β€” render as styled text so the reading flow isn't broken and authors can link in later without touching prose. --> - <span class="inline italic" style="color: {displayColor}; opacity: 0.85;" title={tooltip}>{label}</span> + <span class="inline italic" style="color: {displayColor}; opacity: 0.85;" title={tooltip} + >{label}</span + > {/if} diff --git a/src/lib/components/detail/inline/OutageLink.svelte b/src/lib/components/detail/inline/OutageLink.svelte index ed8fe6a..45aa424 100644 --- a/src/lib/components/detail/inline/OutageLink.svelte +++ b/src/lib/components/detail/inline/OutageLink.svelte @@ -34,5 +34,7 @@ <!-- Registry not yet populated for this id β€” render as styled text so the reading flow isn't broken and authors can link in later without touching prose. --> - <span class="inline italic" style="color: {displayColor}; opacity: 0.85;" title={tooltip}>{label}</span> + <span class="inline italic" style="color: {displayColor}; opacity: 0.85;" title={tooltip} + >{label}</span + > {/if} diff --git a/src/lib/components/detail/inline/ProtocolLink.svelte b/src/lib/components/detail/inline/ProtocolLink.svelte index 40d1f33..94f3bf3 100644 --- a/src/lib/components/detail/inline/ProtocolLink.svelte +++ b/src/lib/components/detail/inline/ProtocolLink.svelte @@ -2,9 +2,7 @@ import { buildGraphNodes } from '$lib/data/index'; import type { GraphNode } from '$lib/data/types'; - const nodeMap: Map<string, GraphNode> = new Map( - buildGraphNodes().map((n) => [n.id, n]) - ); + const nodeMap: Map<string, GraphNode> = new Map(buildGraphNodes().map((n) => [n.id, n])); </script> <script lang="ts"> @@ -60,7 +58,10 @@ bind:this={btn} class="inline transition-colors hover:underline {bold ? 'font-semibold' : 'font-medium'}" style="color: {displayColor}" - onclick={(e) => { e.stopPropagation(); navigateToProtocol(protocolId); }} + onclick={(e) => { + e.stopPropagation(); + navigateToProtocol(protocolId); + }} onmouseenter={show} onmouseleave={hide} onfocus={show} diff --git a/src/lib/components/detail/inline/RichText.svelte b/src/lib/components/detail/inline/RichText.svelte index 2e7f805..5f943f4 100644 --- a/src/lib/components/detail/inline/RichText.svelte +++ b/src/lib/components/detail/inline/RichText.svelte @@ -71,7 +71,10 @@ color={c} />{:else if seg.type === 'bold-concept'}<strong class="font-semibold" ><GlossaryLink conceptId={seg.conceptId} label={seg.label} color={c} /></strong - >{:else if seg.type === 'rfc-ref'}<RfcRef number={seg.number} label={seg.label} color={c} + >{:else if seg.type === 'rfc-ref'}<RfcRef + number={seg.number} + label={seg.label} + color={c} />{:else if seg.type === 'pioneer-link'}<PioneerLink pioneerId={seg.pioneerId} label={seg.label} diff --git a/src/lib/components/detail/registry-index/FrontierIndex.svelte b/src/lib/components/detail/registry-index/FrontierIndex.svelte index 1961d28..1816763 100644 --- a/src/lib/components/detail/registry-index/FrontierIndex.svelte +++ b/src/lib/components/detail/registry-index/FrontierIndex.svelte @@ -52,9 +52,9 @@ What's actively shipping </h1> <p class="mt-2 text-sm leading-relaxed text-t-secondary"> - {frontierEntries.length} developments that have shipped, are rolling out, or are - standardising right now. The 2024-2026 frontier of the protocol stack β€” anything older - lives in the chapters, anything younger lives in IETF drafts. + {frontierEntries.length} developments that have shipped, are rolling out, or are standardising right + now. The 2024-2026 frontier of the protocol stack β€” anything older lives in the chapters, anything + younger lives in IETF drafts. </p> </header> diff --git a/src/lib/components/detail/registry-index/OutagesIndex.svelte b/src/lib/components/detail/registry-index/OutagesIndex.svelte index fe850a5..05ab2c9 100644 --- a/src/lib/components/detail/registry-index/OutagesIndex.svelte +++ b/src/lib/components/detail/registry-index/OutagesIndex.svelte @@ -25,9 +25,8 @@ What broke and what we learned </h1> <p class="mt-2 text-sm leading-relaxed text-t-secondary"> - {outages.length} incidents told as stories β€” setup, mistake, cascade, consequence, - lesson. The post-mortems engineers point to when they argue for redundancy, filtering, - or a less risky deployment. + {outages.length} incidents told as stories β€” setup, mistake, cascade, consequence, lesson. The post-mortems + engineers point to when they argue for redundancy, filtering, or a less risky deployment. </p> </header> @@ -38,9 +37,7 @@ onclick={() => navigateToOutage(o.id)} > <div class="flex items-baseline justify-between gap-2"> - <span class="text-sm font-medium text-t-primary" style="color: {ACCENT};" - >{o.title}</span - > + <span class="text-sm font-medium text-t-primary" style="color: {ACCENT};">{o.title}</span> <span class="shrink-0 text-[10px] text-t-muted tabular-nums">{o.date}</span> </div> <p class="text-xs leading-relaxed text-t-secondary italic"> diff --git a/src/lib/components/detail/registry-index/PioneersIndex.svelte b/src/lib/components/detail/registry-index/PioneersIndex.svelte index 425a6e8..39448bd 100644 --- a/src/lib/components/detail/registry-index/PioneersIndex.svelte +++ b/src/lib/components/detail/registry-index/PioneersIndex.svelte @@ -9,9 +9,7 @@ /** Sort pioneers by birth-year so the chronology of the field * becomes the natural reading order. */ - const sorted = $derived( - [...pioneers].sort((a, b) => parseInt(a.years) - parseInt(b.years)) - ); + const sorted = $derived([...pioneers].sort((a, b) => parseInt(a.years) - parseInt(b.years))); </script> <div class="flex flex-col gap-6"> @@ -27,9 +25,8 @@ The architects of the field </h1> <p class="mt-2 text-sm leading-relaxed text-t-secondary"> - {pioneers.length} people whose work shows up across the protocols in this lab β€” - from Bob Metcalfe's 1973 Ethernet sketch to Eric Rescorla's TLS 1.3 redesign half a - century later. + {pioneers.length} people whose work shows up across the protocols in this lab β€” from Bob Metcalfe's + 1973 Ethernet sketch to Eric Rescorla's TLS 1.3 redesign half a century later. </p> </header> diff --git a/src/lib/components/detail/registry-index/RfcsIndex.svelte b/src/lib/components/detail/registry-index/RfcsIndex.svelte index 6a17807..42bae3c 100644 --- a/src/lib/components/detail/registry-index/RfcsIndex.svelte +++ b/src/lib/components/detail/registry-index/RfcsIndex.svelte @@ -31,8 +31,8 @@ The documents </h1> <p class="mt-2 text-sm leading-relaxed text-t-secondary"> - {rfcs.length} RFCs the chapters and protocol pages cite by name. Newest first; click - any to read the spec inline with notable section pointers. + {rfcs.length} RFCs the chapters and protocol pages cite by name. Newest first; click any to read + the spec inline with notable section pointers. </p> </header> diff --git a/src/lib/components/icons/CategoryIcon.svelte b/src/lib/components/icons/CategoryIcon.svelte index e7651e6..bc78edf 100644 --- a/src/lib/components/icons/CategoryIcon.svelte +++ b/src/lib/components/icons/CategoryIcon.svelte @@ -32,7 +32,11 @@ Bluetooth } from 'lucide-svelte'; - let { icon, size = 24, animate = false }: { icon: string; size?: number; animate?: boolean } = $props(); + let { + icon, + size = 24, + animate = false + }: { icon: string; size?: number; animate?: boolean } = $props(); const iconMap: Record<string, typeof ArrowLeftRight> = { // Categories @@ -69,17 +73,10 @@ }; const Component = $derived(iconMap[icon]); - - let hovered = $state(false); </script> {#if Component} - <span - class="icon-animate inline-flex" - class:animate={hovered || animate} - onmouseenter={() => (hovered = true)} - onmouseleave={() => (hovered = false)} - > + <span class="icon-animate inline-flex" class:animate> <Component {size} strokeWidth={1.5} /> </span> {:else} @@ -102,13 +99,28 @@ .icon-animate { transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); } - .icon-animate.animate { + .icon-animate.animate, + .icon-animate:hover { animation: icon-pulse 0.6s cubic-bezier(0.175, 0.885, 0.32, 1.275); } @keyframes icon-pulse { - 0% { transform: scale(1) rotate(0deg); } - 30% { transform: scale(1.15) rotate(-5deg); } - 60% { transform: scale(1.1) rotate(3deg); } - 100% { transform: scale(1) rotate(0deg); } + 0% { + transform: scale(1) rotate(0deg); + } + 30% { + transform: scale(1.15) rotate(-5deg); + } + 60% { + transform: scale(1.1) rotate(3deg); + } + 100% { + transform: scale(1) rotate(0deg); + } + } + @media (prefers-reduced-motion: reduce) { + .icon-animate.animate, + .icon-animate:hover { + animation: none; + } } </style> diff --git a/src/lib/components/mobile/CategoryAccordion.svelte b/src/lib/components/mobile/CategoryAccordion.svelte index 325cfed..d1aba37 100644 --- a/src/lib/components/mobile/CategoryAccordion.svelte +++ b/src/lib/components/mobile/CategoryAccordion.svelte @@ -46,7 +46,7 @@ {#if expanded} <div class="space-y-2 border-t border-s-border p-3"> {#each protocols as proto (proto.id)} - <ProtocolCard {proto} color={color} /> + <ProtocolCard {proto} {color} /> {/each} </div> {/if} diff --git a/src/lib/components/mobile/MobileDetailSheet.svelte b/src/lib/components/mobile/MobileDetailSheet.svelte index e955e72..83235dd 100644 --- a/src/lib/components/mobile/MobileDetailSheet.svelte +++ b/src/lib/components/mobile/MobileDetailSheet.svelte @@ -71,7 +71,10 @@ {/if} </div> <p class="text-xs text-t-secondary"> - {#each getHighlightedName(proto.id, proto.name) as seg}{#if seg.highlight}<span class="font-bold" style="color: {color}">{seg.text}</span>{:else}{seg.text}{/if}{/each} + {#each getHighlightedName(proto.id, proto.name) as seg, i (i)}{#if seg.highlight}<span + class="font-bold" + style="color: {color}">{seg.text}</span + >{:else}{seg.text}{/if}{/each} </p> <p class="mt-2 rounded-lg border-l-2 py-2 pl-3 text-sm text-t-primary" @@ -81,7 +84,7 @@ </p> </div> - <SimulatorTabs color={color} /> + <SimulatorTabs {color} /> {#if appState.detailViewMode === 'learn'} <!-- Overview --> @@ -91,9 +94,9 @@ {/each} </div> - <ProtocolDiagram protocolId={proto.id} color={color} /> + <ProtocolDiagram protocolId={proto.id} {color} /> - <HowItWorksSteps steps={proto.howItWorks} color={color} /> + <HowItWorksSteps steps={proto.howItWorks} {color} /> <!-- Use cases --> <section> @@ -103,9 +106,7 @@ <ul class="space-y-1"> {#each proto.useCases as useCase, i (i)} <li class="flex items-start gap-2 text-xs text-t-primary"> - <span - class="mt-1.5 h-1 w-1 shrink-0 rounded-full" - style="background-color: {color}" + <span class="mt-1.5 h-1 w-1 shrink-0 rounded-full" style="background-color: {color}" ></span> {useCase} </li> @@ -117,10 +118,10 @@ <CodeExample example={proto.codeExample} /> {/if} - <PerformanceStats performance={proto.performance} color={color} /> + <PerformanceStats performance={proto.performance} {color} /> {:else if appState.detailViewMode === 'simulate'} {#key proto.id} - <SimulatorView protocolId={proto.id} color={color} /> + <SimulatorView protocolId={proto.id} {color} /> {/key} {:else if appState.detailViewMode === 'compare'} {#if appState.compareTargetId} @@ -128,13 +129,13 @@ {@const pair = getPair(proto.id, appState.compareTargetId)} {#if targetProto} {#if pair?.type === 'relationship'} - <RelationshipCard {pair} leftProto={proto} rightProto={targetProto} color={color} /> + <RelationshipCard {pair} leftProto={proto} rightProto={targetProto} {color} /> {:else} - <ComparisonCard {pair} leftProto={proto} rightProto={targetProto} color={color} /> + <ComparisonCard {pair} leftProto={proto} rightProto={targetProto} {color} /> {/if} {/if} {:else} - <ComparisonPicker protocolId={proto.id} color={color} /> + <ComparisonPicker protocolId={proto.id} {color} /> {/if} {/if} </div> diff --git a/src/lib/components/mobile/MobileView.svelte b/src/lib/components/mobile/MobileView.svelte index 49b02d7..15a3120 100644 --- a/src/lib/components/mobile/MobileView.svelte +++ b/src/lib/components/mobile/MobileView.svelte @@ -13,8 +13,24 @@ <h1 class="flex items-center justify-center gap-2 text-lg font-bold text-t-primary"> <svg viewBox="0 0 20 20" class="h-5 w-5 shrink-0" fill="none"> <line x1="10" y1="8.5" x2="10" y2="5" stroke="#6ee7b7" stroke-width="1.2" opacity="0.5" /> - <line x1="8.8" y1="10.8" x2="5.6" y2="12.3" stroke="#c4b5fd" stroke-width="1.2" opacity="0.5" /> - <line x1="11.2" y1="10.8" x2="14.4" y2="12.3" stroke="#7dd3fc" stroke-width="1.2" opacity="0.5" /> + <line + x1="8.8" + y1="10.8" + x2="5.6" + y2="12.3" + stroke="#c4b5fd" + stroke-width="1.2" + opacity="0.5" + /> + <line + x1="11.2" + y1="10.8" + x2="14.4" + y2="12.3" + stroke="#7dd3fc" + stroke-width="1.2" + opacity="0.5" + /> <circle cx="10" cy="3" r="2" fill="#6ee7b7" /> <circle cx="4" cy="13.5" r="2" fill="#c4b5fd" /> <circle cx="16" cy="13.5" r="2" fill="#7dd3fc" /> diff --git a/src/lib/data/book/chapters.ts b/src/lib/data/book/chapters.ts index 3ca465d..25da61a 100644 --- a/src/lib/data/book/chapters.ts +++ b/src/lib/data/book/chapters.ts @@ -47,8 +47,7 @@ const FOUNDATION_SYNOPSIS: Record<string, string> = { 'Two communication patterns β€” {{client-server|client/server}} and {{peer-to-peer|peer-to-peer}} β€” and what each makes easy or hard.', 'encryption-basics': "What HTTPS actually protects β€” and what it doesn't. [[tls|TLS]] at the boundary.", - 'ai-protocols': - '[[mcp|MCP]] and [[a2a|A2A]] β€” the new layer of protocols designed for AI agents.' + 'ai-protocols': '[[mcp|MCP]] and [[a2a|A2A]] β€” the new layer of protocols designed for AI agents.' }; const partI: BookPart = { @@ -65,16 +64,6 @@ const partI: BookPart = { })) }; -/** - * Parts II–XII β€” outline only for now. Empty `slots` arrays mark - * each chapter as "coming soon"; the TOC renderer treats them - * differently from clickable chapters. Filling them in is the next - * sustained content workstream. - */ -function stubChapters(items: { id: string; title: string; synopsis: string }[]): Chapter[] { - return items.map((c) => ({ id: c.id, title: c.title, synopsis: c.synopsis, slots: [] })); -} - export const bookParts: BookPart[] = [ partI, storyOfTheInternet, diff --git a/src/lib/data/book/parts/async-iot.ts b/src/lib/data/book/parts/async-iot.ts index 6195557..022b853 100644 --- a/src/lib/data/book/parts/async-iot.ts +++ b/src/lib/data/book/parts/async-iot.ts @@ -19,7 +19,8 @@ export const asyncIot: BookPart = { { id: 'mqtt', title: 'MQTT', - synopsis: 'Sensors, satellites, and [[mqtt|2-byte publish overhead]] β€” designed in 1999 to instrument oil pipelines.', + synopsis: + 'Sensors, satellites, and [[mqtt|2-byte publish overhead]] β€” designed in 1999 to instrument oil pipelines.', slots: [ { kind: 'pull-quote', @@ -84,11 +85,12 @@ The architecture is **{{mqtt-publish|publish}}-{{mqtt-subscribe|subscribe}}** th { id: 'amqp', title: 'AMQP', - synopsis: '[[amqp|Banking-grade messaging]] β€” JPMorgan Chase, John O\'Hara, and "two billion dollars in collateral calls before he could blink."', + synopsis: + '[[amqp|Banking-grade messaging]] β€” JPMorgan Chase, John O\'Hara, and "two billion dollars in collateral calls before he could blink."', slots: [ { kind: 'pull-quote', - text: 'If you read [[amqp|AMQP]] 1.0, it\'s called Advanced Message Queue Protocol, but there are no queues in it.', + text: "If you read [[amqp|AMQP]] 1.0, it's called Advanced Message Queue Protocol, but there are no queues in it.", attribution: 'Alexis Richardson, March 2025' }, { @@ -147,7 +149,8 @@ The trade-off versus [[mqtt|MQTT]] remains operational complexity. An [[amqp|AMQ { id: 'kafka', title: 'Kafka', - synopsis: '[[kafka|A distributed commit log]] as architecture unit β€” {{linkedin|LinkedIn}}, 2010, named after Franz [[kafka|Kafka]] because "it\'s a system optimized for writing."', + synopsis: + '[[kafka|A distributed commit log]] as architecture unit β€” {{linkedin|LinkedIn}}, 2010, named after Franz [[kafka|Kafka]] because "it\'s a system optimized for writing."', slots: [ { kind: 'pull-quote', @@ -212,11 +215,12 @@ The wire-level details that {{matter|matter}} operationally: [[kafka|Kafka]]'s r { id: 'coap', title: 'CoAP', - synopsis: '[[coap|REST shrunk for microcontrollers]] β€” and one of the most-deployed-at-scale uses turned out to be Chinese smartphones.', + synopsis: + '[[coap|REST shrunk for microcontrollers]] β€” and one of the most-deployed-at-scale uses turned out to be Chinese smartphones.', slots: [ { kind: 'pull-quote', - text: 'NETSCOUT\'s January 2019 scan found 388,344 publicly-reachable [[coap|CoAP]] endpoints, 81% in China, but most were not IoT devices β€” they were Chinese smartphones running the QLC Chain {{peer-to-peer|peer-to-peer}} crypto stack.', + text: "NETSCOUT's January 2019 scan found 388,344 publicly-reachable [[coap|CoAP]] endpoints, 81% in China, but most were not IoT devices β€” they were Chinese smartphones running the QLC Chain {{peer-to-peer|peer-to-peer}} crypto stack.", attribution: 'Author' }, { diff --git a/src/lib/data/book/parts/famous-outages.ts b/src/lib/data/book/parts/famous-outages.ts index fdfef07..4d30855 100644 --- a/src/lib/data/book/parts/famous-outages.ts +++ b/src/lib/data/book/parts/famous-outages.ts @@ -48,7 +48,7 @@ The fix was to install patched {{imp|IMP}} software that rejected sequence numbe }, { type: 'callout', - title: 'Postel\'s Law had limits', + title: "Postel's Law had limits", text: '**Be conservative in what you send, be liberal in what you accept.** A beautiful guideline β€” until "liberal" means accepting a malformed message and propagating it network-wide. The 1980 collapse forced the field to admit Postel\'s Law has an important exception: be **strict** in what you accept from anything that isn\'t under your operational control. The modern interpretation: be liberal with **format**, strict with **semantics**.' } ] @@ -66,7 +66,7 @@ The fix was to install patched {{imp|IMP}} software that rejected sequence numbe **Public post-mortems became the norm.** [[rfc:789|RFC 789]] established that engineering organisations {{mqtt-publish|publish}} detailed root-cause analyses of their incidents. The {{google|Google}} SRE book, the {{cloudflare|Cloudflare}} incident reports, the Facebook 2021 write-up β€” all descendants of this practice. -**Sequence-number arithmetic is paranoid by default.** Modern protocols reject any {{sequence-number|sequence number}} that is impossibly far in the past or future, instead of trusting wall-clock-style ordering. [[tcp|TCP]]\'s [[rfc:9293|PAWS]] (Protection Against Wrapped Sequences, [[rfc:7323|RFC 7323]]) is one example.` +**Sequence-number arithmetic is paranoid by default.** Modern protocols reject any {{sequence-number|sequence number}} that is impossibly far in the past or future, instead of trusting wall-clock-style ordering. [[tcp|TCP]]'s [[rfc:9293|PAWS]] (Protection Against Wrapped Sequences, [[rfc:7323|RFC 7323]]) is one example.` }, { type: 'image', @@ -89,7 +89,7 @@ The fix was to install patched {{imp|IMP}} software that rejected sequence numbe slots: [ { kind: 'pull-quote', - text: 'Most-specific wins, by definition. {{autonomous-system|AS}} 7007 didn\'t hijack anything on purpose β€” it simply announced everything as a /24, and the entire internet routed through a single underpowered Florida router.', + text: "Most-specific wins, by definition. {{autonomous-system|AS}} 7007 didn't hijack anything on purpose β€” it simply announced everything as a /24, and the entire internet routed through a single underpowered Florida router.", attribution: 'Author' }, { @@ -125,7 +125,7 @@ What made the recovery so painful was that there was no way to tell [[bgp|BGP]] title: 'Why It Took Twenty-Five Years to Fix', text: `{{rpki|RPKI}} was specified in 2008. It took until 2026 to cross **50% of advertised [[ip|IP]] space covered**. The reason is the structure of [[bgp|BGP]] deployment. -For {{rpki|RPKI}} to fix the {{autonomous-system|AS}} 7007 problem, two parties have to participate: the prefix-holder must {{mqtt-publish|publish}} a Route Origin Authorisation ({{roa|ROA}}), and the receiving router must enforce {{rov|Route Origin Validation}} ({{rov|ROV}}). For the first decade after specification, only a handful of large networks ran {{rov|ROV}}. Smaller operators pointed out β€” correctly β€” that running {{rov|ROV}} with low {{roa|ROA}} coverage means dropping legitimate routes from peers who haven\'t signed yet. So nobody enforced. Without enforcement, signing your prefixes had no upside. Classic chicken-and-egg. +For {{rpki|RPKI}} to fix the {{autonomous-system|AS}} 7007 problem, two parties have to participate: the prefix-holder must {{mqtt-publish|publish}} a Route Origin Authorisation ({{roa|ROA}}), and the receiving router must enforce {{rov|Route Origin Validation}} ({{rov|ROV}}). For the first decade after specification, only a handful of large networks ran {{rov|ROV}}. Smaller operators pointed out β€” correctly β€” that running {{rov|ROV}} with low {{roa|ROA}} coverage means dropping legitimate routes from peers who haven't signed yet. So nobody enforced. Without enforcement, signing your prefixes had no upside. Classic chicken-and-egg. What broke the deadlock was a series of high-profile incidents (2018 Amazon Route 53 / MyEtherWallet hijack, 2018 Iranian Telegram hijack, 2019 SafeHost / China Telecom leak) that made unsigned networks look negligent. By 2022, the major hyperscalers and tier-1s were enforcing. By 2026, [[frontier:rpki-rov-50-percent|over 50%]] of advertised [[ip|IP]] space was covered. {{aspa|ASPA}} β€” the {{autonomous-system|AS}}-path validation extension β€” is the next chapter.` }, @@ -171,7 +171,7 @@ Mitnick used this to land a forged connection from a host listed in Shimomura's { type: 'callout', title: 'rsh / rlogin trust was the multiplier', - text: '[[tcp|TCP]] sequence prediction by itself is not catastrophic β€” it just lets you forge a connection. The reason this attack worked is that Berkeley Unix\'s \`.rhosts\` mechanism trusted **the source {{ip-address|IP address}}** of an incoming connection as authentication. Forge the source [[ip|IP]], get the trust. [[ssh|SSH]] (which Tatu YlΓΆnen wrote in 1995, partly in response to incidents like this one) replaced \`.rhosts\` with cryptographic identity β€” even a perfectly forged [[tcp|TCP]] connection cannot impersonate someone without their {{private-key|private key}}.' + text: "[[tcp|TCP]] sequence prediction by itself is not catastrophic β€” it just lets you forge a connection. The reason this attack worked is that Berkeley Unix's `.rhosts` mechanism trusted **the source {{ip-address|IP address}}** of an incoming connection as authentication. Forge the source [[ip|IP]], get the trust. [[ssh|SSH]] (which Tatu YlΓΆnen wrote in 1995, partly in response to incidents like this one) replaced `.rhosts` with cryptographic identity β€” even a perfectly forged [[tcp|TCP]] connection cannot impersonate someone without their {{private-key|private key}}." }, { type: 'narrative', @@ -224,7 +224,7 @@ The technical legacy outlived the celebrity. **[[rfc:1948|RFC 1948]]** (Steve Be { type: 'narrative', title: 'A Domestic Block, A Global Outage', - text: `On 24 February 2008, the Pakistan Telecommunications Authority ordered domestic ISPs to block YouTube β€” the immediate cause was a video the government considered blasphemous. Pakistan Telecom ({{autonomous-system|AS}} 17557) implemented the block using the standard "Remotely Triggered Blackhole" (RTBH) technique: inject a more-specific [[bgp|BGP]] route for YouTube\'s prefix into their internal network, pointing it at a null interface. Any traffic destined for YouTube would be silently dropped at the Pakistan Telecom edge. + text: `On 24 February 2008, the Pakistan Telecommunications Authority ordered domestic ISPs to block YouTube β€” the immediate cause was a video the government considered blasphemous. Pakistan Telecom ({{autonomous-system|AS}} 17557) implemented the block using the standard "Remotely Triggered Blackhole" (RTBH) technique: inject a more-specific [[bgp|BGP]] route for YouTube's prefix into their internal network, pointing it at a null interface. Any traffic destined for YouTube would be silently dropped at the Pakistan Telecom edge. This is fine β€” **as long as you don't propagate the route outside your network**.` }, @@ -233,7 +233,7 @@ This is fine β€” **as long as you don't propagate the route outside your network title: 'The Leak', text: `Pakistan Telecom's upstream provider was PCCW Global ({{autonomous-system|AS}} 3491), a major Hong Kong-based {{transit|transit}}. PCCW Global was not filtering incoming [[bgp|BGP]] from Pakistan Telecom β€” they accepted the bogus, more-specific YouTube route and propagated it onward to every PCCW {{peer|peer}}. From there it went global. -Within three minutes of the original injection, the entire internet believed the best path to YouTube\'s prefix was through Pakistan Telecom. Every YouTube request anywhere on the planet was being null-routed by a router in Karachi. YouTube\'s authoritative [[dns|DNS]] continued to resolve correctly; the actual [[tcp|TCP]] connections just disappeared into a black hole. +Within three minutes of the original injection, the entire internet believed the best path to YouTube's prefix was through Pakistan Telecom. Every YouTube request anywhere on the planet was being null-routed by a router in Karachi. YouTube's authoritative [[dns|DNS]] continued to resolve correctly; the actual [[tcp|TCP]] connections just disappeared into a black hole. YouTube was offline globally for two hours. PCCW Global eventually identified the bogus route and applied filtering, after which [[bgp|BGP]] convergence took another 30 minutes to restore reachability.` }, @@ -252,9 +252,9 @@ YouTube was offline globally for two hours. PCCW Global eventually identified th { type: 'narrative', title: 'Why "Most Specific Wins" Is Both Genius and Curse', - text: `[[bgp|BGP]]\'s "most specific prefix wins" rule has a beautiful property: it lets traffic engineering work without coordination. If your origin announces a /16 and your {{cdn|CDN}} announces a /20 inside that block, every router automatically prefers the {{cdn|CDN}} β€” no negotiation needed. + text: `[[bgp|BGP]]'s "most specific prefix wins" rule has a beautiful property: it lets traffic engineering work without coordination. If your origin announces a /16 and your {{cdn|CDN}} announces a /20 inside that block, every router automatically prefers the {{cdn|CDN}} β€” no negotiation needed. -The same rule is what made Pakistan/YouTube possible. A /24 inside YouTube\'s /22 wins, regardless of who is announcing it. The combination of "most specific wins" + "no origin validation" + "global propagation" turned every upstream provider into a single point of failure for every downstream customer\'s prefix integrity. +The same rule is what made Pakistan/YouTube possible. A /24 inside YouTube's /22 wins, regardless of who is announcing it. The combination of "most specific wins" + "no origin validation" + "global propagation" turned every upstream provider into a single point of failure for every downstream customer's prefix integrity. This is the structural reason [[bgp|BGP]] needs cryptography to fix it, not just better operational hygiene. Hygiene catches typos; cryptography catches deliberate hijacks. {{rpki|RPKI}} provides the cryptography. {{aspa|ASPA}} (the {{autonomous-system|AS}}-path validation extension, in {{ietf|IETF}} draft) closes the route-leak hole that origin validation alone cannot fix β€” where {{autonomous-system|AS}} X **does** legitimately originate the prefix, but its upstream then leaks the route through an unintended path.` }, @@ -263,7 +263,7 @@ This is the structural reason [[bgp|BGP]] needs cryptography to fix it, not just src: 'https://upload.wikimedia.org/wikipedia/commons/thumb/b/bf/Arpanet_logical_map%2C_march_1977.png/500px-Arpanet_logical_map%2C_march_1977.png', alt: 'ARPANET logical map, March 1977 β€” sites in the US plus a node at London.', caption: - 'The {{arpanet|ARPANET}} in March 1977 β€” a network small enough that one Pakistan-Telecom-class misconfiguration would have been caught manually within minutes. By 2008 the global [[bgp|BGP]] {{routing-table|routing table}} had grown to ~250,000 prefixes, and Pakistan Telecom\'s null-route on a single /24 of YouTube space silently became the world\'s outage in **three minutes flat**. Scale changes what counts as a recoverable error.', + "The {{arpanet|ARPANET}} in March 1977 β€” a network small enough that one Pakistan-Telecom-class misconfiguration would have been caught manually within minutes. By 2008 the global [[bgp|BGP]] {{routing-table|routing table}} had grown to ~250,000 prefixes, and Pakistan Telecom's null-route on a single /24 of YouTube space silently became the world's outage in **three minutes flat**. Scale changes what counts as a recoverable error.", credit: 'Image: DARPA / public domain, via Wikimedia Commons' } ] @@ -275,7 +275,8 @@ This is the structural reason [[bgp|BGP]] needs cryptography to fix it, not just { id: 'china-telecom-2010', title: 'China Telecom 2010', - synopsis: '15% of the internet routed through a single {{autonomous-system|AS}} for 18 minutes.', + synopsis: + '15% of the internet routed through a single {{autonomous-system|AS}} for 18 minutes.', slots: [ { kind: 'prose', @@ -285,7 +286,7 @@ This is the structural reason [[bgp|BGP]] needs cryptography to fix it, not just title: 'Brief, Massive, Unexplained', text: `On 8 April 2010 at 15:54 {{utc-time|UTC}}, China Telecom ({{autonomous-system|AS}} 23724) announced [[bgp|BGP]] routes for approximately **37,000 prefixes** β€” about **15% of the global {{routing-table|routing table}}** β€” claiming to be the best path. For 18 minutes, traffic destined for U.S. military networks (.mil), several .gov domains, and major commercial sites (Dell, Yahoo, {{ibm|IBM}}, {{microsoft|Microsoft}}) was traversing China Telecom's network on its way to the legitimate destination. -The leak was caught by automated monitoring (BGPmon, {{ripe-ncc|RIPE}} RIS, RouteViews) within minutes. China Telecom\'s upstreams installed filters around 16:12 {{utc-time|UTC}}, and [[bgp|BGP]] convergence restored normal routing by 16:18.` +The leak was caught by automated monitoring (BGPmon, {{ripe-ncc|RIPE}} RIS, RouteViews) within minutes. China Telecom's upstreams installed filters around 16:12 {{utc-time|UTC}}, and [[bgp|BGP]] convergence restored normal routing by 16:18.` }, { type: 'narrative', @@ -356,9 +357,9 @@ The disclosure was coordinated across Red Hat, Canonical, SUSE, Debian, {{aws|AW { type: 'narrative', title: 'How a 23-Year-Old Option Survived Undetected', - text: `The {{sack|SACK}} option itself ([[rfc:2018|RFC 2018]], October 1996) had been working correctly for **23 years**. The bug was not in {{sack|SACK}}\'s logic; it was in a specific edge-case interaction with the **frags_per_skb** limit, increased in 2009 to support larger send buffers. + text: `The {{sack|SACK}} option itself ([[rfc:2018|RFC 2018]], October 1996) had been working correctly for **23 years**. The bug was not in {{sack|SACK}}'s logic; it was in a specific edge-case interaction with the **frags_per_skb** limit, increased in 2009 to support larger send buffers. -When {{sack|SACK}} indicated a large number of non-contiguous holes in the receive window, the kernel\'s logic for splitting the retransmit buffer into smaller skbs (socket buffers) miscalculated a 16-bit length field. The miscalculation overflowed, the kernel asserted, and the BUG_ON() panicked the system. +When {{sack|SACK}} indicated a large number of non-contiguous holes in the receive window, the kernel's logic for splitting the retransmit buffer into smaller skbs (socket buffers) miscalculated a 16-bit length field. The miscalculation overflowed, the kernel asserted, and the BUG_ON() panicked the system. The bug had been present in production code since 2009. It survived because: 1. The trigger required a specific combination of [[tcp|TCP]] options that no real client sent in normal traffic. @@ -366,7 +367,7 @@ The bug had been present in production code since 2009. It survived because: 3. Most performance benchmarks did not exercise the path. 4. {{sack|SACK}} was considered "battle-tested" β€” engineers focused new attention on newer code paths instead. -Looney found it by writing a fuzzer that combined {{sack|SACK}} with [[tcp|TCP]]\'s other options in unusual sequences. The same fuzzer found three additional related bugs ({{cve|CVE}}-2019-11478, 11479, 11479) that were patched in the same coordinated disclosure.` +Looney found it by writing a fuzzer that combined {{sack|SACK}} with [[tcp|TCP]]'s other options in unusual sequences. The same fuzzer found three additional related bugs ({{cve|CVE}}-2019-11478, 11479, 11479) that were patched in the same coordinated disclosure.` }, { type: 'callout', @@ -385,9 +386,9 @@ Looney found it by writing a fuzzer that combined {{sack|SACK}} with [[tcp|TCP]] title: 'What Changed After SACK Panic', text: `Three operational changes are now standard in production {{linux|Linux}} fleets. -**Continuous fuzzing of network code paths.** syzkaller runs against every {{linux|Linux}} kernel commit, generating millions of random syscall + packet sequences per day. Most CVEs in the kernel\'s [[tcp|TCP]]/[[ip|IP]] stack since 2019 have been found this way, not by humans. +**Continuous fuzzing of network code paths.** syzkaller runs against every {{linux|Linux}} kernel commit, generating millions of random syscall + packet sequences per day. Most CVEs in the kernel's [[tcp|TCP]]/[[ip|IP]] stack since 2019 have been found this way, not by humans. -**Faster {{cve|CVE}} response in distributed {{linux|Linux}} environments.** Pre-2019, large fleets often took weeks to roll out a kernel patch β€” full reboot rotations, slow validation cycles. {{sack|SACK}} Panic forced the industry to invest in **live patching** (Red Hat\'s kpatch, Canonical\'s Livepatch, SUSE\'s kGraft) that can apply security fixes to a running kernel without reboot. By 2026, hyperscalers routinely live-patch kernel CVEs across millions of {{hosts-bare|hosts}} within hours. +**Faster {{cve|CVE}} response in distributed {{linux|Linux}} environments.** Pre-2019, large fleets often took weeks to roll out a kernel patch β€” full reboot rotations, slow validation cycles. {{sack|SACK}} Panic forced the industry to invest in **live patching** (Red Hat's kpatch, Canonical's Livepatch, SUSE's kGraft) that can apply security fixes to a running kernel without reboot. By 2026, hyperscalers routinely live-patch kernel CVEs across millions of {{hosts-bare|hosts}} within hours. **Per-feature kill switches.** The {{sack|SACK}} Panic patch is gated behind a sysctl (\`net.ipv4.tcp_sack\`) so operators can disable {{sack|SACK}} entirely if a future bug surfaces β€” without waiting for a kernel {{bgp-update|update}}. Modern kernel networking is full of such switches: an emergency lever for every major optional feature.` }, @@ -396,8 +397,9 @@ Looney found it by writing a fuzzer that combined {{sack|SACK}} with [[tcp|TCP]] src: 'https://upload.wikimedia.org/wikipedia/commons/thumb/3/35/Tux.svg/250px-Tux.svg.png', alt: 'Tux β€” the Linux mascot, a chubby cartoon penguin.', caption: - '**Tux**, the {{linux|Linux}} mascot, drawn by Larry Ewing in 1996. Behind that cheerful penguin sits a [[tcp|TCP]] stack on every internet-facing {{linux|Linux}} server on Earth β€” and from 2009 to 2019 every one of them was a single crafted [[tcp|TCP]] packet away from \`kernel panic\`. The fix shipped 17 June 2019; the lesson β€” **code stability is not code correctness** β€” has reshaped {{linux|Linux}} kernel networking testing since.', - credit: 'Image: Larry Ewing / lewing@isc.tamu.edu, public domain, via Wikimedia Commons' + '**Tux**, the {{linux|Linux}} mascot, drawn by Larry Ewing in 1996. Behind that cheerful penguin sits a [[tcp|TCP]] stack on every internet-facing {{linux|Linux}} server on Earth β€” and from 2009 to 2019 every one of them was a single crafted [[tcp|TCP]] packet away from `kernel panic`. The fix shipped 17 June 2019; the lesson β€” **code stability is not code correctness** β€” has reshaped {{linux|Linux}} kernel networking testing since.', + credit: + 'Image: Larry Ewing / lewing@isc.tamu.edu, public domain, via Wikimedia Commons' } ] } @@ -423,16 +425,16 @@ Looney found it by writing a fuzzer that combined {{sack|SACK}} with [[tcp|TCP]] title: 'A Rule That Killed Its Own Delivery Mechanism', text: `On 30 August 2020, CenturyLink ({{autonomous-system|AS}} 209 β€” one of the largest tier-1 backbones in the U.S., now branded Lumen) propagated a [[bgp|BGP]] **Flowspec** rule across its global network. -Flowspec ([[rfc:5575|RFC 5575]], {{rfc-doc|RFC}} 8955) lets operators install {{firewall|firewall}}-like rules through [[bgp|BGP]] β€” useful for distributing DDoS mitigation rules across thousands of routers in seconds. The rule in question was supposed to filter traffic for one customer\'s DDoS protection. +Flowspec ([[rfc:5575|RFC 5575]], {{rfc-doc|RFC}} 8955) lets operators install {{firewall|firewall}}-like rules through [[bgp|BGP]] β€” useful for distributing DDoS mitigation rules across thousands of routers in seconds. The rule in question was supposed to filter traffic for one customer's DDoS protection. -The catastrophic mistake: the rule\'s match criteria included [[bgp|BGP]] control traffic itself. Routers received the rule, applied it, and immediately began dropping the [[bgp|BGP]] {{bgp-keepalive|keepalive}} packets carrying the next rule. [[bgp|BGP]] sessions timed out across the network. As sessions dropped, [[bgp|BGP]] withdrew every prefix learned through them. The network entered a cascading-failure mode.` +The catastrophic mistake: the rule's match criteria included [[bgp|BGP]] control traffic itself. Routers received the rule, applied it, and immediately began dropping the [[bgp|BGP]] {{bgp-keepalive|keepalive}} packets carrying the next rule. [[bgp|BGP]] sessions timed out across the network. As sessions dropped, [[bgp|BGP]] withdrew every prefix learned through them. The network entered a cascading-failure mode.` }, { type: 'narrative', title: 'Five Hours of Manual Recovery', text: `Once the bad rule had propagated, there was no automated way to retract it β€” the very mechanism for retracting Flowspec rules ([[bgp|BGP]]) was the mechanism the rule had broken. Every router needed to be touched manually, either via out-of-band management or by physically connecting a console. -Recovery took **five hours**. During that window, approximately **3.5% of all global internet traffic dropped** β€” a massive number for a single backbone. {{cloudflare|Cloudflare}}, Amazon, {{microsoft|Microsoft}}, and most of the U.S. tier-1 customers reported downtime. {{cloudflare|Cloudflare}}\'s detailed write-up the next day became required reading in [[bgp|BGP]] operations.` +Recovery took **five hours**. During that window, approximately **3.5% of all global internet traffic dropped** β€” a massive number for a single backbone. {{cloudflare|Cloudflare}}, Amazon, {{microsoft|Microsoft}}, and most of the U.S. tier-1 customers reported downtime. {{cloudflare|Cloudflare}}'s detailed write-up the next day became required reading in [[bgp|BGP]] operations.` }, { type: 'callout', @@ -450,16 +452,16 @@ Recovery took **five hours**. During that window, approximately **3.5% of all gl title: 'The Architectural Concern That Remains', text: `CenturyLink rolled out automated controls preventing self-blocking rules. The broader industry adopted similar guards. But the underlying architectural concern β€” **the same protocol distributes both data and the rules governing data** β€” has no clean fix. -[[bgp|BGP]] is the universal control plane for internet routing. Flowspec rides on [[bgp|BGP]] because that\'s what every router already speaks. The alternative β€” a separate out-of-band protocol for distributing filter rules β€” would require new infrastructure on every router on the internet. The economic friction is too high; nobody is going to deploy it. +[[bgp|BGP]] is the universal control plane for internet routing. Flowspec rides on [[bgp|BGP]] because that's what every router already speaks. The alternative β€” a separate out-of-band protocol for distributing filter rules β€” would require new infrastructure on every router on the internet. The economic friction is too high; nobody is going to deploy it. -So we live with the architectural fragility and add operational guards. Every modern router\'s Flowspec implementation now refuses to install rules that would drop [[bgp|BGP]]\'s own ports (179) or the matching {{peer|peer}} addresses. Each new generation of routers adds more such guards. The lesson is incremental rather than fundamental: when you build a control plane on top of itself, every change to the control plane needs to be reviewed for self-consistency β€” manually, before it ships.` +So we live with the architectural fragility and add operational guards. Every modern router's Flowspec implementation now refuses to install rules that would drop [[bgp|BGP]]'s own ports (179) or the matching {{peer|peer}} addresses. Each new generation of routers adds more such guards. The lesson is incremental rather than fundamental: when you build a control plane on top of itself, every change to the control plane needs to be reviewed for self-consistency β€” manually, before it ships.` }, { type: 'image', src: 'https://upload.wikimedia.org/wikipedia/commons/thumb/8/83/ARPANET_first_router.jpg/500px-ARPANET_first_router.jpg', alt: 'A BBN Interface Message Processor β€” the original ARPANET router, ancestor of every BGP-speaking device on the modern internet.', caption: - 'A {{bbn|BBN}} {{imp|Interface Message Processor}} β€” the original {{arpanet|ARPANET}} router. Every modern [[bgp|BGP]]-speaking router carries the same architectural DNA: a control plane that builds the {{routing-table|forwarding table}} from messages it receives over the *same wires* it eventually forwards user data over. CenturyLink\'s 2020 Flowspec self-block is the canonical example of how that elegant unification can blow up when a single rule disables its own delivery mechanism.', + "A {{bbn|BBN}} {{imp|Interface Message Processor}} β€” the original {{arpanet|ARPANET}} router. Every modern [[bgp|BGP]]-speaking router carries the same architectural DNA: a control plane that builds the {{routing-table|forwarding table}} from messages it receives over the *same wires* it eventually forwards user data over. CenturyLink's 2020 Flowspec self-block is the canonical example of how that elegant unification can blow up when a single rule disables its own delivery mechanism.", credit: 'Photo: Steve Jurvetson, CC BY 2.0, via Wikimedia Commons' } ] @@ -484,23 +486,23 @@ So we live with the architectural fragility and add operational guards. Every mo { type: 'narrative', title: 'A Routine Maintenance Command, Then Six Hours', - text: `On 4 October 2021 at 15:39 {{utc-time|UTC}}, a Facebook engineer ran a routine maintenance command on the backbone connecting Facebook's data centres. The command was supposed to assess capacity by temporarily withdrawing a single backbone link\'s [[bgp|BGP]] advertisements, then restoring them. + text: `On 4 October 2021 at 15:39 {{utc-time|UTC}}, a Facebook engineer ran a routine maintenance command on the backbone connecting Facebook's data centres. The command was supposed to assess capacity by temporarily withdrawing a single backbone link's [[bgp|BGP]] advertisements, then restoring them. -The command had a bug. It withdrew **all** of Facebook\'s [[bgp|BGP]] route advertisements globally β€” not just for the one link it was supposed to assess. Within minutes, every facebook.com, instagram.com, and whatsapp.com lookup returned NXDOMAIN. **3.5 billion users disconnected.** +The command had a bug. It withdrew **all** of Facebook's [[bgp|BGP]] route advertisements globally β€” not just for the one link it was supposed to assess. Within minutes, every facebook.com, instagram.com, and whatsapp.com lookup returned NXDOMAIN. **3.5 billion users disconnected.** That was the easy part of the cascade.` }, { type: 'narrative', title: 'The DNS Black Hole', - text: `Facebook\'s authoritative [[dns|DNS]] servers were inside the data centres that just lost their [[bgp|BGP]] advertisements. Resolvers around the world tried to query them β€” and got nothing back, because the [[ip|IP]] addresses no longer routed anywhere. + text: `Facebook's authoritative [[dns|DNS]] servers were inside the data centres that just lost their [[bgp|BGP]] advertisements. Resolvers around the world tried to query them β€” and got nothing back, because the [[ip|IP]] addresses no longer routed anywhere. -After a brief period of cached responses, every cached record expired (typical TTLs are minutes, not hours). [[dns|DNS]] resolution for Facebook\'s domains failed worldwide. **Without [[dns|DNS]]**, Facebook\'s internal systems β€” Workplace, Calendar, internal monitoring, [[oauth2|OAuth]], the company directory β€” all failed. Engineers could not reach their own infrastructure remotely. They could not even verify that the outage was [[bgp|BGP]]-related, because their monitoring tools couldn\'t resolve internal hostnames.` +After a brief period of cached responses, every cached record expired (typical TTLs are minutes, not hours). [[dns|DNS]] resolution for Facebook's domains failed worldwide. **Without [[dns|DNS]]**, Facebook's internal systems β€” Workplace, Calendar, internal monitoring, [[oauth2|OAuth]], the company directory β€” all failed. Engineers could not reach their own infrastructure remotely. They could not even verify that the outage was [[bgp|BGP]]-related, because their monitoring tools couldn't resolve internal hostnames.` }, { type: 'narrative', title: 'The Badge Readers', - text: `The next layer of cascade was the part that made the outage famous in the broader world. Facebook\'s **physical security infrastructure** β€” door badge readers at the data centres β€” depended on the same authentication system that had just disappeared. + text: `The next layer of cascade was the part that made the outage famous in the broader world. Facebook's **physical security infrastructure** β€” door badge readers at the data centres β€” depended on the same authentication system that had just disappeared. Engineers headed to the data centres physically. They could not enter the buildings. The badge system was offline. They had to be physically escorted in by on-site security staff who could manually override the locks. Then, once inside, they had to find the specific machines that needed manual intervention β€” and the data-centre wayfinding tools were also offline. @@ -522,7 +524,7 @@ The first [[bgp|BGP]] fix went in around 21:00 {{utc-time|UTC}}. Recovery took u title: 'What Changed After Facebook 2021', text: `Three structural changes rolled through the industry in the eighteen months after the outage. -**Out-of-band recovery for authoritative [[dns|DNS]].** Facebook (and others) moved to a model where authoritative [[dns|DNS]] for their critical domains is reachable through multiple independent network paths β€” including paths that do not depend on the company\'s own backbone. {{cloudflare|Cloudflare}} and {{aws|AWS}} Route 53 both saw enterprise growth as customers moved [[dns|DNS]] to "if our network is down, our [[dns|DNS]] is still up." +**Out-of-band recovery for authoritative [[dns|DNS]].** Facebook (and others) moved to a model where authoritative [[dns|DNS]] for their critical domains is reachable through multiple independent network paths β€” including paths that do not depend on the company's own backbone. {{cloudflare|Cloudflare}} and {{aws|AWS}} Route 53 both saw enterprise growth as customers moved [[dns|DNS]] to "if our network is down, our [[dns|DNS]] is still up." **Physical access systems on independent networks.** Badge readers, door locks, environmental controls, fire suppression β€” anything that needs to work during a network outage β€” now runs on dedicated, isolated networks at most hyperscalers. The lesson: physical security cannot depend on the network whose data centre it secures. @@ -545,7 +547,8 @@ The first [[bgp|BGP]] fix went in around 21:00 {{utc-time|UTC}}. Recovery took u { id: 'rogers-2022', title: 'Rogers 2022 β€” A Country Disconnected', - synopsis: 'Fifteen hours, half of Canada offline β€” one [[bgp|BGP]]/{{ospf-hello|OSPF}} redistribution mistake.', + synopsis: + 'Fifteen hours, half of Canada offline β€” one [[bgp|BGP]]/{{ospf-hello|OSPF}} redistribution mistake.', slots: [ { kind: 'pull-quote', @@ -558,29 +561,29 @@ The first [[bgp|BGP]] fix went in around 21:00 {{utc-time|UTC}}. Recovery took u { type: 'narrative', title: 'When the ISP Is the Country', - text: `On 8 July 2022 at 04:45 EDT, Rogers Communications β€” the largest {{isp|ISP}} and mobile carrier in Canada, serving over **11 million subscribers** β€” went down nationally. For 15 hours, Rogers customers had no internet, no mobile signal, no landline (Rogers also runs Canada\'s largest {{voip|VoIP}}-based home phone service through its Hi-Speed Internet bundles), no Interac debit transactions (Interac\'s national network runs over Rogers connectivity), and **no 911 service** in many regions. + text: `On 8 July 2022 at 04:45 EDT, Rogers Communications β€” the largest {{isp|ISP}} and mobile carrier in Canada, serving over **11 million subscribers** β€” went down nationally. For 15 hours, Rogers customers had no internet, no mobile signal, no landline (Rogers also runs Canada's largest {{voip|VoIP}}-based home phone service through its Hi-Speed Internet bundles), no Interac debit transactions (Interac's national network runs over Rogers connectivity), and **no 911 service** in many regions. -The trigger was a misconfiguration during a planned maintenance {{bgp-update|update}} to the Rogers [[ip|IP]]/MPLS core. A bad route policy caused control-plane {{cpu|CPU}} exhaustion across Rogers\' core routers β€” they spent so much {{cpu|CPU}} recomputing routes in response to the bad policy that they had no cycles left to actually forward traffic.` +The trigger was a misconfiguration during a planned maintenance {{bgp-update|update}} to the Rogers [[ip|IP]]/MPLS core. A bad route policy caused control-plane {{cpu|CPU}} exhaustion across Rogers' core routers β€” they spent so much {{cpu|CPU}} recomputing routes in response to the bad policy that they had no cycles left to actually forward traffic.` }, { type: 'narrative', title: 'A Country-Wide Cascade', - text: `The downstream effects revealed how deeply a single carrier\'s connectivity had been woven into Canadian infrastructure. + text: `The downstream effects revealed how deeply a single carrier's connectivity had been woven into Canadian infrastructure. -**Banking and payments**: Interac\'s e-Transfer service stopped working nationwide. Most debit-card transactions failed. Some ATMs went offline. Several major retailers had to close because they could not accept payment. +**Banking and payments**: Interac's e-Transfer service stopped working nationwide. Most debit-card transactions failed. Some ATMs went offline. Several major retailers had to close because they could not accept payment. **Healthcare**: Several hospital systems lost connectivity to Rogers-hosted services. Telehealth platforms that depended on Rogers {{voip|VoIP}} failed. -**Government services**: Service Canada\'s online portals were unreachable from Rogers networks. The Canada Border Services Agency reported delays at land crossings. +**Government services**: Service Canada's online portals were unreachable from Rogers networks. The Canada Border Services Agency reported delays at land crossings. -**Emergency services**: 911 calls failed in many areas. Some provinces issued public advisories telling residents to use neighbours\' phones, alternate networks, or visit fire stations directly. +**Emergency services**: 911 calls failed in many areas. Some provinces issued public advisories telling residents to use neighbours' phones, alternate networks, or visit fire stations directly. Recovery required Rogers engineers to log in to individual core routers (over out-of-band management, which thankfully was separate) and manually roll back the change. By 21:00 EDT, partial service was restored. Full service took until 14 July β€” six days of intermittent issues for some customers.` }, { type: 'callout', title: 'The deeper structural lesson', - text: 'When a single private company\'s outage takes down national emergency services, the company is no longer just a private business β€” it is **critical national infrastructure**. The {{crtc|CRTC}}\'s post-incident investigation forced Rogers to enter mandatory **reciprocal-roaming agreements** with Bell and Telus, so that future single-carrier outages would not strand emergency calls. Other countries (Australia, the UK, Germany) used the Rogers incident as a reference point for similar regulatory action.' + text: "When a single private company's outage takes down national emergency services, the company is no longer just a private business β€” it is **critical national infrastructure**. The {{crtc|CRTC}}'s post-incident investigation forced Rogers to enter mandatory **reciprocal-roaming agreements** with Bell and Telus, so that future single-carrier outages would not strand emergency calls. Other countries (Australia, the UK, Germany) used the Rogers incident as a reference point for similar regulatory action." } ] }, @@ -593,8 +596,8 @@ Recovery required Rogers engineers to log in to individual core routers (over ou title: 'The Regulatory Aftermath', text: `The {{crtc|CRTC}} (Canadian Radio-television and Telecommunications Commission) issued a formal decision on 22 March 2023 requiring all major Canadian carriers to: -1. Implement **reciprocal roaming for emergency calls** within six months β€” so that a phone unable to reach its own carrier can still complete 911 calls through any competing carrier\'s tower. -2. Submit **detailed network architecture and dependency reports** annually, including every system that depends on the carrier\'s network for life-safety functions. +1. Implement **reciprocal roaming for emergency calls** within six months β€” so that a phone unable to reach its own carrier can still complete 911 calls through any competing carrier's tower. +2. Submit **detailed network architecture and dependency reports** annually, including every system that depends on the carrier's network for life-safety functions. 3. Maintain **out-of-band management** independent of the production network for all core routing infrastructure. 4. Conduct **annual outage simulations** with the federal government, including coordinated emergency-services {{failover|failover}}. @@ -641,7 +644,7 @@ Approximately **125 million devices** became unreachable for **up to twelve hour Several states issued public advisories during the outage telling AT&T customers to: - Use [[wifi|Wi-Fi]] calling (which routes through the home internet rather than the cellular network) -- Switch to a different carrier\'s {{sim-usim|SIM}} if available +- Switch to a different carrier's {{sim-usim|SIM}} if available - Use landlines if accessible - Walk or drive to the nearest fire station, police station, or hospital @@ -650,7 +653,7 @@ The {{fcc|FCC}} opened a formal investigation under the 2018 911 Reliability Rul { type: 'callout', title: 'Same shape as Rogers 2022', - text: 'The shape of the AT&T failure mirrors [[outage:rogers-2022|Rogers 2022]] uncomfortably: a planned change, deployed simultaneously across the production fleet, with insufficient progressive-rollout controls. The lesson the industry should have internalised after Rogers β€” **never push a config change to the entire fleet at once** β€” had not propagated. AT&T\'s post-incident report committed to canary deployment for all core network changes within the year.' + text: "The shape of the AT&T failure mirrors [[outage:rogers-2022|Rogers 2022]] uncomfortably: a planned change, deployed simultaneously across the production fleet, with insufficient progressive-rollout controls. The lesson the industry should have internalised after Rogers β€” **never push a config change to the entire fleet at once** β€” had not propagated. AT&T's post-incident report committed to canary deployment for all core network changes within the year." } ] }, @@ -663,7 +666,7 @@ The {{fcc|FCC}} opened a formal investigation under the 2018 911 Reliability Rul title: 'The Canary-Deployment Maturity Gap', text: `The web/cloud industry adopted canary deployments more than a decade ago β€” every meaningful change rolls out to 0.1%, then 1%, then 10%, then 100% of traffic, with automatic rollback on failure indicators. The telecom industry has lagged. -Reasons for the lag are structural. Wireless networks have **strong global consistency requirements** that don\'t align cleanly with canary deployment β€” you can\'t have one cell tower running a different version of the radio access network protocol than the towers next to it without breaking handoff. Some configuration changes are necessarily global. Some changes are necessarily simultaneous (e.g., security updates that close a known vulnerability). +Reasons for the lag are structural. Wireless networks have **strong global consistency requirements** that don't align cleanly with canary deployment β€” you can't have one cell tower running a different version of the radio access network protocol than the towers next to it without breaking handoff. Some configuration changes are necessarily global. Some changes are necessarily simultaneous (e.g., security updates that close a known vulnerability). Post-AT&T-2024, the industry consensus is that **most changes can be canaried** β€” even in wireless cores β€” and the small number that genuinely cannot should receive correspondingly more pre-deployment review. The architectural debate, ongoing, is whether the same caution should apply to security patches that need to ship fast: a mass-deployment outage and an unpatched-{{cve|CVE}} outage are both bad in different ways, and the correct trade-off is not obvious.` }, diff --git a/src/lib/data/book/parts/frontier.ts b/src/lib/data/book/parts/frontier.ts index 437ab15..48388ef 100644 --- a/src/lib/data/book/parts/frontier.ts +++ b/src/lib/data/book/parts/frontier.ts @@ -19,7 +19,8 @@ export const frontier: BookPart = { { id: 'post-quantum', title: 'Post-Quantum TLS', - synopsis: '{{pq-ciphersuite|X25519MLKEM768}} default in iOS 26 and Chrome β€” the first deployed post-quantum [[tls|TLS]] {{handshake|handshake}} on the public web.', + synopsis: + '{{pq-ciphersuite|X25519MLKEM768}} default in iOS 26 and Chrome β€” the first deployed post-quantum [[tls|TLS]] {{handshake|handshake}} on the public web.', slots: [ { kind: 'pull-quote', @@ -48,7 +49,7 @@ Browser deployment moved fast. **Chrome 124 (April 2024)** made X25519Kyber768 d { type: 'callout', title: 'Apple iOS 26 cliff: <2% to 25% in 90 days', - text: '**{{apple|Apple}} iOS 26 / iPadOS 26 / macOS Tahoe 26 / visionOS 26 (September 2025)** turned {{pq-ciphersuite|X25519MLKEM768}} on by default for all [[tls|TLS]] 1.3 in Network.framework. Within **four days** the iOS post-quantum traffic share went from <2% to 11%. By December 2025 it was >25%. {{apple|Apple}}\'s scale plus the default-on shipping pattern is the fastest deployment of a new [[tls|TLS]] feature in the protocol\'s history.' + text: "**{{apple|Apple}} iOS 26 / iPadOS 26 / macOS Tahoe 26 / visionOS 26 (September 2025)** turned {{pq-ciphersuite|X25519MLKEM768}} on by default for all [[tls|TLS]] 1.3 in Network.framework. Within **four days** the iOS post-quantum traffic share went from <2% to 11%. By December 2025 it was >25%. {{apple|Apple}}'s scale plus the default-on shipping pattern is the fastest deployment of a new [[tls|TLS]] feature in the protocol's history." }, { type: 'narrative', @@ -88,7 +89,8 @@ The **47-day-cert cliff**: {{certificate-authority|CA}}/Browser Forum **Ballot S { id: 'l4s-everywhere', title: 'L4S Everywhere', - synopsis: '{{l4s|L4S}}: sub-millisecond queuing {{latency|latency}} for cooperating flows β€” Comcast launched in production January 2025.', + synopsis: + '{{l4s|L4S}}: sub-millisecond queuing {{latency|latency}} for cooperating flows β€” Comcast launched in production January 2025.', slots: [ { kind: 'pull-quote', @@ -137,7 +139,7 @@ The unresolved political fight is **{{l4s|L4S}}-vs-classic fairness**: Scalable src: 'https://upload.wikimedia.org/wikipedia/commons/thumb/0/09/Cable_Modem.JPG/500px-Cable_Modem.JPG', alt: 'A DOCSIS cable modem β€” the kind of last-mile device that ships L4S-capable AQM in 2024-2025.', caption: - 'A consumer **cable modem** β€” the bit of hardware Comcast turned into the world\'s first production **{{l4s|L4S}}** deployment in **January 2025** across six US metros (Atlanta, Chicago, Colorado Springs, Philadelphia, Rockville MD, San Francisco). {{docsis|DOCSIS}} 4.0 modems ship {{l4s|L4S}}-capable Dual-Queue {{aqm|AQM}}; {{apple|Apple}} iOS 17 / macOS Sonoma added {{l4s|L4S}} support in 2023. Sub-millisecond queuing delay at full link utilisation, finally, after 15 years of {{bufferbloat|bufferbloat}}.', + "A consumer **cable modem** β€” the bit of hardware Comcast turned into the world's first production **{{l4s|L4S}}** deployment in **January 2025** across six US metros (Atlanta, Chicago, Colorado Springs, Philadelphia, Rockville MD, San Francisco). {{docsis|DOCSIS}} 4.0 modems ship {{l4s|L4S}}-capable Dual-Queue {{aqm|AQM}}; {{apple|Apple}} iOS 17 / macOS Sonoma added {{l4s|L4S}} support in 2023. Sub-millisecond queuing delay at full link utilisation, finally, after 15 years of {{bufferbloat|bufferbloat}}.", credit: 'Photo: Wikimedia Commons / CC BY-SA' } ] @@ -152,7 +154,8 @@ The unresolved political fight is **{{l4s|L4S}}-vs-classic fairness**: Scalable { id: 'ipv6-mostly', title: 'IPv6-Mostly', - synopsis: 'On 28 March 2026, {{google|Google}}\'s [[ipv6|IPv6]] dashboard recorded 50.1% for the first time β€” and [[ip|IPv4]] crossed under.', + synopsis: + "On 28 March 2026, {{google|Google}}'s [[ipv6|IPv6]] dashboard recorded 50.1% for the first time β€” and [[ip|IPv4]] crossed under.", slots: [ { kind: 'pull-quote', @@ -204,7 +207,7 @@ The "everyone gets this wrong" detail: [[ipv6|IPv6]]'s mandatory-to-implement [[ src: 'https://upload.wikimedia.org/wikipedia/commons/thumb/d/d2/Internet_map_1024.jpg/500px-Internet_map_1024.jpg', alt: 'A 2005 visualisation of the global internet topology with each line a BGP peering relationship.', caption: - 'A snapshot of the global internet, each line a [[bgp|BGP]] {{peering|peering}} relationship. The 28-year migration of this graph to [[ipv6|IPv6]] addressing finally crossed **50.1%** of {{google|Google}}\'s measured user base on **28 March 2026**. The driver was not advocacy; it was *economics* β€” {{aws|AWS}}\'s **$0.005/{{ip-address|IP}}/hour charge from 1 February 2024** did more for v6 deployment in a year than two decades of standards work.', + "A snapshot of the global internet, each line a [[bgp|BGP]] {{peering|peering}} relationship. The 28-year migration of this graph to [[ipv6|IPv6]] addressing finally crossed **50.1%** of {{google|Google}}'s measured user base on **28 March 2026**. The driver was not advocacy; it was *economics* β€” {{aws|AWS}}'s **$0.005/{{ip-address|IP}}/hour charge from 1 February 2024** did more for v6 deployment in a year than two decades of standards work.", credit: 'Image: The Opte Project / Wikimedia Commons, CC BY 2.5' } ] @@ -218,7 +221,8 @@ The "everyone gets this wrong" detail: [[ipv6|IPv6]]'s mandatory-to-implement [[ { id: 'rpki-aspa', title: 'RPKI + ASPA', - synopsis: '{{rpki|Cryptographic BGP}}, finally arriving β€” 50% of [[ip|IPv4]] covered May 2024.', + synopsis: + '{{rpki|Cryptographic BGP}}, finally arriving β€” 50% of [[ip|IPv4]] covered May 2024.', slots: [ { kind: 'pull-quote', @@ -259,7 +263,7 @@ The "everyone gets this wrong" detail: [[ipv6|IPv6]]'s mandatory-to-implement [[ }, { type: 'narrative', - title: 'When RPKI Backfires, And When It Doesn\'t', + title: "When RPKI Backfires, And When It Doesn't", text: `**Orange EspaΓ±a, 3 January 2024**: a threat actor "Snow" used infostealer-harvested credentials to log in to Orange Spain's {{ripe-ncc|RIPE NCC}} account and edited ROAs to make legitimate prefixes {{rpki|RPKI}}-invalid β€” the first major outage caused by **{{rpki|RPKI}} being too strict against an attacker-modified {{roa|ROA}} set**. Lesson: enforce 2FA on RIR portals. The vulnerability is not in {{rpki|RPKI}}; it is in the human-facing authentication surface around {{rpki|RPKI}}. **{{cloudflare|Cloudflare}} 1.1.1.1 hijack (27 June 2024)**: Brazilian {{isp|ISP}} Eletronet (AS267613) announced **1.1.1.1/32**. {{cloudflare|Cloudflare}} had a valid /24 {{roa|ROA}}, but ROAs cover up to maxLength /24, so a /32 announcement is not {{rpki|RPKI}}-invalid. Tier-1 {{peer|PEER}} 1 (AS1031) accepted and propagated. **300 networks in 70 countries lost 1.1.1.1.** The lesson: maxLength matters; sloppy {{roa|ROA}} configuration creates loopholes {{aspa|ASPA}} cannot close. @@ -287,7 +291,8 @@ The regulatory layer is moving too. **The {{fcc|FCC}} issued a Notice of Propose { id: 'ultra-ethernet', title: 'Ultra Ethernet', - synopsis: 'Replacing RoCEv2 in {{ai|AI}} training fabrics β€” [[ethernet|Ultra Ethernet]] Specification 1.0 published 11 June 2025.', + synopsis: + 'Replacing RoCEv2 in {{ai|AI}} training fabrics β€” [[ethernet|Ultra Ethernet]] Specification 1.0 published 11 June 2025.', slots: [ { kind: 'pull-quote', @@ -351,7 +356,8 @@ The commercial scale: **[[ethernet|Ethernet]] switching market exceeded $30B in { id: 'wifi-7-and-8', title: 'Wi-Fi 7 and 8', - synopsis: '[[wifi|Wi-Fi]] 7\'s 320 MHz, then [[wifi|Wi-Fi]] 8\'s 25% better {{tail-latency|tail latency}} target β€” and the politics of 6 GHz.', + synopsis: + "[[wifi|Wi-Fi]] 7's 320 MHz, then [[wifi|Wi-Fi]] 8's 25% better {{tail-latency|tail latency}} target β€” and the politics of 6 GHz.", slots: [ { kind: 'pull-quote', diff --git a/src/lib/data/book/parts/how-to-learn-more.ts b/src/lib/data/book/parts/how-to-learn-more.ts index d00cb1e..48564f0 100644 --- a/src/lib/data/book/parts/how-to-learn-more.ts +++ b/src/lib/data/book/parts/how-to-learn-more.ts @@ -18,7 +18,8 @@ export const howToLearnMore: BookPart = { { id: 'rfcs-to-read', title: 'RFCs Worth Reading', - synopsis: 'A guided tour with section pointers β€” the documents that pay back the time investment.', + synopsis: + 'A guided tour with section pointers β€” the documents that pay back the time investment.', slots: [ { kind: 'prose', @@ -102,7 +103,8 @@ For specialised areas: **Olivier Bonaventure, "Computer Networking: Principles, { id: 'courses', title: 'Courses', - synopsis: 'Stanford {{cs144-course|CS144}} (build a [[tcp|TCP]] stack), {{mit|MIT}} 6.829, Berkeley CS168.', + synopsis: + 'Stanford {{cs144-course|CS144}} (build a [[tcp|TCP]] stack), {{mit|MIT}} 6.829, Berkeley CS168.', slots: [ { kind: 'prose', @@ -137,7 +139,8 @@ For a self-paced path: read **{{rfc-doc|RFC}} 1180** (28 pages), then take **{{c { id: 'blogs', title: 'Blogs', - synopsis: '{{cloudflare|Cloudflare}}, {{meta|Meta}} Engineering, {{apnic|APNIC}} Labs, ipSpace.net.', + synopsis: + '{{cloudflare|Cloudflare}}, {{meta|Meta}} Engineering, {{apnic|APNIC}} Labs, ipSpace.net.', slots: [ { kind: 'prose', diff --git a/src/lib/data/book/parts/layer-2-3.ts b/src/lib/data/book/parts/layer-2-3.ts index e41f33c..2f3e302 100644 --- a/src/lib/data/book/parts/layer-2-3.ts +++ b/src/lib/data/book/parts/layer-2-3.ts @@ -20,7 +20,8 @@ export const layer23: BookPart = { { id: 'ethernet', title: 'Ethernet', - synopsis: 'From {{xerox-parc|PARC}} coaxial cable to [[ethernet|800 GbE]] in {{ai|AI}} training fabrics.', + synopsis: + 'From {{xerox-parc|PARC}} coaxial cable to [[ethernet|800 GbE]] in {{ai|AI}} training fabrics.', slots: [ { kind: 'pull-quote', @@ -87,7 +88,8 @@ The **[[frontier:ultra-ethernet-1-0|Ultra Ethernet Consortium]] Specification 1. { id: 'wifi', title: 'Wi-Fi', - synopsis: '{{csma-ca|CSMA/CA}} on the airwaves; from {{fcc|FCC}} Docket 81-413 to [[wifi|Wi-Fi]] 8.', + synopsis: + '{{csma-ca|CSMA/CA}} on the airwaves; from {{fcc|FCC}} Docket 81-413 to [[wifi|Wi-Fi]] 8.', slots: [ { kind: 'pull-quote', @@ -153,7 +155,8 @@ The breach that changed everything: **TJX (disclosed 17 January 2007)** β€” atta { id: 'arp-and-ndp', title: 'ARP and NDP', - synopsis: 'How a {{packet|packet}} finds the next physical hop β€” [[arp|STD 37]] has not been obsoleted in 44 years.', + synopsis: + 'How a {{packet|packet}} finds the next physical hop β€” [[arp|STD 37]] has not been obsoleted in 44 years.', slots: [ { kind: 'prose', @@ -203,7 +206,7 @@ Two {{ndp|NDP}} CVEs deserve naming. src: 'https://upload.wikimedia.org/wikipedia/commons/thumb/9/90/Ethernet_Switch_%28Front_View%29.jpg/500px-Ethernet_Switch_%28Front_View%29.jpg', alt: 'A rack-mounted Ethernet switch with rows of RJ-45 ports.', caption: - 'An [[ethernet|Ethernet]] switch β€” the physical thing that builds and maintains a {{mac-address|MAC}}-address-to-port table for every device plugged in. Every entry in that table is a successful [[arp|ARP]] request: *who has 192.0.2.5? I do, at ab:cd:ef:01:02:03.* The switch caches; the host caches; the entire seam between the [[ip|IP]] layer\'s 32-bit addresses and the [[ethernet|Ethernet]] layer\'s 48-bit ones lives in those two caches.', + "An [[ethernet|Ethernet]] switch β€” the physical thing that builds and maintains a {{mac-address|MAC}}-address-to-port table for every device plugged in. Every entry in that table is a successful [[arp|ARP]] request: *who has 192.0.2.5? I do, at ab:cd:ef:01:02:03.* The switch caches; the host caches; the entire seam between the [[ip|IP]] layer's 32-bit addresses and the [[ethernet|Ethernet]] layer's 48-bit ones lives in those two caches.", credit: 'Photo: Wikimedia Commons / CC BY-SA' } ] @@ -317,7 +320,7 @@ It then took **twenty-eight years** to reach 50% adoption. The reason is not tec { type: 'narrative', title: 'The 50.1% Crossing β€” And Why It Inflected', - text: `**On 28 March 2026, {{google|Google}}\'s [[ipv6|IPv6]] dashboard recorded 50.1% for the first time** β€” [[ipv6|IPv6]] briefly surpassed [[ip|IPv4]] in {{google|Google}}'s measured user base. {{apnic|APNIC}} Labs and {{cloudflare|Cloudflare}} Radar still place global [[ipv6|IPv6]] capability in the **40-43%** range; the 50% number is a {{google|Google}}-specific snapshot. But it is a milestone the community has been waiting for since 1995. + text: `**On 28 March 2026, {{google|Google}}'s [[ipv6|IPv6]] dashboard recorded 50.1% for the first time** β€” [[ipv6|IPv6]] briefly surpassed [[ip|IPv4]] in {{google|Google}}'s measured user base. {{apnic|APNIC}} Labs and {{cloudflare|Cloudflare}} Radar still place global [[ipv6|IPv6]] capability in the **40-43%** range; the 50% number is a {{google|Google}}-specific snapshot. But it is a milestone the community has been waiting for since 1995. Adoption inflected when **mobile carriers** went [[ipv6|IPv6]]-mostly for cellular subscribers. **T-Mobile US** moved its mobile core to [[ipv6|IPv6]]-only with {{four-six-four-xlat|464XLAT}} (Cameron Byrne, NANOG 61, 2014) β€” the production case study that defined the pattern. **Reliance Jio (India)** launched [[ipv6|IPv6]]-first in 2016 β€” >237M [[ipv6|IPv6]] users by 2017 β€” single biggest reason India's [[ipv6|IPv6]] share now runs 67-80%. **{{meta|Meta}}** runs >99% of internal datacenter traffic over [[ipv6|IPv6]]; entire new clusters are [[ipv6|IPv6]]-only. {{meta|Meta}} says **internal [[ipv6|IPv6]] is 10-15% faster than [[ip|IPv4]]** (and on one carrier mobile measurement, 40% faster). @@ -343,7 +346,7 @@ The 2024 {{ietf|IETF}} backlog tells the story of where [[ipv6|IPv6]] work is ha src: 'https://upload.wikimedia.org/wikipedia/commons/thumb/7/70/Ipv6_address_leading_zeros.svg/500px-Ipv6_address_leading_zeros.svg.png', alt: 'IPv6 address structure showing the eight 16-bit groups and the double-colon zero-compression rule.', caption: - 'An [[ipv6|IPv6]] address β€” **128 bits**, written as eight colon-separated 16-bit groups, with one run of zeros collapsed to `::`. The field grew from [[ip|IPv4]]\'s 32 bits to enough that every grain of sand on Earth could have its own {{subnet|subnet}}. On 28 March 2026 {{google|Google}}\'s [[ipv6|IPv6]] dashboard crossed **50.1%** for the first time β€” 28 years after [[rfc:2460|RFC 2460]] was published.', + "An [[ipv6|IPv6]] address β€” **128 bits**, written as eight colon-separated 16-bit groups, with one run of zeros collapsed to `::`. The field grew from [[ip|IPv4]]'s 32 bits to enough that every grain of sand on Earth could have its own {{subnet|subnet}}. On 28 March 2026 {{google|Google}}'s [[ipv6|IPv6]] dashboard crossed **50.1%** for the first time β€” 28 years after [[rfc:2460|RFC 2460]] was published.", credit: 'Image: Wikimedia Commons / CC BY-SA 4.0' } ] @@ -371,7 +374,7 @@ The 2024 {{ietf|IETF}} backlog tells the story of where [[ipv6|IPv6]] work is ha sections: [ { type: 'narrative', - title: 'Mike Muuss\'s One-Night Tool', + title: "Mike Muuss's One-Night Tool", text: `[[icmp|ICMP]] ([[rfc:792|RFC 792]], September 1981) is the protocol that lets the network tell you something is wrong without opening a connection. When a router drops your packet because the **{{ttl|TTL}}** hit zero, it sends an [[icmp|ICMP]] **{{time-exceeded|Time Exceeded}}** back to you β€” the mechanism that **{{traceroute|traceroute}}** exploits to map every hop along a path. When a destination is unreachable, you get **Destination Unreachable**. When a router has too small an {{mtu|MTU}} for your packet and the **Don't Fragment** bit is set, it sends **{{fragmentation|Fragmentation}} Needed**, which is what **{{path-mtu-discovery|Path MTU Discovery}}** depends on. The most famous [[icmp|ICMP]] message is **{{echo-request|Echo Request}} / {{echo-reply|Echo Reply}}** β€” what **{{ping|ping}}** sends. **Mike Muuss** wrote {{ping|ping}} at BRL Aberdeen **in December 1983 in a single night** after hearing Dave Mills describe Fuzzball {{latency|latency}}-timing experiments. He had to write the kernel raw-[[icmp|ICMP]] socket support too because it didn't exist. *"Had everything working well before sunrise."* @@ -428,7 +431,7 @@ The most famous [[icmp|ICMP]] message is **{{echo-request|Echo Request}} / {{ech slots: [ { kind: 'pull-quote', - text: '[[bgp|BGP]] doesn\'t have a real authentication story for 30+ years. The 16-byte all-ones Marker field at the start of every [[bgp|BGP]] message was originally a placeholder for an authentication digest β€” now vestigial.', + text: "[[bgp|BGP]] doesn't have a real authentication story for 30+ years. The 16-byte all-ones Marker field at the start of every [[bgp|BGP]] message was originally a placeholder for an authentication digest β€” now vestigial.", attribution: 'Author' }, { @@ -483,9 +486,9 @@ That sketch became [[rfc:4271|BGP-1]] ([[rfc:1105|RFC 1105]], June 1989), then [ { type: 'image', src: 'https://upload.wikimedia.org/wikipedia/commons/thumb/b/bf/Arpanet_logical_map%2C_march_1977.png/500px-Arpanet_logical_map%2C_march_1977.png', - alt: 'ARPANET logical map, March 1977 β€” predecessor topology to today\'s BGP-routed internet.', + alt: "ARPANET logical map, March 1977 β€” predecessor topology to today's BGP-routed internet.", caption: - 'The {{arpanet|ARPANET}} logical map, March 1977 β€” every node fits on a single sheet of paper. Today\'s [[bgp|BGP]] global {{routing-table|routing table}} has crossed **a million prefixes**, advertised by ~46,800 {{autonomous-system|ASes}}. [[pioneer:yakov-rekhter|Yakov Rekhter]] and Kirk Lougheed sketched the *Two-Napkin Protocol* in 1989 β€” three handwritten sheets that became the protocol every {{transit|transit}} provider on Earth still speaks.', + "The {{arpanet|ARPANET}} logical map, March 1977 β€” every node fits on a single sheet of paper. Today's [[bgp|BGP]] global {{routing-table|routing table}} has crossed **a million prefixes**, advertised by ~46,800 {{autonomous-system|ASes}}. [[pioneer:yakov-rekhter|Yakov Rekhter]] and Kirk Lougheed sketched the *Two-Napkin Protocol* in 1989 β€” three handwritten sheets that became the protocol every {{transit|transit}} provider on Earth still speaks.", credit: 'Image: DARPA / public domain, via Wikimedia Commons' } ] @@ -504,7 +507,8 @@ That sketch became [[rfc:4271|BGP-1]] ([[rfc:1105|RFC 1105]], June 1989), then [ { id: 'dns', title: 'DNS', - synopsis: "[[dns|The naming layer]] every other protocol depends on β€” designed by [[pioneer:paul-mockapetris|Paul Mockapetris]] in 1983.", + synopsis: + '[[dns|The naming layer]] every other protocol depends on β€” designed by [[pioneer:paul-mockapetris|Paul Mockapetris]] in 1983.', slots: [ { kind: 'pull-quote', @@ -526,12 +530,12 @@ The first six TLDs were **\`.edu, .gov, .com, .mil, .org, .net\`**, with **\`.in { type: 'callout', title: '.onion is a special-use carve-out', - text: '**{{iana|IANA}} reserved \`.onion\` as a Special-Use Domain Name ([[rfc:7686|RFC 7686]], 2015) β€” MUST NOT be looked up in public [[dns|DNS]].** A rare carve-out outside {{icann|ICANN}}\'s namespace, granted because the Tor protocol uses .onion as an internal addressing scheme rather than a public naming hierarchy. The reservation prevents accidental [[dns|DNS]] leakage of Tor traffic.' + text: "**{{iana|IANA}} reserved `.onion` as a Special-Use Domain Name ([[rfc:7686|RFC 7686]], 2015) β€” MUST NOT be looked up in public [[dns|DNS]].** A rare carve-out outside {{icann|ICANN}}'s namespace, granted because the Tor protocol uses .onion as an internal addressing scheme rather than a public naming hierarchy. The reservation prevents accidental [[dns|DNS]] leakage of Tor traffic." }, { type: 'narrative', title: 'The Kaminsky Moment, And Modern DNSSEC', - text: `**Dan Kaminsky\'s {{cve|CVE}}-2008-1447 (July 2008)** turned every {{recursive-resolver|recursive resolver}} in the world into a cache-poisoning target by abusing in-bailiwick referrals + the small (16-bit) [[dns|DNS]] transaction {{id-identifier|ID}}. The disclosure was coordinated across all major [[dns|DNS]] vendors; patches added **source-port randomisation** as the immediate mitigation. The deeper fix is **{{dnssec|DNSSEC}}**, which has been deploying glacially. + text: `**Dan Kaminsky's {{cve|CVE}}-2008-1447 (July 2008)** turned every {{recursive-resolver|recursive resolver}} in the world into a cache-poisoning target by abusing in-bailiwick referrals + the small (16-bit) [[dns|DNS]] transaction {{id-identifier|ID}}. The disclosure was coordinated across all major [[dns|DNS]] vendors; patches added **source-port randomisation** as the immediate mitigation. The deeper fix is **{{dnssec|DNSSEC}}**, which has been deploying glacially. **KeyTrap ({{cve|CVE}}-2023-50387, February 2024)**: ATHENE researchers (Heftrig, Schulmann, Vogel, Waidner) disclosed inherent {{dnssec|DNSSEC}} validation complexity attacks β€” CVSS 7.5. BIND, Unbound, PowerDNS, Knot all patched, but the underlying {{dnssec|DNSSEC}} RFCs themselves are the issue. {{dnssec|DNSSEC}} is conceptually right and operationally fragile. diff --git a/src/lib/data/book/parts/patterns-failures.ts b/src/lib/data/book/parts/patterns-failures.ts index b59b946..5ecf1a1 100644 --- a/src/lib/data/book/parts/patterns-failures.ts +++ b/src/lib/data/book/parts/patterns-failures.ts @@ -77,7 +77,7 @@ Modern protocols inherit the same idea. [[quic|QUIC]] has per-stream and per-con src: 'https://upload.wikimedia.org/wikipedia/commons/thumb/7/71/TCP_Three-Way_Handshake.svg/500px-TCP_Three-Way_Handshake.svg.png', alt: 'TCP three-way handshake β€” SYN, SYN-ACK, ACK between client and server.', caption: - 'The canonical **{{handshake|handshake}}**: [[tcp|TCP]]\'s **{{syn-cookies|SYN}} β†’ {{syn-ack|SYN-ACK}} β†’ {{ack|ACK}}** dance from [[rfc:9293|RFC 793]] in 1981. Every other {{handshake|handshake}} in this book β€” [[tls|TLS]] {{client-hello|ClientHello}}/{{server-hello|ServerHello}}/Finished, [[ssh|SSH]] KEX, [[mqtt|MQTT]] {{mqtt-connect|CONNECT}}/CONNACK, [[sctp|SCTP]]\'s four-way {{cookie|Cookie}} {{exchange|exchange}} β€” is a variation on this shape. Recognise the pattern once; recognise it in every other protocol you ever read.', + "The canonical **{{handshake|handshake}}**: [[tcp|TCP]]'s **{{syn-cookies|SYN}} β†’ {{syn-ack|SYN-ACK}} β†’ {{ack|ACK}}** dance from [[rfc:9293|RFC 793]] in 1981. Every other {{handshake|handshake}} in this book β€” [[tls|TLS]] {{client-hello|ClientHello}}/{{server-hello|ServerHello}}/Finished, [[ssh|SSH]] KEX, [[mqtt|MQTT]] {{mqtt-connect|CONNECT}}/CONNACK, [[sctp|SCTP]]'s four-way {{cookie|Cookie}} {{exchange|exchange}} β€” is a variation on this shape. Recognise the pattern once; recognise it in every other protocol you ever read.", credit: 'Image: Wikimedia Commons / public domain' } ] @@ -221,7 +221,7 @@ The arc: react to loss β†’ react to delay β†’ model the network β†’ use explicit { type: 'callout', title: 'The unsolved problem: heterogeneous fairness', - text: 'Every congestion-control algorithm is fair to itself. Mix {{bbr|BBR}} with {{cubic|CUBIC}} on a shared bottleneck and {{bbr|BBR}} takes the lion\'s share. Mix {{l4s|L4S}} with classic flows in the wrong queue and {{l4s|L4S}} starves. Each new algorithm has had to fight not just for performance but for **coexistence** with the deployed base β€” a constraint that consumes most of the engineering effort. {{bbrv3|BBRv3}} spent two years on coexistence work before it was production-ready.' + text: "Every congestion-control algorithm is fair to itself. Mix {{bbr|BBR}} with {{cubic|CUBIC}} on a shared bottleneck and {{bbr|BBR}} takes the lion's share. Mix {{l4s|L4S}} with classic flows in the wrong queue and {{l4s|L4S}} starves. Each new algorithm has had to fight not just for performance but for **coexistence** with the deployed base β€” a constraint that consumes most of the engineering effort. {{bbrv3|BBRv3}} spent two years on coexistence work before it was production-ready." }, { type: 'image', diff --git a/src/lib/data/book/parts/realtime-av.ts b/src/lib/data/book/parts/realtime-av.ts index d2c09a0..da44d9f 100644 --- a/src/lib/data/book/parts/realtime-av.ts +++ b/src/lib/data/book/parts/realtime-av.ts @@ -74,7 +74,7 @@ Active 2025-2026 work in the {{ietf|IETF}} AVTCORE WG: **{{rfc-doc|RFC}} 9628 (2 src: 'https://upload.wikimedia.org/wikipedia/commons/thumb/6/6d/Polycom_VSX_7000_with_2_video_conferencing_screens.JPG/500px-Polycom_VSX_7000_with_2_video_conferencing_screens.JPG', alt: 'A Polycom VSX 7000 video-conferencing system with two screens.', caption: - 'A **Polycom VSX 7000** video-conferencing system β€” the early-2000s enterprise hardware whose audio and video both rode [[rtp|RTP]] under the hood. From the 1992 MBone audio-cast that produced [[rtp|RTP]]\'s wire format to today\'s ~2.5M-concurrent Discord voice fleet, the same {{sequence-number|Sequence Number}} + Timestamp + {{payload|Payload}} Type fields have carried voice and video across every generation of conferencing hardware.', + "A **Polycom VSX 7000** video-conferencing system β€” the early-2000s enterprise hardware whose audio and video both rode [[rtp|RTP]] under the hood. From the 1992 MBone audio-cast that produced [[rtp|RTP]]'s wire format to today's ~2.5M-concurrent Discord voice fleet, the same {{sequence-number|Sequence Number}} + Timestamp + {{payload|Payload}} Type fields have carried voice and video across every generation of conferencing hardware.", credit: 'Photo: Wikimedia Commons / CC BY-SA' } ] @@ -90,7 +90,8 @@ Active 2025-2026 work in the {{ietf|IETF}} AVTCORE WG: **{{rfc-doc|RFC}} 9628 (2 { id: 'webrtc', title: 'WebRTC', - synopsis: '{{peer-to-peer|Peer-to-peer}} in the browser, {{ice|ICE}}/{{stun|STUN}}/{{turn|TURN}}, {{dtls|DTLS}}, {{srtp|SRTP}} β€” and the only way for a browser to send a [[udp|UDP]] packet.', + synopsis: + '{{peer-to-peer|Peer-to-peer}} in the browser, {{ice|ICE}}/{{stun|STUN}}/{{turn|TURN}}, {{dtls|DTLS}}, {{srtp|SRTP}} β€” and the only way for a browser to send a [[udp|UDP]] packet.', slots: [ { kind: 'pull-quote', @@ -146,7 +147,7 @@ Plan B [[sdp|SDP]] is fully gone now: deprecation-warned in Chrome M89 (Feb 2021 src: 'https://upload.wikimedia.org/wikipedia/commons/thumb/2/23/Video_Conference_Using_Laptop.jpg/500px-Video_Conference_Using_Laptop.jpg', alt: 'A laptop with a video conferencing application showing multiple participants.', caption: - 'A laptop video call β€” what the [[webrtc|WebRTC]] stack actually produces in the user\'s seat. Underneath: a {{ble|BLE}}-discovered camera, {{ice-candidate|ICE candidate}} gathering, a {{dtls|DTLS}}-keyed {{srtp|SRTP}} flow over [[udp|UDP]], NetEQ in the audio path, libwebrtc compiled into the browser. **1.21 million lines of code** in libwebrtc β€” three times the size of the Space Shuttle\'s onboard software, and it boots in under a second.', + "A laptop video call β€” what the [[webrtc|WebRTC]] stack actually produces in the user's seat. Underneath: a {{ble|BLE}}-discovered camera, {{ice-candidate|ICE candidate}} gathering, a {{dtls|DTLS}}-keyed {{srtp|SRTP}} flow over [[udp|UDP]], NetEQ in the audio path, libwebrtc compiled into the browser. **1.21 million lines of code** in libwebrtc β€” three times the size of the Space Shuttle's onboard software, and it boots in under a second.", credit: 'Photo: Wikimedia Commons / CC BY-SA' } ] @@ -160,7 +161,8 @@ Plan B [[sdp|SDP]] is fully gone now: deprecation-warned in Chrome M89 (Feb 2021 { id: 'sip-and-sdp', title: 'SIP and SDP', - synopsis: '[[pioneer:henning-schulzrinne|Henning Schulzrinne]] wrote three protocols ([[sip|SIP]], [[sdp|SDP]], [[rtp|RTP]]) that carry the world\'s phone calls.', + synopsis: + "[[pioneer:henning-schulzrinne|Henning Schulzrinne]] wrote three protocols ([[sip|SIP]], [[sdp|SDP]], [[rtp|RTP]]) that carry the world's phone calls.", slots: [ { kind: 'pull-quote', @@ -189,7 +191,7 @@ Twenty-eight years in, the protocol-version line is still \`v=0\`. The [[sdp|SDP { type: 'callout', title: 'The 911 outages keep happening', - text: 'The **AT&T 22 February 2024 outage** disconnected 125 million devices and blocked ~25,000 911 calls β€” caused by a single misconfigured network element during expansion, surfacing as {{ims|IMS}}/[[sip|SIP]] registration failures. The **CenturyLink December 2018 911 outage** lost 911 service for 7.4 million Washington residents for 49 hours; 24,000 calls failed; Washington {{utc-time|UTC}} fined them $7.2 M. **{{volte|VoLTE}}/{{vonr|VoNR}} is the world\'s largest [[sip|SIP]] deployment** β€” {{gsma|GSMA}} reports 310+ {{volte|VoLTE}} operators in 140+ countries and 45+ commercial {{vonr|VoNR}} networks by 2025 β€” and the failure modes ripple straight into emergency services.' + text: "The **AT&T 22 February 2024 outage** disconnected 125 million devices and blocked ~25,000 911 calls β€” caused by a single misconfigured network element during expansion, surfacing as {{ims|IMS}}/[[sip|SIP]] registration failures. The **CenturyLink December 2018 911 outage** lost 911 service for 7.4 million Washington residents for 49 hours; 24,000 calls failed; Washington {{utc-time|UTC}} fined them $7.2 M. **{{volte|VoLTE}}/{{vonr|VoNR}} is the world's largest [[sip|SIP]] deployment** β€” {{gsma|GSMA}} reports 310+ {{volte|VoLTE}} operators in 140+ countries and 45+ commercial {{vonr|VoNR}} networks by 2025 β€” and the failure modes ripple straight into emergency services." }, { type: 'narrative', @@ -231,11 +233,12 @@ The cryptography is slowly tightening: **{{rfc-doc|RFC}} 8760 (March 2020)** fin { id: 'hls-and-dash', title: 'HLS and DASH', - synopsis: '[[hls|HLS]] and [[dash|DASH]] β€” adaptive bitrate over plain {{http-method|HTTP}}, and the {{m3u|M3U}} playlist Winamp left behind.', + synopsis: + '[[hls|HLS]] and [[dash|DASH]] β€” adaptive bitrate over plain {{http-method|HTTP}}, and the {{m3u|M3U}} playlist Winamp left behind.', slots: [ { kind: 'pull-quote', - text: 'The world\'s most-deployed video protocol still starts every playlist with `#EXTM3U` β€” the format Fraunhofer created in 1995 for WinPlay3 and Nullsoft popularised in Winamp on 21 April 1997.', + text: "The world's most-deployed video protocol still starts every playlist with `#EXTM3U` β€” the format Fraunhofer created in 1995 for WinPlay3 and Nullsoft popularised in Winamp on 21 April 1997.", attribution: 'Author' }, { @@ -253,7 +256,7 @@ The trick was breaking the stream into **2-10 second segments**, each a regular { type: 'callout', title: 'M3U is a Winamp inheritance', - text: '[[hls|HLS]]\'s playlist format is **{{m3u|M3U}}**, which was created in 1995 by Fraunhofer IIS for **WinPlay3** and popularised by **Nullsoft\'s Winamp on 21 April 1997**. The world\'s most-deployed video protocol β€” the one carrying every live sports event, every Netflix stream, every {{apple|Apple}} TV {{broadcast|broadcast}} β€” still starts every playlist with `#EXTM3U`. The internet runs on inheritance.' + text: "[[hls|HLS]]'s playlist format is **{{m3u|M3U}}**, which was created in 1995 by Fraunhofer IIS for **WinPlay3** and popularised by **Nullsoft's Winamp on 21 April 1997**. The world's most-deployed video protocol β€” the one carrying every live sports event, every Netflix stream, every {{apple|Apple}} TV {{broadcast|broadcast}} β€” still starts every playlist with `#EXTM3U`. The internet runs on inheritance." }, { type: 'narrative', @@ -291,7 +294,7 @@ The post-Flash reality: **Adobe Flash Player retired on 31 December 2020**, kill src: 'https://upload.wikimedia.org/wikipedia/commons/thumb/f/f5/Zpracovani_videa_HTTP_Live_Streaming.png/500px-Zpracovani_videa_HTTP_Live_Streaming.png', alt: 'HLS architecture diagram β€” encoder produces multi-bitrate segments, CDN serves them, player adapts bitrate.', caption: - '**[[hls|HLS]]** architecture: an encoder produces parallel multi-bitrate ladders of small .ts (or now .mp4 / CMAF) segments; a {{cdn|CDN}} serves them over plain {{http-method|HTTP}}; the client adapts bitrate between segments. Shipped 17 June 2009 with iPhone {{os|OS}} 3.0 / iPhone 3GS β€” {{apple|Apple}}\'s play to dodge Flash and survive the 2008 3G {{firewall|firewall}} reality by reusing {{http-method|HTTP}}/443.', + "**[[hls|HLS]]** architecture: an encoder produces parallel multi-bitrate ladders of small .ts (or now .mp4 / CMAF) segments; a {{cdn|CDN}} serves them over plain {{http-method|HTTP}}; the client adapts bitrate between segments. Shipped 17 June 2009 with iPhone {{os|OS}} 3.0 / iPhone 3GS β€” {{apple|Apple}}'s play to dodge Flash and survive the 2008 3G {{firewall|firewall}} reality by reusing {{http-method|HTTP}}/443.", credit: 'Image: Wikimedia Commons / CC BY-SA' } ] @@ -306,7 +309,8 @@ The post-Flash reality: **Adobe Flash Player retired on 31 December 2020**, kill { id: 'moq-transport', title: 'MoQ Transport', - synopsis: 'Sub-second live streaming over [[quic|QUIC]] β€” the first {{ietf|IETF}} media transport that intentionally is not [[rtp|RTP]].', + synopsis: + 'Sub-second live streaming over [[quic|QUIC]] β€” the first {{ietf|IETF}} media transport that intentionally is not [[rtp|RTP]].', slots: [ { kind: 'pull-quote', @@ -363,7 +367,7 @@ The conservative alternative: **[[rtp|RTP]]-over-[[quic|QUIC]] (RoQ)**. \`draft- src: 'https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/AT%26T_Picturephone_%2812721549765%29.jpg/500px-AT%26T_Picturephone_%2812721549765%29.jpg', alt: 'The 1964 AT&T Picturephone β€” an early commercial video-call device.', caption: - 'The **AT&T Picturephone**, demonstrated at the 1964 World\'s Fair β€” the first commercial live video over a telecommunications network. Sixty years and four wholesale rewrites later (analog β†’ ISDN β†’ [[rtp|RTP]]/H.323 β†’ [[webrtc|WebRTC]]), **MoQ over [[quic|QUIC]]** is the latest answer to the question the Picturephone asked: *how do you carry one-to-many live video at scale, in real time, over a network you do not own?* The current draft is `draft-{{ietf|ietf}}-moq-transport-17`; {{cloudflare|Cloudflare}} deployed MoQ relays across 330+ cities through 2025.', + "The **AT&T Picturephone**, demonstrated at the 1964 World's Fair β€” the first commercial live video over a telecommunications network. Sixty years and four wholesale rewrites later (analog β†’ ISDN β†’ [[rtp|RTP]]/H.323 β†’ [[webrtc|WebRTC]]), **MoQ over [[quic|QUIC]]** is the latest answer to the question the Picturephone asked: *how do you carry one-to-many live video at scale, in real time, over a network you do not own?* The current draft is `draft-{{ietf|ietf}}-moq-transport-17`; {{cloudflare|Cloudflare}} deployed MoQ relays across 330+ cities through 2025.", credit: 'Photo: AT&T Archives / Wikimedia Commons, public domain' } ] diff --git a/src/lib/data/book/parts/story-of-the-internet.ts b/src/lib/data/book/parts/story-of-the-internet.ts index 233e44e..5d50c26 100644 --- a/src/lib/data/book/parts/story-of-the-internet.ts +++ b/src/lib/data/book/parts/story-of-the-internet.ts @@ -20,7 +20,8 @@ export const storyOfTheInternet: BookPart = { { id: 'before-the-internet', title: 'Before the Internet', - synopsis: '{{xerox-parc|Xerox PARC}}, {{arpanet|ARPANET}}, {{ncp|NCP}} β€” the three streams that flowed into [[tcp|TCP]]/[[ip|IP]].', + synopsis: + '{{xerox-parc|Xerox PARC}}, {{arpanet|ARPANET}}, {{ncp|NCP}} β€” the three streams that flowed into [[tcp|TCP]]/[[ip|IP]].', slots: [ { kind: 'pull-quote', @@ -41,7 +42,7 @@ The third tradition was packet radio. ARPA's Packet Radio Network (PRNET, 1973) }, { type: 'callout', - title: "Why three? Because the problem was three problems.", + title: 'Why three? Because the problem was three problems.', text: 'Local fabric ([[ethernet|Ethernet]]), wide-area research backbone ({{arpanet|ARPANET}}), and unreliable wireless (PRNET/SATNET) each forced different design pressures. The architecture that won β€” [[tcp|TCP]]/[[ip|IP]] β€” is the one that took none of them as canonical and instead specified the **gluing** layer.' } ] @@ -62,7 +63,7 @@ The third tradition was packet radio. ARPA's Packet Radio Network (PRNET, 1973) src: 'https://upload.wikimedia.org/wikipedia/commons/thumb/3/3d/Interface_Message_Processor_%28%22IMP%22%29_%282586235502%29.jpg/500px-Interface_Message_Processor_%28%22IMP%22%29_%282586235502%29.jpg', alt: 'A BBN-built Interface Message Processor (IMP) on display at the Computer History Museum.', caption: - 'An original {{bbn|BBN}} {{imp|Interface Message Processor}} ({{imp|IMP}}) β€” the rugged minicomputer that served as {{arpanet|ARPANET}}\'s first router. The protocol that ran between IMPs is what [[tcp|TCP]]/[[ip|IP]] would later replace.', + "An original {{bbn|BBN}} {{imp|Interface Message Processor}} ({{imp|IMP}}) β€” the rugged minicomputer that served as {{arpanet|ARPANET}}'s first router. The protocol that ran between IMPs is what [[tcp|TCP]]/[[ip|IP]] would later replace.", credit: 'Photo: Erik Pitti, CC BY 2.0, via Wikimedia Commons' } ] @@ -75,7 +76,8 @@ The third tradition was packet radio. ARPA's Packet Radio Network (PRNET, 1973) { id: 'the-1981-burst', title: 'The 1981–83 Standardisation Burst', - synopsis: '[[rfc:791|RFC 791]]/792/793, the {{arpanet|ARPANET}} {{flag-day-1983|flag day}}, and {{ieee-802-15-4|IEEE}} 802.3 ratified β€” three years that locked in the stack.', + synopsis: + '[[rfc:791|RFC 791]]/792/793, the {{arpanet|ARPANET}} {{flag-day-1983|flag day}}, and {{ieee-802-15-4|IEEE}} 802.3 ratified β€” three years that locked in the stack.', slots: [ { kind: 'prose', @@ -123,7 +125,8 @@ This is the deepest principle of the era: **separate what changes together from { id: 'the-1986-collapse', title: 'The 1986 Congestion Collapse', - synopsis: '32 kbps to 40 bps in 400 yards β€” and [[pioneer:van-jacobson|Van Jacobson]]\'s six-algorithm fix.', + synopsis: + "32 kbps to 40 bps in 400 yards β€” and [[pioneer:van-jacobson|Van Jacobson]]'s six-algorithm fix.", slots: [ { kind: 'prose', @@ -222,7 +225,7 @@ By 1995, {{osi-model|OSI}} was effectively dead in production networks. CLNP sur sections: [ { type: 'narrative', - title: 'A Manager\'s Side Project', + title: "A Manager's Side Project", text: `In March 1989, **[[pioneer:tim-berners-lee|Tim Berners-Lee]]** circulated a memo at {{cern|CERN}} titled **"Information Management: A Proposal."** His manager, Mike Sendall, scribbled "vague but exciting" on the cover. The proposal described a system where documents on different machines could link to each other through hypertext, retrieved by a uniform addressing scheme. By Christmas 1990, on a NeXT workstation in his office, Berners-Lee had built the first **web server** (info.cern.ch), the first **web browser** (also a WYSIWYG editor), and the first three protocols he needed: {{http-method|HTTP}} for transport, {{html|HTML}} for markup, and URLs for addressing. The whole system rode on top of [[tcp|TCP]] β€” that was the entire architectural assumption. It did not have to invent transport, ordering, {{retransmission|retransmission}}, or addressing. The internet had already solved those. @@ -253,14 +256,15 @@ The architectural lesson the web carried forward: an application that succeeds a { kind: 'pull-quote', text: 'Vague but exciting.', - attribution: 'Mike Sendall, on the cover of Berners-Lee\'s 1989 memo' + attribution: "Mike Sendall, on the cover of Berners-Lee's 1989 memo" } ] }, { id: 'mobile-and-bufferbloat', title: 'The Mobile and Bufferbloat Decade', - synopsis: '3G, 4G, the iPhone, and why your home internet is {{bufferbloat|laggy under load}}.', + synopsis: + '3G, 4G, the iPhone, and why your home internet is {{bufferbloat|laggy under load}}.', slots: [ { kind: 'prose', @@ -276,8 +280,9 @@ The fix took fifteen years. **{{aqm|Active queue management}}** (CoDel, fq_codel }, { type: 'callout', - title: 'Bufferbloat is the canonical example of well-meaning engineering creating a network-wide pathology.', - text: 'Adding more buffer seemed obviously good β€” bursts wouldn\'t cause loss. But [[tcp|TCP]]\'s congestion-control loop **needed** loss as its signal. The fix was to push buffers back down and add explicit signalling ({{ecn|ECN}}) instead.' + title: + 'Bufferbloat is the canonical example of well-meaning engineering creating a network-wide pathology.', + text: "Adding more buffer seemed obviously good β€” bursts wouldn't cause loss. But [[tcp|TCP]]'s congestion-control loop **needed** loss as its signal. The fix was to push buffers back down and add explicit signalling ({{ecn|ECN}}) instead." }, { type: 'image', @@ -326,7 +331,7 @@ This is the structural lesson of the late-2010s protocol-design era: **{{encrypt src: 'https://upload.wikimedia.org/wikipedia/commons/thumb/2/29/Google_Data_Center%2C_The_Dalles.jpg/500px-Google_Data_Center%2C_The_Dalles.jpg', alt: 'Google data center in The Dalles, Oregon β€” where the gQUIC traffic was first deployed.', caption: - '{{google|Google}}\'s data center in **The Dalles, Oregon**. By 2014, every connection to *chrome.com* / *youtube.com* from a Chrome client was speaking experimental gQUIC over [[udp|UDP]] to one of these buildings. The fleet of users plus the fleet of servers is what gave {{google|Google}} the leverage to design a new transport β€” and the leverage to *iterate* on it monthly instead of waiting decades for kernel rollouts.', + "{{google|Google}}'s data center in **The Dalles, Oregon**. By 2014, every connection to *chrome.com* / *youtube.com* from a Chrome client was speaking experimental gQUIC over [[udp|UDP]] to one of these buildings. The fleet of users plus the fleet of servers is what gave {{google|Google}} the leverage to design a new transport β€” and the leverage to *iterate* on it monthly instead of waiting decades for kernel rollouts.", credit: 'Photo: Tony Webster, CC BY 2.0, via Wikimedia Commons' } ] diff --git a/src/lib/data/book/parts/transport.ts b/src/lib/data/book/parts/transport.ts index a31d184..c19a27e 100644 --- a/src/lib/data/book/parts/transport.ts +++ b/src/lib/data/book/parts/transport.ts @@ -20,7 +20,8 @@ export const transport: BookPart = { { id: 'tcp', title: 'TCP', - synopsis: '[[tcp|Reliable byte streams]], four decades of {{congestion-control|congestion control}}.', + synopsis: + '[[tcp|Reliable byte streams]], four decades of {{congestion-control|congestion control}}.', slots: [ { kind: 'pull-quote', @@ -51,7 +52,7 @@ Forty-five years after [[rfc:9293|RFC 793]] (September 1981), [[tcp|TCP]] is sti { type: 'callout', title: 'Three pre-existing security incidents from the 1990s', - text: '**[[tcp|TCP]] sequence-prediction (Mitnick 1994)** exploited predictable initial {{sequence-number|sequence numbers}} from {{bsd|BSD}}\'s linear {{isn|ISN}} counter. [[rfc:1948|RFC 1948]] (1996) replaced it with a cryptographically-hashed function of the four-tuple. **{{syn-cookies|SYN}} floods (mid-1990s)** exhausted server connection tables before {{syn-cookies|SYN cookies}} (Bernstein, [[rfc:4987|RFC 4987]]) made them {{stateless|stateless}}. **Smurf attacks (1997)** abused [[ip|IP]] {{broadcast|broadcast}} to amplify {{tcp-rst|TCP RST}} floods. Modern stacks defeat all three; the design lessons are baked into [[rfc:9293|RFC 9293]]\'s security considerations.' + text: "**[[tcp|TCP]] sequence-prediction (Mitnick 1994)** exploited predictable initial {{sequence-number|sequence numbers}} from {{bsd|BSD}}'s linear {{isn|ISN}} counter. [[rfc:1948|RFC 1948]] (1996) replaced it with a cryptographically-hashed function of the four-tuple. **{{syn-cookies|SYN}} floods (mid-1990s)** exhausted server connection tables before {{syn-cookies|SYN cookies}} (Bernstein, [[rfc:4987|RFC 4987]]) made them {{stateless|stateless}}. **Smurf attacks (1997)** abused [[ip|IP]] {{broadcast|broadcast}} to amplify {{tcp-rst|TCP RST}} floods. Modern stacks defeat all three; the design lessons are baked into [[rfc:9293|RFC 9293]]'s security considerations." }, { type: 'narrative', @@ -97,7 +98,8 @@ The vulnerability surface keeps producing CVEs. **{{cve|CVE}}-2019-11477 ({{sack { id: 'udp', title: 'UDP', - synopsis: '[[udp|Three pages of RFC]], no guarantees, ubiquitous β€” and the substrate beneath [[quic|QUIC]].', + synopsis: + '[[udp|Three pages of RFC]], no guarantees, ubiquitous β€” and the substrate beneath [[quic|QUIC]].', slots: [ { kind: 'pull-quote', @@ -199,7 +201,7 @@ The deeper lesson [[sctp|SCTP]] teaches is the lesson [[quic|QUIC]] applied: **i { type: 'callout', title: 'WebRTC Data Channels are SCTP under the hood', - text: 'There is one place [[sctp|SCTP]] runs successfully on the open internet: **[[webrtc|WebRTC]] Data Channels**. [[rfc:8831|RFC 8831]] defines the data channel as **[[sctp|SCTP]] over {{dtls|DTLS}} over [[udp|UDP]]** β€” the [[sctp|SCTP]]-over-something-else trick [[quic|QUIC]] would later generalise. The browser implementations (libwebrtc, Firefox\'s networking stack) carry an [[sctp|SCTP]] stack in user space. [[webrtc|WebRTC]] is the largest production [[sctp|SCTP]] deployment by message count, even though almost nobody knows it.' + text: "There is one place [[sctp|SCTP]] runs successfully on the open internet: **[[webrtc|WebRTC]] Data Channels**. [[rfc:8831|RFC 8831]] defines the data channel as **[[sctp|SCTP]] over {{dtls|DTLS}} over [[udp|UDP]]** β€” the [[sctp|SCTP]]-over-something-else trick [[quic|QUIC]] would later generalise. The browser implementations (libwebrtc, Firefox's networking stack) carry an [[sctp|SCTP]] stack in user space. [[webrtc|WebRTC]] is the largest production [[sctp|SCTP]] deployment by message count, even though almost nobody knows it." }, { type: 'narrative', @@ -328,7 +330,7 @@ The {{ietf|IETF}} [[quic|QUIC]] Working Group, formed in 2016, took {{google|Goo }, { type: 'narrative', - title: 'What\'s On the Frontier', + title: "What's On the Frontier", text: `The next ten years of transport innovation are all riding on [[quic|QUIC]]. **[[frontier:multipath-quic|Multipath QUIC]]** (\`draft-ietf-quic-multipath\`) entered IESG Last Call in December 2025. Inherits [[mptcp|MPTCP]]'s algorithmic ideas inside a transport that actually traverses middleboxes. @@ -348,7 +350,7 @@ By 2026, **{{meta|Meta}} reports >75% of internet-facing traffic on [[quic|QUIC] src: 'https://upload.wikimedia.org/wikipedia/commons/thumb/2/20/Google_Corkboard_Server_Rack.jpg/500px-Google_Corkboard_Server_Rack.jpg', alt: 'Early Google "corkboard" server rack β€” bare motherboards mounted on cork backing, displayed at the Computer History Museum.', caption: - 'An early **{{google|Google}} corkboard server** β€” the company that designed [[quic|QUIC]] in 2012 because it could no longer ship [[tcp|TCP]] improvements through kernel rollouts fast enough for its fleet. [[pioneer:jim-roskind|Jim Roskind]]\'s answer was to put a brand-new transport in *user space* on top of [[udp|UDP]], where it could iterate monthly and middleboxes would forward it unchanged.', + "An early **{{google|Google}} corkboard server** β€” the company that designed [[quic|QUIC]] in 2012 because it could no longer ship [[tcp|TCP]] improvements through kernel rollouts fast enough for its fleet. [[pioneer:jim-roskind|Jim Roskind]]'s answer was to put a brand-new transport in *user space* on top of [[udp|UDP]], where it could iterate monthly and middleboxes would forward it unchanged.", credit: 'Photo: Wikimedia Commons / CC BY-SA' } ] diff --git a/src/lib/data/book/parts/utilities-security.ts b/src/lib/data/book/parts/utilities-security.ts index 4972c9b..16549b9 100644 --- a/src/lib/data/book/parts/utilities-security.ts +++ b/src/lib/data/book/parts/utilities-security.ts @@ -12,13 +12,15 @@ export const utilitiesSecurity: BookPart = { id: 'utilities-security', title: 'Utilities & Security', label: 'IX', - description: 'The invisible plumbing β€” [[tls|TLS]], [[ssh|SSH]], [[ntp|NTP]], the email stack, and authentication.', + description: + 'The invisible plumbing β€” [[tls|TLS]], [[ssh|SSH]], [[ntp|NTP]], the email stack, and authentication.', chapters: [ // ──────────────────────────────────────────────────────────── { id: 'tls', title: 'TLS', - synopsis: '[[tls|From SSL 1.0]] (never released) to post-quantum hybrid by default in iOS 26.', + synopsis: + '[[tls|From SSL 1.0]] (never released) to post-quantum hybrid by default in iOS 26.', slots: [ { kind: 'pull-quote', @@ -40,7 +42,7 @@ In 1999 the {{ietf|IETF}} took ownership and renamed it [[tls|TLS]] 1.0 ([[rfc:2 { type: 'callout', title: 'TLS 1.3 has middlebox-compatibility hacks built in', - text: 'The "everyone gets it wrong" wire fact: **[[tls|TLS]] 1.3 {{client-hello|ClientHello}}.legacy_version = 0x0303** ([[tls|TLS]] 1.2); the real version goes in the \`supported_versions\` extension. **legacy_session_id is non-empty** (faking {{session-resumption|session resumption}}). Both sides send a no-op **ChangeCipherSpec record** after their first flight. All of this is because middleboxes broke when they saw real [[tls|TLS]] 1.3 wire format. The protocol is technically clean; the wire encoding is a deliberate camouflage.' + text: 'The "everyone gets it wrong" wire fact: **[[tls|TLS]] 1.3 {{client-hello|ClientHello}}.legacy_version = 0x0303** ([[tls|TLS]] 1.2); the real version goes in the `supported_versions` extension. **legacy_session_id is non-empty** (faking {{session-resumption|session resumption}}). Both sides send a no-op **ChangeCipherSpec record** after their first flight. All of this is because middleboxes broke when they saw real [[tls|TLS]] 1.3 wire format. The protocol is technically clean; the wire encoding is a deliberate camouflage.' }, { type: 'narrative', @@ -73,7 +75,7 @@ Two more historical incidents to name: **goto fail ({{cve|CVE}}-2014-1266)** β€” src: 'https://upload.wikimedia.org/wikipedia/commons/thumb/9/95/Digital_certificates_chain_of_trust.png/500px-Digital_certificates_chain_of_trust.png', alt: 'Digital certificate chain of trust diagram β€” root CA, intermediate CA, end-entity certificate.', caption: - 'A **[[tls|TLS]] {{certificate-chain|certificate chain}} of trust**: a root {{certificate-authority|CA}} signs an intermediate CA, which signs the end-entity {{certificate|certificate}} your browser actually sees. Every HTTPS connection ends at a chain like this; DigiNotar\'s August 2011 compromise (531 fraudulent certs for 344 domains) is what forced **{{certificate-transparency|Certificate Transparency}}** into existence as a structural fix. The current frontier is 47-day cert lifetimes, mandatory by 15 March 2029.', + "A **[[tls|TLS]] {{certificate-chain|certificate chain}} of trust**: a root {{certificate-authority|CA}} signs an intermediate CA, which signs the end-entity {{certificate|certificate}} your browser actually sees. Every HTTPS connection ends at a chain like this; DigiNotar's August 2011 compromise (531 fraudulent certs for 344 domains) is what forced **{{certificate-transparency|Certificate Transparency}}** into existence as a structural fix. The current frontier is 47-day cert lifetimes, mandatory by 15 March 2029.", credit: 'Image: Wikimedia Commons / CC BY-SA' } ] @@ -92,7 +94,8 @@ Two more historical incidents to name: **goto fail ({{cve|CVE}}-2014-1266)** β€” { id: 'ssh', title: 'SSH', - synopsis: '[[ssh|Encrypted shells]], port forwards, and {{scp-copy|SCP}} β€” written by Tatu YlΓΆnen in Helsinki, July 1995.', + synopsis: + '[[ssh|Encrypted shells]], port forwards, and {{scp-copy|SCP}} β€” written by Tatu YlΓΆnen in Helsinki, July 1995.', slots: [ { kind: 'pull-quote', @@ -160,7 +163,8 @@ The protocol uses **public-key cryptography** for host and user authentication, { id: 'ntp', title: 'NTP', - synopsis: '[[ntp|Why your timestamp is correct]] to within milliseconds β€” and the era rollover on 7 February 2036.', + synopsis: + '[[ntp|Why your timestamp is correct]] to within milliseconds β€” and the era rollover on 7 February 2036.', slots: [ { kind: 'pull-quote', @@ -184,7 +188,7 @@ A client samples the {{rtt|round-trip time}} to a server (call it Ξ΄) and the ap { type: 'callout', title: 'Era rollover: 7 February 2036 at 06:28:16 UTC', - text: '[[ntp|NTP]]\'s 64-bit timestamp uses the **[[ntp|NTP]] prime epoch, 1900-01-01 00:00:00 {{utc-time|UTC}}** β€” older than {{arpanet|ARPANET}}, older than UNIX, older than every other timestamp standard in computing. Span = 2Β³Β² s = **136.19 years per era**. **Era rollover is 7 February 2036 at 06:28:16 {{utc-time|UTC}}.** The protocol handles eras correctly via 64-bit math; many client implementations assume 32-bit and will need fixes before 2036. The Y2036 work has been quietly underway since 2020.' + text: "[[ntp|NTP]]'s 64-bit timestamp uses the **[[ntp|NTP]] prime epoch, 1900-01-01 00:00:00 {{utc-time|UTC}}** β€” older than {{arpanet|ARPANET}}, older than UNIX, older than every other timestamp standard in computing. Span = 2Β³Β² s = **136.19 years per era**. **Era rollover is 7 February 2036 at 06:28:16 {{utc-time|UTC}}.** The protocol handles eras correctly via 64-bit math; many client implementations assume 32-bit and will need fixes before 2036. The Y2036 work has been quietly underway since 2020." }, { type: 'narrative', @@ -217,7 +221,7 @@ A client samples the {{rtt|round-trip time}} to a server (call it Ξ΄) and the ap src: 'https://upload.wikimedia.org/wikipedia/commons/thumb/8/8e/Nist-f1.jpg/500px-Nist-f1.jpg', alt: 'NIST-F1 caesium fountain atomic clock β€” the US primary frequency standard.', caption: - '**{{nist|NIST}}-F1**, the caesium fountain atomic clock that has served as the US primary frequency standard since 1999. Accurate to about one second in 100 million years. [[pioneer:david-mills|David Mills]]\'s **[[ntp|NTP]]** (1985 β€” Mills died 17 January 2024) is the protocol that flows this kind of accuracy out to every laptop, phone, and server on the internet, with Marzullo\'s 1984 consensus algorithm picking a sane median from a flock of stratum-1 sources.', + "**{{nist|NIST}}-F1**, the caesium fountain atomic clock that has served as the US primary frequency standard since 1999. Accurate to about one second in 100 million years. [[pioneer:david-mills|David Mills]]'s **[[ntp|NTP]]** (1985 β€” Mills died 17 January 2024) is the protocol that flows this kind of accuracy out to every laptop, phone, and server on the internet, with Marzullo's 1984 consensus algorithm picking a sane median from a flock of stratum-1 sources.", credit: 'Photo: NIST / public domain, via Wikimedia Commons' } ] @@ -231,7 +235,8 @@ A client samples the {{rtt|round-trip time}} to a server (call it Ξ΄) and the ap { id: 'oauth-and-jwt', title: 'OAuth 2.1 and JWT', - synopsis: '[[oauth2|How modern apps delegate access]] β€” and the most famous resignation in protocol history.', + synopsis: + '[[oauth2|How modern apps delegate access]] β€” and the most famous resignation in protocol history.', slots: [ { kind: 'pull-quote', @@ -253,7 +258,7 @@ Before [[oauth2|OAuth]], an app that wanted access to your {{google|Google}} cal { type: 'callout', title: 'The Road to Hell resignation', - text: '**The "Road to Hell" resignation (26 July 2012)**: Eran Hammer published *"[[oauth2|OAuth]] 2.0 and the Road to Hell"* β€” most famous resignation in modern protocol history. His core line: *"WS-\* bad"* β€” shorthand among {{ietf|IETF}} veterans for any standard sunk by enterprise committee design. The "everyone gets it wrong" framework fact: **[[oauth2|OAuth]] 2.0 is technically a framework, not a protocol.** [[rfc:6749|RFC 6749]]\'s abstract itself warns *"this specification is likely to produce a wide range of non-interoperable implementations"* β€” language Hammer fought to insert.' + text: '**The "Road to Hell" resignation (26 July 2012)**: Eran Hammer published *"[[oauth2|OAuth]] 2.0 and the Road to Hell"* β€” most famous resignation in modern protocol history. His core line: *"WS-* bad"* β€” shorthand among {{ietf|IETF}} veterans for any standard sunk by enterprise committee design. The "everyone gets it wrong" framework fact: **[[oauth2|OAuth]] 2.0 is technically a framework, not a protocol.** [[rfc:6749|RFC 6749]]\'s abstract itself warns *"this specification is likely to produce a wide range of non-interoperable implementations"* β€” language Hammer fought to insert.' }, { type: 'narrative', @@ -308,7 +313,8 @@ Before [[oauth2|OAuth]], an app that wanted access to your {{google|Google}} cal { id: 'email-stack', title: 'The Email Stack', - synopsis: '[[smtp|SMTP]] + [[imap|IMAP]], the protocol family that refused to die β€” and the new bulk-sender enforcement.', + synopsis: + '[[smtp|SMTP]] + [[imap|IMAP]], the protocol family that refused to die β€” and the new bulk-sender enforcement.', slots: [ { kind: 'pull-quote', @@ -367,7 +373,7 @@ His "Ten Commandments of How to Write an [[imap|IMAP]] client" still circulates; src: 'https://upload.wikimedia.org/wikipedia/commons/thumb/7/72/Email.svg/500px-Email.svg.png', alt: 'Email envelope icon β€” stylised mail handler.', caption: - '**Email** β€” the longest-running application of the internet. Ray Tomlinson at {{bbn|BBN}} picked the **@** sign in 1971 modifying SNDMSG. [[pioneer:jon-postel|Jon Postel]] published [[rfc:5321|RFC 821]] on port 25 in August 1982. Forty-four years later [[smtp|SMTP]] still relays your mail, [[imap|IMAP]] still serves your folders, and **{{dmarc|DMARC}} enforcement** at {{google|Google}} + Yahoo (from 1 February 2024) finally killed the easy spoofed-From address. The protocol is older than {{arpanet|ARPANET}}\'s {{flag-day-1983|flag day}}; the standards work is not done.', + "**Email** β€” the longest-running application of the internet. Ray Tomlinson at {{bbn|BBN}} picked the **@** sign in 1971 modifying SNDMSG. [[pioneer:jon-postel|Jon Postel]] published [[rfc:5321|RFC 821]] on port 25 in August 1982. Forty-four years later [[smtp|SMTP]] still relays your mail, [[imap|IMAP]] still serves your folders, and **{{dmarc|DMARC}} enforcement** at {{google|Google}} + Yahoo (from 1 February 2024) finally killed the easy spoofed-From address. The protocol is older than {{arpanet|ARPANET}}'s {{flag-day-1983|flag day}}; the standards work is not done.", credit: 'Image: Wikimedia Commons / public domain' } ] diff --git a/src/lib/data/book/parts/web-api.ts b/src/lib/data/book/parts/web-api.ts index 529f048..c99bb82 100644 --- a/src/lib/data/book/parts/web-api.ts +++ b/src/lib/data/book/parts/web-api.ts @@ -57,7 +57,7 @@ That readability is the entire reason every developer can debug an HTTP problem { type: 'callout', title: 'The 6-connection cap is why HTTP/2 exists', - text: 'By 2009, web pages were averaging 90 requests across 15 origins. With 6 connections per origin, every page paid the cost of [[tcp|TCP]] setup repeatedly, and connections were {{imap-idle|idle}} most of the time. {{google|Google}}\'s {{spdy|SPDY}} experiment proposed {{multiplexing|multiplexing}} many requests over a single connection, with {{binary-framing|binary framing}}. {{spdy|SPDY}} became the seed of [[http2|HTTP/2]].' + text: "By 2009, web pages were averaging 90 requests across 15 origins. With 6 connections per origin, every page paid the cost of [[tcp|TCP]] setup repeatedly, and connections were {{imap-idle|idle}} most of the time. {{google|Google}}'s {{spdy|SPDY}} experiment proposed {{multiplexing|multiplexing}} many requests over a single connection, with {{binary-framing|binary framing}}. {{spdy|SPDY}} became the seed of [[http2|HTTP/2]]." }, { type: 'narrative', @@ -75,7 +75,7 @@ That readability is the entire reason every developer can debug an HTTP problem src: 'https://upload.wikimedia.org/wikipedia/commons/thumb/d/d5/HTTP_persistent_connection.svg/500px-HTTP_persistent_connection.svg.png', alt: 'HTTP persistent connection diagram β€” multiple request/response pairs reusing the same TCP connection.', caption: - '**[[http1|HTTP/1.1]] persistent connections** β€” request, response, request, response, all on the *same* [[tcp|TCP]] socket. The default in [[http1|HTTP/1.1]] (1997), and a quiet revolution after [[http1|HTTP/1.0]]\'s one-connection-per-request model. The reason a 1990s page-load of 90 small assets did not have to pay 90 {{syn-cookies|SYN}}/{{syn-ack|SYN-ACK}}/{{ack|ACK}} handshakes.', + "**[[http1|HTTP/1.1]] persistent connections** β€” request, response, request, response, all on the *same* [[tcp|TCP]] socket. The default in [[http1|HTTP/1.1]] (1997), and a quiet revolution after [[http1|HTTP/1.0]]'s one-connection-per-request model. The reason a 1990s page-load of 90 small assets did not have to pay 90 {{syn-cookies|SYN}}/{{syn-ack|SYN-ACK}}/{{ack|ACK}} handshakes.", credit: 'Image: Wikimedia Commons / CC BY-SA 3.0' } ] @@ -91,7 +91,8 @@ That readability is the entire reason every developer can debug an HTTP problem { id: 'http2', title: 'HTTP/2', - synopsis: '{{binary-framing|Binary framing}}, streams, {{hpack|HPACK}} β€” and the security saga that has not stopped.', + synopsis: + '{{binary-framing|Binary framing}}, streams, {{hpack|HPACK}} β€” and the security saga that has not stopped.', slots: [ { kind: 'pull-quote', @@ -140,7 +141,7 @@ The pattern: each {{cve|CVE}} breaks an assumption that earlier mitigations had src: 'https://upload.wikimedia.org/wikipedia/commons/thumb/1/19/HTTP_pipelining2.svg/500px-HTTP_pipelining2.svg.png', alt: 'HTTP/1.1 pipelining vs HTTP/2 multiplexing diagram, showing how multiple streams share one connection.', caption: - '[[http1|HTTP/1.1]] {{pipelining|pipelining}} vs [[http2|HTTP/2]] {{multiplexing|multiplexing}}. The 6-connection cap on [[http1|HTTP/1.1]] meant browsers paid the cost of [[tcp|TCP]] setup repeatedly; [[http2|HTTP/2]]\'s many-streams-on-one-connection model dropped page loads 30-40% in real-world measurements. The trade-off: a single {{retransmission|TCP retransmit}} now stalls *all* streams β€” which is the {{head-of-line-blocking|head-of-line blocking}} problem [[http3|HTTP/3]] finally fixed.', + "[[http1|HTTP/1.1]] {{pipelining|pipelining}} vs [[http2|HTTP/2]] {{multiplexing|multiplexing}}. The 6-connection cap on [[http1|HTTP/1.1]] meant browsers paid the cost of [[tcp|TCP]] setup repeatedly; [[http2|HTTP/2]]'s many-streams-on-one-connection model dropped page loads 30-40% in real-world measurements. The trade-off: a single {{retransmission|TCP retransmit}} now stalls *all* streams β€” which is the {{head-of-line-blocking|head-of-line blocking}} problem [[http3|HTTP/3]] finally fixed.", credit: 'Image: Wikimedia Commons / CC BY-SA 4.0' } ] @@ -213,7 +214,7 @@ The fix in flight is **in-kernel [[quic|QUIC]]**. Xin Long posted the first ~9,0 src: 'https://upload.wikimedia.org/wikipedia/commons/thumb/7/73/Full_TLS_1.3_Handshake.svg/500px-Full_TLS_1.3_Handshake.svg.png', alt: 'TLS 1.3 full handshake diagram showing ClientHello, ServerHello, certificate, finished messages in one round-trip.', caption: - 'The **[[tls|TLS]] 1.3** {{handshake|handshake}} β€” one round-trip ([[rfc:8446|RFC 8446]], 2018), down from two in [[tls|TLS]] 1.2. [[http3|HTTP/3]]\'s headline win is *folding this entire {{handshake|handshake}} into the [[quic|QUIC]] transport {{handshake|handshake}}*, achieving **{{one-rtt|1-RTT}}** connection setup for new sessions and **{{zero-rtt|0-RTT}}** for resumption β€” a flat 1-2 round-trips eliminated from every page load on mobile, where {{latency|latency}}, not {{bandwidth|bandwidth}}, is the bottleneck.', + "The **[[tls|TLS]] 1.3** {{handshake|handshake}} β€” one round-trip ([[rfc:8446|RFC 8446]], 2018), down from two in [[tls|TLS]] 1.2. [[http3|HTTP/3]]'s headline win is *folding this entire {{handshake|handshake}} into the [[quic|QUIC]] transport {{handshake|handshake}}*, achieving **{{one-rtt|1-RTT}}** connection setup for new sessions and **{{zero-rtt|0-RTT}}** for resumption β€” a flat 1-2 round-trips eliminated from every page load on mobile, where {{latency|latency}}, not {{bandwidth|bandwidth}}, is the bottleneck.", credit: 'Image: Wikimedia Commons / CC0' } ] @@ -231,7 +232,8 @@ The fix in flight is **in-kernel [[quic|QUIC]]**. Xin Long posted the first ~9,0 { id: 'rest-and-graphql', title: 'REST and GraphQL', - synopsis: '[[rest|REST]] and [[graphql|GraphQL]] β€” two ways to model an {{api|API}}, and a 25-year argument over which one Fielding actually meant.', + synopsis: + '[[rest|REST]] and [[graphql|GraphQL]] β€” two ways to model an {{api|API}}, and a 25-year argument over which one Fielding actually meant.', slots: [ { kind: 'prose', @@ -295,7 +297,8 @@ The choice between [[rest|REST]] and [[graphql|GraphQL]] is not strictly either/ { id: 'grpc', title: 'gRPC', - synopsis: '[[grpc|Typed RPC]] over [[http2|HTTP/2]] β€” the microservices default for the controlled-both-sides case.', + synopsis: + '[[grpc|Typed RPC]] over [[http2|HTTP/2]] β€” the microservices default for the controlled-both-sides case.', slots: [ { kind: 'pull-quote', @@ -340,7 +343,7 @@ Active 2024-2026 work in the [[grpc|gRPC]] working group includes: native [[http src: 'https://upload.wikimedia.org/wikipedia/commons/1/18/RPC_overview.png', alt: 'RPC overview diagram β€” client stub, network, server stub, marshalling and unmarshalling parameters.', caption: - 'The **{{rpc|RPC}}** model that [[grpc|gRPC]] inherits from a 40-year lineage of Sun {{rpc|RPC}} / DCE / CORBA / Thrift. The client *stub* serialises arguments, sends them over the network, and pretends to the caller that nothing happened. [[grpc|gRPC]]\'s contribution is **{{protocol-buffers|Protocol Buffers}}** (compact binary schema) + **[[http2|HTTP/2]] streams** as the transport. The model dominates service-to-service traffic inside every large engineering org since ~2019.', + "The **{{rpc|RPC}}** model that [[grpc|gRPC]] inherits from a 40-year lineage of Sun {{rpc|RPC}} / DCE / CORBA / Thrift. The client *stub* serialises arguments, sends them over the network, and pretends to the caller that nothing happened. [[grpc|gRPC]]'s contribution is **{{protocol-buffers|Protocol Buffers}}** (compact binary schema) + **[[http2|HTTP/2]] streams** as the transport. The model dominates service-to-service traffic inside every large engineering org since ~2019.", credit: 'Image: Wikimedia Commons / CC BY-SA' } ] @@ -354,7 +357,8 @@ Active 2024-2026 work in the [[grpc|gRPC]] working group includes: native [[http { id: 'websockets-and-sse', title: 'WebSockets and SSE', - synopsis: '[[websockets|WebSockets]] and [[sse|SSE]] β€” {{server-push|server push}} two ways, and the [[sse|SSE]] renaissance via {{llm|LLM}} streaming.', + synopsis: + '[[websockets|WebSockets]] and [[sse|SSE]] β€” {{server-push|server push}} two ways, and the [[sse|SSE]] renaissance via {{llm|LLM}} streaming.', slots: [ { kind: 'pull-quote', @@ -392,7 +396,7 @@ That changed when LLMs started streaming tokens. **OpenAI, {{anthropic|Anthropic { type: 'callout', title: 'The 2024-2026 CVE wave for WebSocket', - text: '[[rfc:6455|RFC 6455]] itself has not changed. The ecosystem has. Major CVEs in major implementations: **{{cve|CVE}}-2024-37890** in Node \`ws\`; **{{cve|CVE}}-2025-10148** in libcurl reviving the very cache-poisoning attack masking was designed to prevent; **{{cve|CVE}}-2025-43855** in tRPC; **{{cve|CVE}}-2025-5399** in libcurl. \`gorilla/websocket\` was archived in late 2022 and unarchived under community maintenance; \`nhooyr/websocket\` was renamed to \`coder/websocket\` in 2024. The protocol is stable; the implementations are not.' + text: '[[rfc:6455|RFC 6455]] itself has not changed. The ecosystem has. Major CVEs in major implementations: **{{cve|CVE}}-2024-37890** in Node `ws`; **{{cve|CVE}}-2025-10148** in libcurl reviving the very cache-poisoning attack masking was designed to prevent; **{{cve|CVE}}-2025-43855** in tRPC; **{{cve|CVE}}-2025-5399** in libcurl. `gorilla/websocket` was archived in late 2022 and unarchived under community maintenance; `nhooyr/websocket` was renamed to `coder/websocket` in 2024. The protocol is stable; the implementations are not.' }, { type: 'narrative', @@ -424,7 +428,8 @@ The choice between [[websockets|WebSocket]], [[sse|SSE]], and {{webtransport|Web { id: 'mcp-and-a2a', title: 'MCP and A2A', - synopsis: 'The protocol layer for {{ai|AI}} agents β€” built deliberately boring on top of [[json-rpc|JSON-RPC]], {{http-method|HTTP}}, and [[sse|SSE]].', + synopsis: + 'The protocol layer for {{ai|AI}} agents β€” built deliberately boring on top of [[json-rpc|JSON-RPC]], {{http-method|HTTP}}, and [[sse|SSE]].', slots: [ { kind: 'pull-quote', diff --git a/src/lib/data/book/parts/wireless.ts b/src/lib/data/book/parts/wireless.ts index c77c204..26726cf 100644 --- a/src/lib/data/book/parts/wireless.ts +++ b/src/lib/data/book/parts/wireless.ts @@ -45,7 +45,7 @@ Wired networking is a problem with a known solution. Wireless networking is thre }, { type: 'narrative', - title: "CSMA/CA β€” the bedrock trick", + title: 'CSMA/CA β€” the bedrock trick', text: `Wired [[ethernet|Ethernet]] uses **{{csma-cd|CSMA/CD}}** (Collision *Detection*): a station listens while it transmits, and the moment another station's signal collides with its own on the wire, both back off and retry. That trick is **impossible on radio**. Your own transmitter saturates your own receiver β€” a wireless {{nic|NIC}} literally cannot hear another station while it is sending. Every wireless {{mac-address|MAC}} therefore uses **{{csma-ca|CSMA/CA}}** β€” listen *before* you talk, plus a randomised back-off if the channel was busy, plus a mandatory {{ack|ACK}} after every {{unicast|unicast}} frame so the sender knows whether it got through. [[wifi|Wi-Fi]] calls it DCF (Distributed Coordination Function). Before each frame, a station senses the channel for a DIFS interval (28–34 Β΅s), picks a random slot from a contention window (initial CW = 15, doubled on collision up to 1023), and transmits if still {{imap-idle|idle}}. Every successful frame is ACKed after a SIFS gap (~10 Β΅s); no {{ack|ACK}} in time is presumed to mean collision and the sender retries from a larger window. The ratio of *protocol overhead* to *{{payload|payload}} bytes* on a busy [[wifi|802.11]] channel routinely exceeds 50% β€” which is why a Wi-Fi 6 {{access-point|access point}}'s nominal 9.6 Gbit/s shows up as 1–2 Gbit/s of real throughput in a crowded room. @@ -55,7 +55,7 @@ Wired networking is a problem with a known solution. Wireless networking is thre { type: 'callout', title: 'The hidden-terminal problem in one sentence', - text: 'On a wired bus, every station hears every other station. On a radio, station A and station C may both hear {{access-point|AP}} B but **not each other** β€” so they both think the channel is clear, both transmit at once, and both collide at B. The **{{hidden-terminal|RTS/CTS}}** option exists because of this; so does [[bluetooth|BLE]]\'s master-clocked frequency hopping; so does every [[cellular|cellular]] {{ran|RAN}}\'s centralised uplink scheduler. The same physics ripples through every wireless protocol design.' + text: "On a wired bus, every station hears every other station. On a radio, station A and station C may both hear {{access-point|AP}} B but **not each other** β€” so they both think the channel is clear, both transmit at once, and both collide at B. The **{{hidden-terminal|RTS/CTS}}** option exists because of this; so does [[bluetooth|BLE]]'s master-clocked frequency hopping; so does every [[cellular|cellular]] {{ran|RAN}}'s centralised uplink scheduler. The same physics ripples through every wireless protocol design." }, { type: 'narrative', @@ -109,7 +109,7 @@ They coexist by a series of small accommodations. **Modern combo chips** ({{appl slots: [ { kind: 'pull-quote', - text: 'Wi-Fi 6\'s nominal 9.6 Gbit/s shows up as 1–2 Gbit/s of real throughput in a crowded room, because more than half of the {{airtime|airtime}} is spent on DIFS gaps, {{ack|ACK}} frames, beacons, and back-off. The headline number is a physics fact; the delivered number is an {{airtime|airtime}} budget.', + text: "Wi-Fi 6's nominal 9.6 Gbit/s shows up as 1–2 Gbit/s of real throughput in a crowded room, because more than half of the {{airtime|airtime}} is spent on DIFS gaps, {{ack|ACK}} frames, beacons, and back-off. The headline number is a physics fact; the delivered number is an {{airtime|airtime}} budget.", attribution: 'Author' }, { @@ -126,7 +126,7 @@ If you read Part III's Wi-Fi chapter first, this one is the second pass. If you }, { type: 'narrative', - title: "The CSMA/CA loop in real time", + title: 'The CSMA/CA loop in real time', text: `Every [[wifi|802.11]] transmission begins with a station deciding the channel is {{imap-idle|idle}}. The procedure (DCF β€” Distributed Coordination Function) is mechanical: sense the channel for a **DIFS** interval of 28–34 Β΅s, pick a random slot from a contention window starting at CW = 15, count it down (each slot = 9 or 20 Β΅s depending on {{phy|PHY}}), and transmit if the channel is still idle when the counter hits zero. If two stations pick the same slot, they collide; both double their CW (up to 1023) and try again. Every {{unicast|unicast}} frame must be {{ack|ACKed}} after a **SIFS** gap of ~10 Β΅s. No {{ack|ACK}} means assumed collision and retransmit from a larger CW. {{ack|ACK}} frames are themselves unprotected by CSMA β€” they fire SIFS-fast precisely so no other station has time to seize the channel between data and {{ack|ACK}}. @@ -136,7 +136,7 @@ The visible cost is **{{airtime|airtime}} overhead**. Add up DIFS + SIFS + {{ack { type: 'callout', title: 'RTS/CTS is the hidden-terminal escape hatch', - text: 'When two stations cannot hear each other but both hear the {{access-point|AP}}, they need the {{hidden-terminal|hidden-terminal}} fix: send a tiny **Request To Send**, wait for the {{ap-access-point|AP}}\'s **Clear To Send** which every other station within range will also hear, then transmit during the announced duration. {{rts-cts|RTS/CTS}} is *optional* and trades {{latency|latency}} for {{airtime|airtime}} certainty β€” it adds two extra frames to every transmission, so it is on by default only for frames larger than a configurable threshold (often 2,346 bytes β€” i.e., never in practice). Networks that {{turn|turn}} it on aggressively tend to be airport halls and convention centres where dozens of clients are routinely behind a column from each other.' + text: "When two stations cannot hear each other but both hear the {{access-point|AP}}, they need the {{hidden-terminal|hidden-terminal}} fix: send a tiny **Request To Send**, wait for the {{ap-access-point|AP}}'s **Clear To Send** which every other station within range will also hear, then transmit during the announced duration. {{rts-cts|RTS/CTS}} is *optional* and trades {{latency|latency}} for {{airtime|airtime}} certainty β€” it adds two extra frames to every transmission, so it is on by default only for frames larger than a configurable threshold (often 2,346 bytes β€” i.e., never in practice). Networks that {{turn|turn}} it on aggressively tend to be airport halls and convention centres where dozens of clients are routinely behind a column from each other." }, { type: 'narrative', @@ -161,7 +161,7 @@ The real headline feature of [[wifi|Wi-Fi]] 8 / 802.11bn is more honest about th { type: 'callout', title: 'Power management is the hidden battery story', - text: '802.11ax introduced **{{target-wake-time|Target Wake Time}}** β€” a client and {{access-point|AP}} pre-negotiate exact wake-up windows, so the client\'s radio stays deeply asleep between scheduled appointments. Originally aimed at low-power IoT (years on a coin cell), it is now what extends smartphone battery life on busy networks. **{{bss-coloring|BSS Coloring}}** added a 6-bit color field so a station can tell its own {{ap-access-point|AP}}\'s transmissions from a neighbour\'s on the same channel, and apply a relaxed clear-channel threshold β€” recovering {{airtime|airtime}} that classic carrier sense would have forfeited. Both features are why Wi-Fi 6/7 outperforms Wi-Fi 5 in *exactly the apartment buildings and shopping centres* where Wi-Fi 5 used to grind to a halt.' + text: "802.11ax introduced **{{target-wake-time|Target Wake Time}}** β€” a client and {{access-point|AP}} pre-negotiate exact wake-up windows, so the client's radio stays deeply asleep between scheduled appointments. Originally aimed at low-power IoT (years on a coin cell), it is now what extends smartphone battery life on busy networks. **{{bss-coloring|BSS Coloring}}** added a 6-bit color field so a station can tell its own {{ap-access-point|AP}}'s transmissions from a neighbour's on the same channel, and apply a relaxed clear-channel threshold β€” recovering {{airtime|airtime}} that classic carrier sense would have forfeited. Both features are why Wi-Fi 6/7 outperforms Wi-Fi 5 in *exactly the apartment buildings and shopping centres* where Wi-Fi 5 used to grind to a halt." }, { type: 'narrative', @@ -261,7 +261,7 @@ The pattern is simple: BLE has the **right discovery + power profile** to be the }, { type: 'narrative', - title: "LE Audio, Auracast, and the hearing-loop replacement story", + title: 'LE Audio, Auracast, and the hearing-loop replacement story', text: `**{{le-audio|LE Audio}}** is the 2020+ rebuild of Bluetooth audio, defined across Core 5.2+ and a stack of profiles (BAP, PBP, TMAP, HAP). It runs over **Isochronous Channels** β€” Connected Isochronous Streams (CIS) for {{unicast|unicast}} earbuds and hearing aids, {{broadcast|Broadcast}} Isochronous Streams ({{bis-broadcast|BIS}}) for one-to-many. The mandatory {{codec|codec}} is **{{lc3|LC3}}** ({{sig|SIG}} + Fraunhofer IIS + Ericsson, January 2020), roughly 2Γ— more battery-efficient than the 1990s SBC {{codec|codec}} at equivalent quality. The cultural moment is **{{auracast|Auracast}}** β€” the {{sig|SIG}}'s brand for **{{broadcast|Broadcast}} Isochronous Streams** ({{bis-broadcast|BIS}}) over {{le-audio|LE Audio}} + {{lc3|LC3}}, one transmitter to unlimited listeners. Public venues replace analog hearing-loops with an {{auracast|Auracast}} {{broadcast|broadcast}}; nearby listeners scan, pick a stream, and tune in. **Frankfurt Airport became the first airport in the world to {{broadcast|broadcast}} all gate announcements over {{auracast|Auracast}} on 28 January 2026**. Cinemas, theatres, gyms, lecture halls, and houses of worship are deploying similar setups through 2026 and 2027. @@ -296,7 +296,7 @@ The 2022 attack is the canonical case study for why every credential standard si src: 'https://upload.wikimedia.org/wikipedia/commons/thumb/d/da/Bluetooth.svg/250px-Bluetooth.svg.png', alt: 'The Bluetooth logo β€” a bind-rune combining Hagall and Bjarkan, the initials of Harald BlΓ₯tand.', caption: - 'The **[[bluetooth|Bluetooth]]** logo: a bind-rune combining **Hagall** (ᚼ = H) and **Bjarkan** (α›’ = B) β€” *Harald BlΓ₯tand*\'s initials in Younger Futhark. [[pioneer:jim-kardach|Jim Kardach]] of {{intel|Intel}} proposed the name on a Toronto pub crawl in 1997 after the 10th-century Danish king who united Denmark and Norway. It was supposed to be a placeholder.', + "The **[[bluetooth|Bluetooth]]** logo: a bind-rune combining **Hagall** (ᚼ = H) and **Bjarkan** (α›’ = B) β€” *Harald BlΓ₯tand*'s initials in Younger Futhark. [[pioneer:jim-kardach|Jim Kardach]] of {{intel|Intel}} proposed the name on a Toronto pub crawl in 1997 after the 10th-century Danish king who united Denmark and Norway. It was supposed to be a placeholder.", credit: 'Image: Bluetooth SIG trademark, via Wikimedia Commons' } ] @@ -345,7 +345,7 @@ Read that sentence again. **The control plane of every 5G carrier on Earth is no { type: 'callout', title: 'The largest enterprise IPsec deployment on Earth', - text: 'Every interface between the [[cellular|cellular]] {{ran|radio access network}} and the core (N2/N3 in 5G, S1 in {{lte|LTE}}) is wrapped in [[ipsec|IPsec ESP]] per {{3gpp|3GPP}} {{ts-3gpp|TS}} 33.501. With ~9 billion subscribers and tens of millions of base stations worldwide, the [[cellular|cellular]] backhaul is the single largest production [[ipsec|IPsec]] deployment that exists. [[pioneer:andreas-steffen|Andreas Steffen]]\'s strongSwan, {{cisco|Cisco}} IOS, and Juniper {{junos|Junos}} run more [[ipsec|IPsec]] tunnels inside one [[cellular|cellular]] operator than the entire enterprise {{vpn|VPN}} market combined.' + text: "Every interface between the [[cellular|cellular]] {{ran|radio access network}} and the core (N2/N3 in 5G, S1 in {{lte|LTE}}) is wrapped in [[ipsec|IPsec ESP]] per {{3gpp|3GPP}} {{ts-3gpp|TS}} 33.501. With ~9 billion subscribers and tens of millions of base stations worldwide, the [[cellular|cellular]] backhaul is the single largest production [[ipsec|IPsec]] deployment that exists. [[pioneer:andreas-steffen|Andreas Steffen]]'s strongSwan, {{cisco|Cisco}} IOS, and Juniper {{junos|Junos}} run more [[ipsec|IPsec]] tunnels inside one [[cellular|cellular]] operator than the entire enterprise {{vpn|VPN}} market combined." }, { type: 'narrative', @@ -409,7 +409,7 @@ The shape rhymes with the rest of this Part. Every wireless protocol's cryptogra src: 'https://upload.wikimedia.org/wikipedia/commons/thumb/4/4a/Cellular_network_standards_and_generation_timeline.svg/500px-Cellular_network_standards_and_generation_timeline.svg.png', alt: 'Timeline of cellular network standards from 1G through 5G, by generation.', caption: - '**Fifty years of [[cellular|cellular]]** β€” from 1G analog AMPS / TACS / NMT in the early 1980s through 2G {{gsm|GSM}} / IS-95, 3G {{wcdma|WCDMA}} / CDMA2000, 4G {{lte|LTE}}, and {{5g-nr|5G NR}}. Each generation redrew both the air interface and the core network on roughly a decade\'s cadence, while the {{3gpp|3GPP}} Release calendar kept ticking every ~18 months. **6G** is in pre-standardisation now; first commercial deployments expected around 2030.', + "**Fifty years of [[cellular|cellular]]** β€” from 1G analog AMPS / TACS / NMT in the early 1980s through 2G {{gsm|GSM}} / IS-95, 3G {{wcdma|WCDMA}} / CDMA2000, 4G {{lte|LTE}}, and {{5g-nr|5G NR}}. Each generation redrew both the air interface and the core network on roughly a decade's cadence, while the {{3gpp|3GPP}} Release calendar kept ticking every ~18 months. **6G** is in pre-standardisation now; first commercial deployments expected around 2030.", credit: 'Image: Wikimedia Commons / CC BY-SA 4.0' } ] @@ -473,7 +473,7 @@ Seven APDUs, ~300 ms, and the latte is paid for.` }, { type: 'narrative', - title: "Tokenisation β€” why your real card number never leaves the bank", + title: 'Tokenisation β€” why your real card number never leaves the bank', text: `{{apple|Apple}}'s 9 September 2014 launch was not just "we added an [[nfc|NFC]] chip to the iPhone." It was a *tokenisation revolution* baked into the architecture. The cardholder's real **Funding {{pan-id|PAN}} (FPAN)** never reaches the device. The bank issues a **Device {{pan-id|PAN}} ({{dpan|DPAN}})** instead, provisioned via the Token Service Provider (Visa Token Service or Mastercard Digital Enablement Service) into the {{ese|embedded Secure Element}} or the {{hce|HCE}} keystore. Every tap generates a per-transaction {{emv-cryptogram|cryptogram}} bound to the {{dpan|DPAN}}, the **{{atc|ATC}}** (Application Transaction Counter), and the **Unpredictable Number** from the terminal. A stolen {{dpan|DPAN}} is worthless without the keys in the {{se-secure-element|SE}}; a stolen cryptogram is worthless because the {{atc|ATC}} has already moved on. This is the reason **{{apple|Apple}} Pay fraud rates in 2026 are broadly in line with card-not-present rates** β€” much better than physical-card-present fraud at unattended terminals β€” despite the initial 2015 *"yellow path"* enrolment disaster where social-engineered phone agents over-approved fraudulent provisioning. @@ -616,7 +616,7 @@ The unlock dance: {{ble|BLE}} advertising from the car β†’ {{ble|BLE}} pairing + }, { type: 'narrative', - title: "Regional masks, Japan, and the global-product problem", + title: 'Regional masks, Japan, and the global-product problem', text: `{{fcc|FCC}} Part 15.519 caps average power-spectral-density at **βˆ’41.3 dBm/MHz** across 3.1–10.6 GHz. {{etsi|ETSI}} EN 302 065 in Europe is similar but with stricter Detect-and-Avoid requirements in some sub-bands. **Japan** applies a different mask with restrictions in 7.25–7.75 GHz that overlap Channel 9 β€” {{apple|Apple}}'s iPhone reduces or disables [[uwb|UWB]] features (Precision Finding, Find People) in Japan and a handful of other countries. The practical effect for a global consumer product: **(a)** geo-fence [[uwb|UWB]] features based on locale, **(b)** default to **Channel 5** in Japan and a handful of other restricted jurisdictions, **(c)** support a *no-UWB* mode entirely for countries where [[uwb|UWB]] is not permitted (a few small markets). This is one of the underappreciated reasons [[uwb|UWB]] consumer adoption is slower than {{ble|BLE}} or [[wifi|Wi-Fi]] β€” *the regulatory map is fragmented*, and every iPhone software release ships a different list of countries where Precision Finding works. @@ -628,7 +628,7 @@ The contrast with [[nfc|NFC]] is instructive: [[nfc|NFC]] operates in the global src: 'https://upload.wikimedia.org/wikipedia/commons/thumb/2/2d/Apple_AirTag.svg/330px-Apple_AirTag.svg.png', alt: 'An Apple AirTag β€” a small round white tracker with the Apple logo.', caption: - 'The **{{apple|Apple}} AirTag**, $29, shipped 30 April 2021. Inside: a battery, a {{ble|BLE}} radio, a speaker, and the **{{apple|Apple}} {{u1-chip|U1}} chip** β€” the [[uwb|UWB]] silicon that gave consumer [[uwb|UWB]] its first mass-market product. Precision Finding\'s arrow-and-distance display swept the world\'s awareness of [[uwb|UWB]] into one purchase. ABI projects [[uwb|UWB]] phone penetration rising from 27% in 2025 to 52% by 2030 β€” the same adoption curve [[nfc|NFC]] followed a decade earlier.', + "The **{{apple|Apple}} AirTag**, $29, shipped 30 April 2021. Inside: a battery, a {{ble|BLE}} radio, a speaker, and the **{{apple|Apple}} {{u1-chip|U1}} chip** β€” the [[uwb|UWB]] silicon that gave consumer [[uwb|UWB]] its first mass-market product. Precision Finding's arrow-and-distance display swept the world's awareness of [[uwb|UWB]] into one purchase. ABI projects [[uwb|UWB]] phone penetration rising from 27% in 2025 to 52% by 2030 β€” the same adoption curve [[nfc|NFC]] followed a decade earlier.", credit: 'Image: Apple Inc. trademark / Wikimedia Commons' } ] @@ -651,7 +651,7 @@ The contrast with [[nfc|NFC]] is instructive: [[nfc|NFC]] operates in the global slots: [ { kind: 'pull-quote', - text: "Philips Hue's 2012 {{apple|Apple}} Store launch never said \"Zigbee\" out loud. The press release mentioned ZigBee LightLink exactly once; the in-store materials, packaging, and iOS app strenuously avoided the term. The customer was sold *web-enabled* lighting. The canonical example of a successful protocol whose user-visible brand is the product, not the standard.", + text: 'Philips Hue\'s 2012 {{apple|Apple}} Store launch never said "Zigbee" out loud. The press release mentioned ZigBee LightLink exactly once; the in-store materials, packaging, and iOS app strenuously avoided the term. The customer was sold *web-enabled* lighting. The canonical example of a successful protocol whose user-visible brand is the product, not the standard.', attribution: 'Author' }, { @@ -701,7 +701,7 @@ In 2026, **new device design has bifurcated**. Lighting and sensors are increasi { type: 'callout', title: "Matter's commitment, in three sentences", - text: 'The {{sig-bluetooth-acronym|CSA}} launched **{{matter|Matter}} 1.0 on 4 October 2022** as an {{ip-address|IP}}-native smart-home standard, running over [[wifi|Wi-Fi]], [[ethernet|Ethernet]], and {{thread|Thread}}. {{matter|Matter}} does **not** run over [[zigbee|Zigbee]] on the wire β€” but it reuses Zigbee\'s {{zcl|ZCL}} data model directly, which lets a *{{matter|Matter}} Bridge for non-{{matter|Matter}} devices* (Hue Bridge, Aqara Hub M3) translate {{matter|Matter}} operations to Zigbee one-to-one. Now at **v1.5 (20 November 2025)**, with camera streaming via RTSP, removing the last category that previously required Zigbee bridging.' + text: "The {{sig-bluetooth-acronym|CSA}} launched **{{matter|Matter}} 1.0 on 4 October 2022** as an {{ip-address|IP}}-native smart-home standard, running over [[wifi|Wi-Fi]], [[ethernet|Ethernet]], and {{thread|Thread}}. {{matter|Matter}} does **not** run over [[zigbee|Zigbee]] on the wire β€” but it reuses Zigbee's {{zcl|ZCL}} data model directly, which lets a *{{matter|Matter}} Bridge for non-{{matter|Matter}} devices* (Hue Bridge, Aqara Hub M3) translate {{matter|Matter}} operations to Zigbee one-to-one. Now at **v1.5 (20 November 2025)**, with camera streaming via RTSP, removing the last category that previously required Zigbee bridging." }, { type: 'narrative', @@ -753,7 +753,7 @@ For the home-automation hobbyist, the **{{matter|Matter}} bridge** is the right id: 'security-across-the-wireless-family', title: 'Security across the wireless family', synopsis: - 'One arc covering {{krack|KRACK}}, {{knob-attack|KNOB}}/{{bias-attack|BIAS}}/{{bluffs-attack|BLUFFS}}, FragAttacks, {{mifare|MIFARE}} Crypto1, the 2022 Tesla [[bluetooth|BLE]] relay, the Ghost Peak [[uwb|UWB]] {{sts|STS}} attack, and the {{ss7|SS7}} / {{diameter|Diameter}} trust holdover β€” every wireless protocol\'s negotiation logic, broken on stage at least once.', + "One arc covering {{krack|KRACK}}, {{knob-attack|KNOB}}/{{bias-attack|BIAS}}/{{bluffs-attack|BLUFFS}}, FragAttacks, {{mifare|MIFARE}} Crypto1, the 2022 Tesla [[bluetooth|BLE]] relay, the Ghost Peak [[uwb|UWB]] {{sts|STS}} attack, and the {{ss7|SS7}} / {{diameter|Diameter}} trust holdover β€” every wireless protocol's negotiation logic, broken on stage at least once.", slots: [ { kind: 'pull-quote', @@ -874,7 +874,7 @@ Every chapter in this Part has security stories. This chapter ties them together slots: [ { kind: 'pull-quote', - text: '{{spectrum|Spectrum}} policy moves on a four-year clock; the technology runs ten years faster. Every wireless protocol\'s deployment is gated by a regulator nobody on the engineering team has met.', + text: "{{spectrum|Spectrum}} policy moves on a four-year clock; the technology runs ten years faster. Every wireless protocol's deployment is gated by a regulator nobody on the engineering team has met.", attribution: 'Author' }, { @@ -903,7 +903,7 @@ The lower 6 GHz band (5.925–6.425 GHz) is **Low-Power Indoor (LPI)** β€” licen { type: 'callout', title: 'CBRS and the three-tier sharing experiment', - text: 'The US **{{cbrs|Citizens Broadband Radio Service}}** band β€” 3.55–3.7 GHz β€” is the US regulator\'s **experiment in dynamic {{spectrum|spectrum}} sharing**. Three tiers coexist: **Incumbent** (US Navy radars get absolute priority), **Priority Access Licensees** (PALs, auctioned in 2020 for ~$4.5B), and **General Authorized Access** (anyone with a certified device). A cloud service called the **{{spectrum|Spectrum}} Access System** arbitrates in real time β€” telling each device which channels and power levels it may use right now based on Navy radar activity. Powers Private 4G {{lte|LTE}} / 5G deployments at ports (Port of Long Beach), mines, hospitals, manufacturing plants, and stadiums. The largest production use of *database-arbitrated coexistence* anywhere on Earth. Europe has experimented with similar concepts (PMSE in the UK, {{lsa|LSA}} in some EU pilots) but has not deployed at {{cbrs|CBRS}} scale.' + text: "The US **{{cbrs|Citizens Broadband Radio Service}}** band β€” 3.55–3.7 GHz β€” is the US regulator's **experiment in dynamic {{spectrum|spectrum}} sharing**. Three tiers coexist: **Incumbent** (US Navy radars get absolute priority), **Priority Access Licensees** (PALs, auctioned in 2020 for ~$4.5B), and **General Authorized Access** (anyone with a certified device). A cloud service called the **{{spectrum|Spectrum}} Access System** arbitrates in real time β€” telling each device which channels and power levels it may use right now based on Navy radar activity. Powers Private 4G {{lte|LTE}} / 5G deployments at ports (Port of Long Beach), mines, hospitals, manufacturing plants, and stadiums. The largest production use of *database-arbitrated coexistence* anywhere on Earth. Europe has experimented with similar concepts (PMSE in the UK, {{lsa|LSA}} in some EU pilots) but has not deployed at {{cbrs|CBRS}} scale." }, { type: 'narrative', @@ -961,7 +961,7 @@ Whether [[cellular|cellular]] {{ambient-iot|Ambient IoT}} actually displaces the { type: 'callout', title: 'The four-year clock and the two-year clock', - text: 'Two clocks set the pace of wireless. The first is the **{{wrc|World Radiocommunication Conference}}**, every 3–4 years, where the world\'s {{spectrum|spectrum}} allocations are renegotiated by treaty. **{{wrc|WRC-27}}** is the next major event β€” terahertz bands for 6G, harmonisation of {{direct-to-cell|Direct-to-Cell}} bands, the 6 GHz EU upper-band decision. The second is the **{{3gpp|3GPP}} Release cycle**, every ~18 months β€” Release 19 in flight, Release 20 (6G study items) kicking off. Together they decide what wireless protocols you can build, where, when. The {{ietf|IETF}} model β€” *rough consensus and running code, two-week sprints* β€” does not apply at this layer. {{spectrum|Spectrum}} and cellular standards run on geological time, and that is the constraint every wireless engineer eventually meets.' + text: "Two clocks set the pace of wireless. The first is the **{{wrc|World Radiocommunication Conference}}**, every 3–4 years, where the world's {{spectrum|spectrum}} allocations are renegotiated by treaty. **{{wrc|WRC-27}}** is the next major event β€” terahertz bands for 6G, harmonisation of {{direct-to-cell|Direct-to-Cell}} bands, the 6 GHz EU upper-band decision. The second is the **{{3gpp|3GPP}} Release cycle**, every ~18 months β€” Release 19 in flight, Release 20 (6G study items) kicking off. Together they decide what wireless protocols you can build, where, when. The {{ietf|IETF}} model β€” *rough consensus and running code, two-week sprints* β€” does not apply at this layer. {{spectrum|Spectrum}} and cellular standards run on geological time, and that is the constraint every wireless engineer eventually meets." }, { type: 'narrative', diff --git a/src/lib/data/category-deep-dives.ts b/src/lib/data/category-deep-dives.ts index 7c4617f..31f4dd9 100644 --- a/src/lib/data/category-deep-dives.ts +++ b/src/lib/data/category-deep-dives.ts @@ -246,7 +246,8 @@ Transport is pluggable: **{{stdio|stdio}}** for local processes (the server is a { type: 'diagram', title: 'MCP Session Lifecycle', - caption: 'The full [[mcp|MCP]] session from initialization through tool invocation. The three-step {{handshake|handshake}} establishes capabilities before any tool or resource access.', + caption: + 'The full [[mcp|MCP]] session from initialization through tool invocation. The three-step {{handshake|handshake}} establishes capabilities before any tool or resource access.', definition: `graph TD I["initialize request<br/>(client capabilities, version)"] --> IR["initialize response<br/>(server capabilities, tools, resources)"] IR --> N["initialized {{notification|notification}}<br/>({{handshake|handshake}} complete)"] @@ -529,7 +530,7 @@ The numbers below are typical 2026 production values; spec maxima are higher, re }, { type: 'narrative', - title: 'CSMA/CA β€” collision avoidance in a medium you can\'t monitor', + title: "CSMA/CA β€” collision avoidance in a medium you can't monitor", text: `Wired [[ethernet|Ethernet]] uses **{{csma-cd|CSMA/CD}}** (Collision Detection): a station listens while it transmits and aborts the moment another station's signal collides with its own. That trick is impossible on radio β€” your own transmitter saturates your own receiver, so a wireless {{nic|NIC}} literally cannot hear another station while it is sending. Every wireless {{mac-address|MAC}} therefore uses **{{csma-ca|CSMA/CA}}** (Collision *Avoidance*): listen-before-talk, plus a randomised back-off if the channel was busy. [[wifi|Wi-Fi]]'s flavour is DCF (Distributed Coordination Function). Before each {{frame|frame}}, the station senses the channel for a DIFS interval (28–34 Β΅s), then picks a random slot from a contention window (initial CW=15, doubled on collision up to 1023), then transmits if still {{imap-idle|idle}}. Every successful frame is {{ack|ACKed}} after a SIFS gap (~10 Β΅s); no {{ack|ACK}} in time = the sender assumes collision and {{retransmission|retransmits}} from a larger CW. {{rts-cts|RTS/CTS}} is the optional defence against hidden terminals: the sender first asks "may I?" with a tiny RTS, the receiver responds with CTS, and every station that heard either falls silent for the negotiated duration. @@ -541,7 +542,7 @@ The cost of {{csma-ca|CSMA/CA}} is **{{airtime|airtime}} overhead**. At Wi-Fi 6' { type: 'callout', title: 'The hidden-terminal problem in one sentence', - text: 'On a wired bus, every station hears every other; on a radio, station A and station C may both hear {{ap-access-point|AP}} B but not each other β€” so they both think the channel is clear and both transmit at once, colliding at B. {{rts-cts|RTS/CTS}} exists because of this. The same physics motivates {{ble|BLE}}\'s frequency-hopping master clock, Zigbee\'s coordinator-led scheduling, and every cellular {{ran|RAN}}\'s centralised uplink scheduler.' + text: "On a wired bus, every station hears every other; on a radio, station A and station C may both hear {{ap-access-point|AP}} B but not each other β€” so they both think the channel is clear and both transmit at once, colliding at B. {{rts-cts|RTS/CTS}} exists because of this. The same physics motivates {{ble|BLE}}'s frequency-hopping master clock, Zigbee's coordinator-led scheduling, and every cellular {{ran|RAN}}'s centralised uplink scheduler." }, { type: 'narrative', diff --git a/src/lib/data/category-stories/async-iot.ts b/src/lib/data/category-stories/async-iot.ts index 1bf201f..4b2d500 100644 --- a/src/lib/data/category-stories/async-iot.ts +++ b/src/lib/data/category-stories/async-iot.ts @@ -122,7 +122,7 @@ export const asyncIotStory: CategoryStory = { title: 'Messaging Visionary', org: 'iMatix', contribution: - 'Built the first open-source [[amqp|AMQP]] broker (OpenAMQ) at iMatix and later created ZeroMQ, a brokerless messaging library. A passionate open-source advocate, though he grew critical of [[amqp|AMQP]]\'s complexity and eventually left the workgroup.', + "Built the first open-source [[amqp|AMQP]] broker (OpenAMQ) at iMatix and later created ZeroMQ, a brokerless messaging library. A passionate open-source advocate, though he grew critical of [[amqp|AMQP]]'s complexity and eventually left the workgroup.", imagePath: 'https://upload.wikimedia.org/wikipedia/commons/thumb/d/d9/Pieter_Hintjens_at_EuroPython2014_%28cropped%29.jpg/330px-Pieter_Hintjens_at_EuroPython2014_%28cropped%29.jpg' }, diff --git a/src/lib/data/category-stories/index.ts b/src/lib/data/category-stories/index.ts index b055dda..8d05902 100644 --- a/src/lib/data/category-stories/index.ts +++ b/src/lib/data/category-stories/index.ts @@ -7,17 +7,17 @@ import { realtimeAvStory } from './realtime-av'; import { utilitiesStory } from './utilities'; import { wirelessStory } from './wireless'; -const storyMap = new Map<string, CategoryStory>( - [ - networkFoundationsStory, - transportStory, - webApiStory, - asyncIotStory, - realtimeAvStory, - utilitiesStory, - wirelessStory - ].map((s) => [s.categoryId, s]) -); +export const categoryStories: CategoryStory[] = [ + networkFoundationsStory, + transportStory, + webApiStory, + asyncIotStory, + realtimeAvStory, + utilitiesStory, + wirelessStory +]; + +const storyMap = new Map<string, CategoryStory>(categoryStories.map((s) => [s.categoryId, s])); export function getCategoryStory(categoryId: string): CategoryStory | undefined { return storyMap.get(categoryId); diff --git a/src/lib/data/category-stories/network-foundations.ts b/src/lib/data/category-stories/network-foundations.ts index 2218241..92c1c9f 100644 --- a/src/lib/data/category-stories/network-foundations.ts +++ b/src/lib/data/category-stories/network-foundations.ts @@ -2,7 +2,8 @@ import type { CategoryStory } from './types'; export const networkFoundationsStory: CategoryStory = { categoryId: 'network-foundations', - tagline: 'From {{xerox-parc|Xerox PARC}} to every connected device β€” how frames, addresses, and routes make the internet possible', + tagline: + 'From {{xerox-parc|Xerox PARC}} to every connected device β€” how frames, addresses, and routes make the internet possible', sections: [ { type: 'narrative', @@ -206,7 +207,7 @@ That sketch became [[ethernet|Ethernet]], and it solved the first problem of net year: 2026, title: 'IPv6 Crosses 50% on Google', description: - 'On 28 March 2026, [[ipv6|IPv6]] carried 50.1% of {{google|Google}}\'s traffic for the first time β€” 28 years after [[rfc:2460|RFC 2460]]. {{cloudflare|Cloudflare}} and {{apnic|APNIC}} measure 40-43% from their vantage points, so the milestone is real but uneven.', + "On 28 March 2026, [[ipv6|IPv6]] carried 50.1% of {{google|Google}}'s traffic for the first time β€” 28 years after [[rfc:2460|RFC 2460]]. {{cloudflare|Cloudflare}} and {{apnic|APNIC}} measure 40-43% from their vantage points, so the milestone is real but uneven.", protocolId: 'ipv6' } ] diff --git a/src/lib/data/category-stories/realtime-av.ts b/src/lib/data/category-stories/realtime-av.ts index 2663bcd..9f88525 100644 --- a/src/lib/data/category-stories/realtime-av.ts +++ b/src/lib/data/category-stories/realtime-av.ts @@ -182,7 +182,8 @@ export const realtimeAvStory: CategoryStory = { { year: 2021, title: 'WebRTC 1.0 \u2014 W3C Recommendation', - description: 'After a decade of development, [[webrtc|WebRTC]] reaches official standard status.', + description: + 'After a decade of development, [[webrtc|WebRTC]] reaches official standard status.', protocolId: 'webrtc' } ] diff --git a/src/lib/data/category-stories/types.ts b/src/lib/data/category-stories/types.ts index 6ab8a99..7e96c7a 100644 --- a/src/lib/data/category-stories/types.ts +++ b/src/lib/data/category-stories/types.ts @@ -45,8 +45,15 @@ export type StorySection = | { type: 'image'; src: string; alt: string; caption?: string; credit?: string; title?: string } | { type: 'comparison'; title?: string; axes: string[]; rows: ComparisonRow[]; note?: string }; -export interface CategoryStory { - categoryId: string; +/** The shared shape of any story body β€” a tagline plus ordered sections. + * Both {@link CategoryStory} and `SubcategoryStory` extend this; components + * that only render the body (e.g. CategoryStoryView) should accept this + * rather than a specific parent type. */ +export interface StoryContent { tagline: string; sections: StorySection[]; } + +export interface CategoryStory extends StoryContent { + categoryId: string; +} diff --git a/src/lib/data/category-stories/utilities.ts b/src/lib/data/category-stories/utilities.ts index 493c4d4..03d8965 100644 --- a/src/lib/data/category-stories/utilities.ts +++ b/src/lib/data/category-stories/utilities.ts @@ -75,7 +75,7 @@ export const utilitiesStory: CategoryStory = { year: 1988, title: 'IMAP Created β€” RFC 1064', description: - "Mark Crispin at Stanford invents the Internet Message Access Protocol. Unlike POP, mail stays on the server β€” a radical idea that enables multi-device access.", + 'Mark Crispin at Stanford invents the Internet Message Access Protocol. Unlike POP, mail stays on the server β€” a radical idea that enables multi-device access.', protocolId: 'imap' } ] @@ -207,7 +207,7 @@ export const utilitiesStory: CategoryStory = { src: 'https://upload.wikimedia.org/wikipedia/commons/thumb/6/69/Netscape_Navigator_2_Screenshot.png/500px-Netscape_Navigator_2_Screenshot.png', alt: 'A screenshot of Netscape Navigator 2, the browser that introduced SSL encryption to the web', caption: - "Netscape Navigator β€” the browser that introduced {{ssl|SSL}} and the padlock icon, making encrypted web communication possible. This {{ui|UI}} convention persists in every browser today.", + 'Netscape Navigator β€” the browser that introduced {{ssl|SSL}} and the padlock icon, making encrypted web communication possible. This {{ui|UI}} convention persists in every browser today.', credit: 'Screenshot: Indolering / CC0, via Wikimedia Commons' }, { diff --git a/src/lib/data/category-stories/web-api.ts b/src/lib/data/category-stories/web-api.ts index fca85d6..4218a80 100644 --- a/src/lib/data/category-stories/web-api.ts +++ b/src/lib/data/category-stories/web-api.ts @@ -14,7 +14,7 @@ The first version, {{http-method|HTTP}}/0.9, supported just one command: GET. No { type: 'image', src: 'https://upload.wikimedia.org/wikipedia/commons/thumb/d/d1/First_Web_Server.jpg/500px-First_Web_Server.jpg', - alt: 'The NeXT computer used by Tim Berners-Lee at CERN, the world\'s first web server', + alt: "The NeXT computer used by Tim Berners-Lee at CERN, the world's first web server", caption: 'The NeXT cube at {{cern|CERN}} β€” the first web server and web browser, built by [[pioneer:tim-berners-lee|Tim Berners-Lee]] in 1990. The handwritten label reads "This machine is a server. DO NOT POWER IT DOWN!!"', credit: 'Photo: Coolcaesar / CC BY-SA 3.0, via Wikimedia Commons' @@ -103,7 +103,7 @@ Meanwhile, {{google|Google}}'s internal {{rpc|RPC}} system 'Stubby' was handling src: 'https://upload.wikimedia.org/wikipedia/commons/thumb/8/8d/Ginevra%2C_centro_visitatori_del_cern%2C_primo_server_della_storia_%281989%29%2C_02.JPG/500px-Ginevra%2C_centro_visitatori_del_cern%2C_primo_server_della_storia_%281989%29%2C_02.JPG', alt: "Tim Berners-Lee's 1989 proposal 'Information Management: A Proposal' displayed at the CERN visitors center", caption: - "Berners-Lee's 1989 proposal on display at {{cern|CERN}} β€” the document his supervisor Mike Sendall marked \"Vague, but exciting.\" It described {{http-method|HTTP}}, {{html|HTML}}, and URLs before any of them existed.", + 'Berners-Lee\'s 1989 proposal on display at {{cern|CERN}} β€” the document his supervisor Mike Sendall marked "Vague, but exciting." It described {{http-method|HTTP}}, {{html|HTML}}, and URLs before any of them existed.', credit: 'Photo: Sailko / CC BY 3.0, via Wikimedia Commons' }, { diff --git a/src/lib/data/category-stories/wireless.ts b/src/lib/data/category-stories/wireless.ts index c5a5495..a7d7a42 100644 --- a/src/lib/data/category-stories/wireless.ts +++ b/src/lib/data/category-stories/wireless.ts @@ -36,7 +36,7 @@ Together β€” Wi-Fi for local broadband, Bluetooth for personal-area, Cellular fo title: 'Viterbi algorithm; Qualcomm co-founder', org: 'Qualcomm', contribution: - 'Invented the **Viterbi algorithm** in 1967 β€” used in every cellular phone, every disk-drive read channel, every {{gps|GPS}} receiver, and every speech recognizer. *On advice of a lawyer, Viterbi did not patent the algorithm.* Co-founded Qualcomm in 1985; led the company through the {{cdma|CDMA}}-vs-{{tdma|TDMA}} wars that culminated in {{cdma|CDMA}}\'s mathematical foundation becoming {{wcdma|WCDMA}} inside {{umts|UMTS}}. **{{ieee-802-15-4|IEEE}} Medal of Honor 2010**.' + "Invented the **Viterbi algorithm** in 1967 β€” used in every cellular phone, every disk-drive read channel, every {{gps|GPS}} receiver, and every speech recognizer. *On advice of a lawyer, Viterbi did not patent the algorithm.* Co-founded Qualcomm in 1985; led the company through the {{cdma|CDMA}}-vs-{{tdma|TDMA}} wars that culminated in {{cdma|CDMA}}'s mathematical foundation becoming {{wcdma|WCDMA}} inside {{umts|UMTS}}. **{{ieee-802-15-4|IEEE}} Medal of Honor 2010**." }, { name: 'Vic Hayes', @@ -52,7 +52,7 @@ Together β€” Wi-Fi for local broadband, Bluetooth for personal-area, Cellular fo title: 'Inventor of Bluetooth', org: 'Ericsson Mobile (Lund) / Plantronics', contribution: - "Dutch engineer who designed the [[bluetooth|Bluetooth]] radio at Ericsson Lund in 1994–97. Tasked with replacing the RS-232 cable to a mobile-phone headset; his frequency-hopping {{piconet|piconet}} design became the foundation of every [[bluetooth|Bluetooth]] chip ever made. European Inventor Award Lifetime Achievement finalist (2015)." + 'Dutch engineer who designed the [[bluetooth|Bluetooth]] radio at Ericsson Lund in 1994–97. Tasked with replacing the RS-232 cable to a mobile-phone headset; his frequency-hopping {{piconet|piconet}} design became the foundation of every [[bluetooth|Bluetooth]] chip ever made. European Inventor Award Lifetime Achievement finalist (2015).' }, { name: 'Sven Mattisson', @@ -60,7 +60,7 @@ Together β€” Wi-Fi for local broadband, Bluetooth for personal-area, Cellular fo title: 'Co-inventor of Bluetooth', org: 'Ericsson Research / Sony Mobile', contribution: - 'Swedish engineer who owned the analog RF and CMOS implementation work that paired with Jaap Haartsen\'s digital baseband. The IC-level decisions that made [[bluetooth|Bluetooth]] manufacturable at consumer price points.' + "Swedish engineer who owned the analog RF and CMOS implementation work that paired with Jaap Haartsen's digital baseband. The IC-level decisions that made [[bluetooth|Bluetooth]] manufacturable at consumer price points." }, { name: 'Jim Kardach', @@ -85,7 +85,7 @@ Together β€” Wi-Fi for local broadband, Bluetooth for personal-area, Cellular fo year: 1973, title: 'First handheld cellular call β€” Motorola DynaTAC', description: - "Marty Cooper of Motorola dials Joel Engel at AT&T Bell Labs from Sixth Avenue, Manhattan: *\"Joel, this is Marty. I'm calling you from a cell phone, a real handheld portable cell phone.\"* The DynaTAC weighs 2.5 lb and gets 35 minutes of talk after 10 hours of charging.", + 'Marty Cooper of Motorola dials Joel Engel at AT&T Bell Labs from Sixth Avenue, Manhattan: *"Joel, this is Marty. I\'m calling you from a cell phone, a real handheld portable cell phone."* The DynaTAC weighs 2.5 lb and gets 35 minutes of talk after 10 hours of charging.', protocolId: 'cellular' }, { @@ -127,7 +127,7 @@ Together β€” Wi-Fi for local broadband, Bluetooth for personal-area, Cellular fo year: 2010, title: 'Bluetooth 4.0 / BLE', description: - '[[bluetooth|Bluetooth]] Core 4.0 (December 2009 β†’ 2010 products) adds **Bluetooth Low Energy** (originally Nokia\'s *Wibree*). Different radio, different framing ({{l2cap|L2CAP}}/{{att-mtu|ATT}}/{{gatt|GATT}}) β€” wearables, beacons, AirTag-class trackers all sit on top of this layer.', + "[[bluetooth|Bluetooth]] Core 4.0 (December 2009 β†’ 2010 products) adds **Bluetooth Low Energy** (originally Nokia's *Wibree*). Different radio, different framing ({{l2cap|L2CAP}}/{{att-mtu|ATT}}/{{gatt|GATT}}) β€” wearables, beacons, AirTag-class trackers all sit on top of this layer.", protocolId: 'bluetooth' }, { @@ -148,7 +148,7 @@ Together β€” Wi-Fi for local broadband, Bluetooth for personal-area, Cellular fo year: 2018, title: '5G NR Release 15 freeze', description: - "{{3gpp|3GPP}} Release 15 β€” the **first {{5g-nr|5G NR}} specification** β€” is frozen on 14 June 2018. Service-based {{5g-core|5G Core}}, flexible numerology, {{mmwave|mmWave}} (FR2) support, network slicing. First commercial 5G networks light up in 2019; first 5G-Standalone (no {{lte|LTE}} anchor) deployments arrive in 2020–2021.", + '{{3gpp|3GPP}} Release 15 β€” the **first {{5g-nr|5G NR}} specification** β€” is frozen on 14 June 2018. Service-based {{5g-core|5G Core}}, flexible numerology, {{mmwave|mmWave}} (FR2) support, network slicing. First commercial 5G networks light up in 2019; first 5G-Standalone (no {{lte|LTE}} anchor) deployments arrive in 2020–2021.', protocolId: 'cellular' }, { @@ -176,7 +176,7 @@ Together β€” Wi-Fi for local broadband, Bluetooth for personal-area, Cellular fo year: 2025, title: 'T-Mobile + SpaceX Direct-to-Cell launches commercially', description: - "The first commercial **satellite-to-cell** service. Standard band n25/n26 phones {{mqtt-connect|connect}} to low-Earth-orbit {{starlink|Starlink}} satellites for {{sms|SMS}} and emergency. {{apple|Apple}}\'s Globalstar partnership and AT&T's AST SpaceMobile follow similar patterns. Reshapes \"coverage\" as a concept: \"no signal\" no longer means *no signal*.", + 'The first commercial **satellite-to-cell** service. Standard band n25/n26 phones {{mqtt-connect|connect}} to low-Earth-orbit {{starlink|Starlink}} satellites for {{sms|SMS}} and emergency. {{apple|Apple}}\'s Globalstar partnership and AT&T\'s AST SpaceMobile follow similar patterns. Reshapes "coverage" as a concept: "no signal" no longer means *no signal*.', protocolId: 'cellular' } ] diff --git a/src/lib/data/comparison/pairs.ts b/src/lib/data/comparison/pairs.ts index 400bb6c..b305f6d 100644 --- a/src/lib/data/comparison/pairs.ts +++ b/src/lib/data/comparison/pairs.ts @@ -13,11 +13,23 @@ const vsPairs: ProtocolPair[] = [ summary: '[[tcp|TCP]] guarantees every byte arrives in order at the cost of {{latency|latency}}; [[udp|UDP]] prioritizes speed by skipping reliability guarantees entirely.', keyDifferences: [ - { aspect: 'Connection model', left: '{{connection-oriented|Connection-oriented}} (3-way handshake)', right: '{{connectionless|Connectionless}} (fire-and-forget)' }, - { aspect: 'Reliability', left: 'Guaranteed delivery with retransmission', right: 'Best-effort, no retransmission' }, + { + aspect: 'Connection model', + left: '{{connection-oriented|Connection-oriented}} (3-way handshake)', + right: '{{connectionless|Connectionless}} (fire-and-forget)' + }, + { + aspect: 'Reliability', + left: 'Guaranteed delivery with retransmission', + right: 'Best-effort, no retransmission' + }, { aspect: 'Ordering', left: 'Strict in-order delivery', right: 'No ordering guarantees' }, { aspect: 'Header size', left: '20-60 bytes', right: '8 bytes' }, - { aspect: 'Overhead', left: 'Higher (ACKs, {{flow-control|flow control}}, congestion)', right: 'Minimal (just send and hope)' } + { + aspect: 'Overhead', + left: 'Higher (ACKs, {{flow-control|flow control}}, congestion)', + right: 'Minimal (just send and hope)' + } ], useLeftWhen: [ 'You need guaranteed delivery (file transfer, web pages, email)', @@ -38,11 +50,31 @@ const vsPairs: ProtocolPair[] = [ summary: 'Standard [[tcp|TCP]] uses a single network path; [[mptcp|MPTCP]] spreads traffic across multiple paths (e.g. [[wifi|Wi-Fi]] + cellular) for better throughput and seamless {{failover|failover}}.', keyDifferences: [ - { aspect: 'Connection model', left: 'Multiple subflows across interfaces', right: 'Single path, single interface' }, - { aspect: 'Redundancy', left: 'Seamless failover between paths', right: 'Connection drops if path fails' }, - { aspect: 'Throughput', left: 'Aggregate bandwidth of all paths', right: 'Limited to single path bandwidth' }, - { aspect: 'Complexity', left: 'Complex path management and scheduling', right: 'Simple, well-understood behavior' }, - { aspect: 'Ecosystem', left: 'Growing support (Apple, Linux 5.6+)', right: 'Universal support everywhere' } + { + aspect: 'Connection model', + left: 'Multiple subflows across interfaces', + right: 'Single path, single interface' + }, + { + aspect: 'Redundancy', + left: 'Seamless failover between paths', + right: 'Connection drops if path fails' + }, + { + aspect: 'Throughput', + left: 'Aggregate bandwidth of all paths', + right: 'Limited to single path bandwidth' + }, + { + aspect: 'Complexity', + left: 'Complex path management and scheduling', + right: 'Simple, well-understood behavior' + }, + { + aspect: 'Ecosystem', + left: 'Growing support (Apple, Linux 5.6+)', + right: 'Universal support everywhere' + } ], useLeftWhen: [ 'Devices have multiple network interfaces (mobile with [[wifi|Wi-Fi]] + cellular)', @@ -63,11 +95,31 @@ const vsPairs: ProtocolPair[] = [ summary: '[[tcp|TCP]] delivers a single ordered byte stream; [[sctp|SCTP]] delivers multiple independent message streams over one association with built-in {{multi-homing|multi-homing}}.', keyDifferences: [ - { aspect: 'Data format', left: 'Message-oriented (preserves boundaries)', right: 'Byte-stream (no message boundaries)' }, - { aspect: 'Multiplexing', left: 'Multiple independent streams', right: 'Single stream ({{head-of-line-blocking|head-of-line blocking}})' }, - { aspect: 'Redundancy', left: 'Built-in multi-homing (multiple IPs)', right: 'Single [[ip|IP]] per connection' }, - { aspect: 'Connection model', left: '4-way handshake with cookie (DoS-resistant)', right: '3-way handshake' }, - { aspect: 'Ecosystem', left: 'Limited (telecom, [[webrtc|WebRTC]] data channels)', right: 'Universal support' } + { + aspect: 'Data format', + left: 'Message-oriented (preserves boundaries)', + right: 'Byte-stream (no message boundaries)' + }, + { + aspect: 'Multiplexing', + left: 'Multiple independent streams', + right: 'Single stream ({{head-of-line-blocking|head-of-line blocking}})' + }, + { + aspect: 'Redundancy', + left: 'Built-in multi-homing (multiple IPs)', + right: 'Single [[ip|IP]] per connection' + }, + { + aspect: 'Connection model', + left: '4-way handshake with cookie (DoS-resistant)', + right: '3-way handshake' + }, + { + aspect: 'Ecosystem', + left: 'Limited (telecom, [[webrtc|WebRTC]] data channels)', + right: 'Universal support' + } ], useLeftWhen: [ 'You need multiple independent streams without {{head-of-line-blocking|head-of-line blocking}}', @@ -88,11 +140,31 @@ const vsPairs: ProtocolPair[] = [ summary: 'Raw [[udp|UDP]] is a minimal, unreliable datagram service; [[quic|QUIC]] builds reliability, {{multiplexing|multiplexing}}, and {{encryption|encryption}} on top of [[udp|UDP]] to replace [[tcp|TCP]]+[[tls|TLS]].', keyDifferences: [ - { aspect: 'Reliability', left: 'Reliable delivery with retransmission', right: 'Best-effort, no guarantees' }, - { aspect: 'Encryption', left: 'Built-in [[tls|TLS]] 1.3 (always encrypted)', right: 'None (plaintext datagrams)' }, - { aspect: 'Multiplexing', left: 'Multiple independent streams', right: 'Single datagram, no streams' }, - { aspect: 'Connection model', left: '{{zero-rtt|0-RTT}}/{{one-rtt|1-RTT}} handshake', right: 'No connection setup' }, - { aspect: 'Complexity', left: 'Full transport protocol (congestion, {{flow-control|flow control}})', right: 'Minimal 8-byte header' } + { + aspect: 'Reliability', + left: 'Reliable delivery with retransmission', + right: 'Best-effort, no guarantees' + }, + { + aspect: 'Encryption', + left: 'Built-in [[tls|TLS]] 1.3 (always encrypted)', + right: 'None (plaintext datagrams)' + }, + { + aspect: 'Multiplexing', + left: 'Multiple independent streams', + right: 'Single datagram, no streams' + }, + { + aspect: 'Connection model', + left: '{{zero-rtt|0-RTT}}/{{one-rtt|1-RTT}} handshake', + right: 'No connection setup' + }, + { + aspect: 'Complexity', + left: 'Full transport protocol (congestion, {{flow-control|flow control}})', + right: 'Minimal 8-byte header' + } ], useLeftWhen: [ 'You need reliable delivery but want to avoid [[tcp|TCP]] {{head-of-line-blocking|head-of-line blocking}}', @@ -104,7 +176,7 @@ const vsPairs: ProtocolPair[] = [ 'Your protocol handles its own reliability ([[dns|DNS]], [[ntp|NTP]], custom game protocols)', 'Absolute minimum overhead per packet is critical', 'You are sending single-shot messages that do not need stream semantics', - 'Simplicity and universality outweigh [[quic|QUIC]]\'s features' + "Simplicity and universality outweigh [[quic|QUIC]]'s features" ] }, @@ -116,11 +188,31 @@ const vsPairs: ProtocolPair[] = [ summary: '[[http1|[[http1|HTTP/1]].1]] sends requests sequentially over separate connections; [[http2|HTTP/2]] multiplexes many requests over a single connection with header compression and {{server-push|server push}}.', keyDifferences: [ - { aspect: 'Multiplexing', left: 'One request per connection at a time', right: 'Many concurrent streams on one connection' }, - { aspect: 'Data format', left: 'Text-based headers', right: '{{binary-framing|Binary framing}} with {{hpack|HPACK}} compression' }, - { aspect: 'Header size', left: 'Repetitive, uncompressed headers', right: 'Compressed via {{hpack|HPACK}} (up to 90% smaller)' }, - { aspect: 'Direction', left: 'Client-initiated only', right: '{{server-push|Server push}} (proactive resource delivery)' }, - { aspect: 'Connection model', left: 'Multiple [[tcp|TCP]] connections (6 per domain)', right: 'Single [[tcp|TCP]] connection per origin' } + { + aspect: 'Multiplexing', + left: 'One request per connection at a time', + right: 'Many concurrent streams on one connection' + }, + { + aspect: 'Data format', + left: 'Text-based headers', + right: '{{binary-framing|Binary framing}} with {{hpack|HPACK}} compression' + }, + { + aspect: 'Header size', + left: 'Repetitive, uncompressed headers', + right: 'Compressed via {{hpack|HPACK}} (up to 90% smaller)' + }, + { + aspect: 'Direction', + left: 'Client-initiated only', + right: '{{server-push|Server push}} (proactive resource delivery)' + }, + { + aspect: 'Connection model', + left: 'Multiple [[tcp|TCP]] connections (6 per domain)', + right: 'Single [[tcp|TCP]] connection per origin' + } ], useLeftWhen: [ 'You are supporting very old clients or constrained devices that lack [[http2|HTTP/2]]', @@ -141,11 +233,31 @@ const vsPairs: ProtocolPair[] = [ summary: '[[http2|HTTP/2]] runs over [[tcp|TCP]] and suffers from [[tcp|TCP]]-level {{head-of-line-blocking|head-of-line blocking}}; [[http3|HTTP/3]] runs over [[quic|QUIC]] ([[udp|UDP]]-based) eliminating this and adding faster connection setup.', keyDifferences: [ - { aspect: 'Transport', left: '[[tcp|TCP]] + [[tls|TLS]] 1.2/1.3 (separate layers)', right: '[[quic|QUIC]] ([[udp|UDP]]-based, [[tls|TLS]] 1.3 built-in)' }, - { aspect: 'Multiplexing', left: 'Streams share [[tcp|TCP]] ({{head-of-line-blocking|head-of-line blocking}})', right: 'Streams independent (no cross-stream blocking)' }, - { aspect: 'Connection model', left: '{{one-rtt|1-RTT}} [[tcp|TCP]] + {{one-rtt|1-RTT}} [[tls|TLS]] = 2+ {{rtt|RTT}}', right: '{{one-rtt|1-RTT}} or {{zero-rtt|0-RTT}} (combined transport+crypto)' }, - { aspect: 'Header size', left: '{{hpack|HPACK}} compression', right: 'QPACK compression (designed for [[quic|QUIC]])' }, - { aspect: 'Ecosystem', left: 'Mature, universal support', right: 'Growing rapidly, most modern browsers support it' } + { + aspect: 'Transport', + left: '[[tcp|TCP]] + [[tls|TLS]] 1.2/1.3 (separate layers)', + right: '[[quic|QUIC]] ([[udp|UDP]]-based, [[tls|TLS]] 1.3 built-in)' + }, + { + aspect: 'Multiplexing', + left: 'Streams share [[tcp|TCP]] ({{head-of-line-blocking|head-of-line blocking}})', + right: 'Streams independent (no cross-stream blocking)' + }, + { + aspect: 'Connection model', + left: '{{one-rtt|1-RTT}} [[tcp|TCP]] + {{one-rtt|1-RTT}} [[tls|TLS]] = 2+ {{rtt|RTT}}', + right: '{{one-rtt|1-RTT}} or {{zero-rtt|0-RTT}} (combined transport+crypto)' + }, + { + aspect: 'Header size', + left: '{{hpack|HPACK}} compression', + right: 'QPACK compression (designed for [[quic|QUIC]])' + }, + { + aspect: 'Ecosystem', + left: 'Mature, universal support', + right: 'Growing rapidly, most modern browsers support it' + } ], useLeftWhen: [ 'Maximum compatibility with existing infrastructure is required', @@ -166,11 +278,31 @@ const vsPairs: ProtocolPair[] = [ summary: '[[rest|REST]] uses human-readable {{json|JSON}} over {{http-method|HTTP}} for broad compatibility; [[grpc|gRPC]] uses binary Protobuf over [[http2|HTTP/2]] for high-performance, strongly-typed service communication.', keyDifferences: [ - { aspect: 'Data format', left: 'Binary ({{protocol-buffers|Protocol Buffers}})', right: 'Text ({{json|JSON}}, {{xml|XML}})' }, - { aspect: 'Transport', left: '[[http2|HTTP/2]] only (multiplexed streams)', right: 'Any HTTP version' }, - { aspect: 'Direction', left: 'Bidirectional streaming natively', right: '{{request-response|Request-response}} only (streaming via workarounds)' }, - { aspect: 'Browser support', left: 'Requires grpc-web proxy', right: 'Native in all browsers' }, - { aspect: 'Complexity', left: 'Schema-first (.proto files, codegen)', right: 'Schema-optional, ad-hoc design common' } + { + aspect: 'Data format', + left: 'Binary ({{protocol-buffers|Protocol Buffers}})', + right: 'Text ({{json|JSON}}, {{xml|XML}})' + }, + { + aspect: 'Transport', + left: '[[http2|HTTP/2]] only (multiplexed streams)', + right: 'Any HTTP version' + }, + { + aspect: 'Direction', + left: 'Bidirectional streaming natively', + right: '{{request-response|Request-response}} only (streaming via workarounds)' + }, + { + aspect: 'Browser support', + left: 'Requires grpc-web proxy', + right: 'Native in all browsers' + }, + { + aspect: 'Complexity', + left: 'Schema-first (.proto files, codegen)', + right: 'Schema-optional, ad-hoc design common' + } ], useLeftWhen: [ 'Services communicate internally (microservice-to-microservice)', @@ -191,11 +323,31 @@ const vsPairs: ProtocolPair[] = [ summary: '[[rest|REST]] exposes fixed endpoints that return predetermined data shapes; [[graphql|GraphQL]] exposes a single endpoint where clients query exactly the fields they need.', keyDifferences: [ - { aspect: 'Data format', left: 'Client-specified query shapes', right: 'Server-defined resource shapes' }, - { aspect: 'Caching', left: 'Complex (query-level, requires tooling)', right: 'Simple (HTTP caching per URL)' }, - { aspect: 'Overhead', left: 'No over-fetching, but query parsing cost', right: 'Often over-fetches or under-fetches data' }, - { aspect: 'Direction', left: 'Queries + mutations + subscriptions', right: 'CRUD mapped to HTTP methods' }, - { aspect: 'Complexity', left: 'Schema required, resolver architecture', right: 'Simpler, convention-based' } + { + aspect: 'Data format', + left: 'Client-specified query shapes', + right: 'Server-defined resource shapes' + }, + { + aspect: 'Caching', + left: 'Complex (query-level, requires tooling)', + right: 'Simple (HTTP caching per URL)' + }, + { + aspect: 'Overhead', + left: 'No over-fetching, but query parsing cost', + right: 'Often over-fetches or under-fetches data' + }, + { + aspect: 'Direction', + left: 'Queries + mutations + subscriptions', + right: 'CRUD mapped to HTTP methods' + }, + { + aspect: 'Complexity', + left: 'Schema required, resolver architecture', + right: 'Simpler, convention-based' + } ], useLeftWhen: [ 'Clients need different slices of data (mobile vs desktop vs watch)', @@ -216,10 +368,26 @@ const vsPairs: ProtocolPair[] = [ summary: '[[websockets|WebSocket]] provides {{full-duplex|full-duplex}} bidirectional communication; [[sse|SSE]] provides server-to-client streaming over plain {{http-method|HTTP}} with automatic reconnection.', keyDifferences: [ - { aspect: 'Direction', left: 'Server-to-client only', right: '{{full-duplex|Full-duplex}} bidirectional' }, - { aspect: 'Transport', left: 'Standard HTTP (works with proxies, CDNs)', right: 'Upgraded connection (custom framing)' }, - { aspect: 'Complexity', left: 'Simple (EventSource API, text-based)', right: 'More complex (handshake, binary frames)' }, - { aspect: 'Reliability', left: 'Built-in auto-reconnection and last-event-ID', right: 'Manual reconnection logic needed' }, + { + aspect: 'Direction', + left: 'Server-to-client only', + right: '{{full-duplex|Full-duplex}} bidirectional' + }, + { + aspect: 'Transport', + left: 'Standard HTTP (works with proxies, CDNs)', + right: 'Upgraded connection (custom framing)' + }, + { + aspect: 'Complexity', + left: 'Simple (EventSource API, text-based)', + right: 'More complex (handshake, binary frames)' + }, + { + aspect: 'Reliability', + left: 'Built-in auto-reconnection and last-event-ID', + right: 'Manual reconnection logic needed' + }, { aspect: 'Data format', left: 'Text only (UTF-8)', right: 'Text and binary frames' } ], useLeftWhen: [ @@ -241,11 +409,31 @@ const vsPairs: ProtocolPair[] = [ summary: '[[graphql|GraphQL]] lets clients flexibly query for exactly the data they need over {{http-method|HTTP}}; [[grpc|gRPC]] provides high-performance, schema-strict {{rpc|RPC}} with bidirectional streaming.', keyDifferences: [ - { aspect: 'Data format', left: '{{json|JSON}} response, query language', right: 'Binary {{protocol-buffers|Protocol Buffers}}' }, - { aspect: 'Direction', left: '{{request-response|Request-response}} + subscriptions', right: 'Unary, server/client/bidirectional streaming' }, - { aspect: 'Browser support', left: 'Native (standard HTTP POST)', right: 'Requires grpc-web proxy' }, - { aspect: 'Complexity', left: 'Schema + resolvers, flexible queries', right: 'Schema + codegen, strict contracts' }, - { aspect: 'Overhead', left: '{{json|JSON}} text (human-readable)', right: 'Binary (compact, ~5-10x smaller)' } + { + aspect: 'Data format', + left: '{{json|JSON}} response, query language', + right: 'Binary {{protocol-buffers|Protocol Buffers}}' + }, + { + aspect: 'Direction', + left: '{{request-response|Request-response}} + subscriptions', + right: 'Unary, server/client/bidirectional streaming' + }, + { + aspect: 'Browser support', + left: 'Native (standard HTTP POST)', + right: 'Requires grpc-web proxy' + }, + { + aspect: 'Complexity', + left: 'Schema + resolvers, flexible queries', + right: 'Schema + codegen, strict contracts' + }, + { + aspect: 'Overhead', + left: '{{json|JSON}} text (human-readable)', + right: 'Binary (compact, ~5-10x smaller)' + } ], useLeftWhen: [ 'Clients need flexible, ad-hoc queries over complex data graphs', @@ -266,11 +454,31 @@ const vsPairs: ProtocolPair[] = [ summary: '[[http1|[[http1|HTTP/1]].1]] is the text-based, universally supported baseline; [[http3|HTTP/3]] is the latest evolution running over [[quic|QUIC]] with {{multiplexing|multiplexing}}, {{zero-rtt|0-RTT}}, and built-in {{encryption|encryption}}.', keyDifferences: [ - { aspect: 'Transport', left: '[[tcp|TCP]] (1+ {{rtt|RTT}} handshake)', right: '[[quic|QUIC]] over [[udp|UDP]] ({{zero-rtt|0-RTT}} possible)' }, - { aspect: 'Multiplexing', left: 'No multiplexing (one request per connection)', right: 'Full stream multiplexing (no {{head-of-line-blocking|head-of-line blocking}})' }, - { aspect: 'Header size', left: 'Uncompressed text headers', right: 'QPACK compressed binary headers' }, - { aspect: 'Encryption', left: 'Optional (HTTP or HTTPS)', right: 'Always encrypted ([[tls|TLS]] 1.3 built into [[quic|QUIC]])' }, - { aspect: 'Ecosystem', left: 'Universal β€” every device and proxy supports it', right: 'Modern browsers and CDNs; some firewalls block [[udp|UDP]]' } + { + aspect: 'Transport', + left: '[[tcp|TCP]] (1+ {{rtt|RTT}} handshake)', + right: '[[quic|QUIC]] over [[udp|UDP]] ({{zero-rtt|0-RTT}} possible)' + }, + { + aspect: 'Multiplexing', + left: 'No multiplexing (one request per connection)', + right: 'Full stream multiplexing (no {{head-of-line-blocking|head-of-line blocking}})' + }, + { + aspect: 'Header size', + left: 'Uncompressed text headers', + right: 'QPACK compressed binary headers' + }, + { + aspect: 'Encryption', + left: 'Optional (HTTP or HTTPS)', + right: 'Always encrypted ([[tls|TLS]] 1.3 built into [[quic|QUIC]])' + }, + { + aspect: 'Ecosystem', + left: 'Universal β€” every device and proxy supports it', + right: 'Modern browsers and CDNs; some firewalls block [[udp|UDP]]' + } ], useLeftWhen: [ 'Maximum backward compatibility is the top priority', @@ -291,11 +499,31 @@ const vsPairs: ProtocolPair[] = [ summary: '[[http2|HTTP/2]] provides multiplexed {{request-response|request-response}} with {{server-push|server push}} over a single connection; [[websockets|WebSocket]] provides a persistent, {{full-duplex|full-duplex}} message channel.', keyDifferences: [ - { aspect: 'Direction', left: '{{request-response|Request-response}} + {{server-push|server push}}', right: '{{full-duplex|Full-duplex}} persistent channel' }, - { aspect: 'Data format', left: 'HTTP semantics (headers, status codes)', right: 'Raw frames (text or binary)' }, - { aspect: 'Multiplexing', left: 'Many concurrent request/response streams', right: 'Single bidirectional channel' }, - { aspect: 'Caching', left: 'Standard HTTP caching works', right: 'No HTTP caching (custom protocol)' }, - { aspect: 'Complexity', left: 'Standard HTTP (works with existing tooling)', right: 'Requires upgrade handshake, custom framing' } + { + aspect: 'Direction', + left: '{{request-response|Request-response}} + {{server-push|server push}}', + right: '{{full-duplex|Full-duplex}} persistent channel' + }, + { + aspect: 'Data format', + left: 'HTTP semantics (headers, status codes)', + right: 'Raw frames (text or binary)' + }, + { + aspect: 'Multiplexing', + left: 'Many concurrent request/response streams', + right: 'Single bidirectional channel' + }, + { + aspect: 'Caching', + left: 'Standard HTTP caching works', + right: 'No HTTP caching (custom protocol)' + }, + { + aspect: 'Complexity', + left: 'Standard HTTP (works with existing tooling)', + right: 'Requires upgrade handshake, custom framing' + } ], useLeftWhen: [ 'Your communication follows {{request-response|request-response}} patterns (APIs, page loads)', @@ -316,11 +544,27 @@ const vsPairs: ProtocolPair[] = [ summary: '[[rest|REST]] follows a {{stateless|stateless}} {{request-response|request-response}} model ideal for {{crud|CRUD}} operations; [[websockets|WebSocket]] maintains a persistent connection for real-time bidirectional communication.', keyDifferences: [ - { aspect: 'Statefulness', left: '{{stateless|Stateless}} (each request is independent)', right: '{{stateful|Stateful}} (persistent connection)' }, - { aspect: 'Direction', left: 'Client-initiated requests only', right: '{{full-duplex|Full-duplex}} (either side can send anytime)' }, + { + aspect: 'Statefulness', + left: '{{stateless|Stateless}} (each request is independent)', + right: '{{stateful|Stateful}} (persistent connection)' + }, + { + aspect: 'Direction', + left: 'Client-initiated requests only', + right: '{{full-duplex|Full-duplex}} (either side can send anytime)' + }, { aspect: 'Caching', left: 'Built-in HTTP caching', right: 'No caching (real-time stream)' }, - { aspect: 'Overhead', left: 'Full HTTP headers per request', right: 'Minimal framing after handshake (2-14 bytes)' }, - { aspect: 'Complexity', left: 'Simple, well-understood conventions', right: 'Requires connection management and reconnection logic' } + { + aspect: 'Overhead', + left: 'Full HTTP headers per request', + right: 'Minimal framing after handshake (2-14 bytes)' + }, + { + aspect: 'Complexity', + left: 'Simple, well-understood conventions', + right: 'Requires connection management and reconnection logic' + } ], useLeftWhen: [ 'Your operations are CRUD-style (create, read, update, delete)', @@ -341,9 +585,21 @@ const vsPairs: ProtocolPair[] = [ summary: '[[graphql|GraphQL]] lets clients query exactly the data they need via flexible queries; [[sse|SSE]] provides a simple server-push stream for real-time updates over {{http-method|HTTP}}.', keyDifferences: [ - { aspect: 'Direction', left: '{{request-response|Request-response}} + subscriptions', right: 'Server-to-client push only' }, - { aspect: 'Data format', left: 'Client-defined query shapes ({{json|JSON}})', right: 'Server-defined event stream (text)' }, - { aspect: 'Complexity', left: 'Schema, resolvers, query parsing', right: 'Simple EventSource API' }, + { + aspect: 'Direction', + left: '{{request-response|Request-response}} + subscriptions', + right: 'Server-to-client push only' + }, + { + aspect: 'Data format', + left: 'Client-defined query shapes ({{json|JSON}})', + right: 'Server-defined event stream (text)' + }, + { + aspect: 'Complexity', + left: 'Schema, resolvers, query parsing', + right: 'Simple EventSource API' + }, { aspect: 'Caching', left: 'Complex (query-level)', right: 'HTTP-level caching possible' }, { aspect: 'Browser support', left: 'Requires fetch/library', right: 'Native EventSource API' } ], @@ -366,11 +622,31 @@ const vsPairs: ProtocolPair[] = [ summary: '[[rest|REST]] is an architectural style defining how to structure APIs; [[http2|HTTP/2]] is a transport protocol that improves how {{http-method|HTTP}} requests are delivered β€” they operate at different levels and are not direct alternatives. They are complementary: [[rest|REST]] APIs can (and commonly do) run over [[http2|HTTP/2]], gaining {{multiplexing|multiplexing}}, header compression, and {{server-push|server push}} without any changes to {{api|API}} design.', keyDifferences: [ - { aspect: 'Multiplexing', left: 'Multiple concurrent streams natively', right: 'One request per connection (uses multiple connections)' }, - { aspect: 'Direction', left: '{{server-push|Server push}} for proactive delivery', right: 'Client-initiated requests only' }, - { aspect: 'Header size', left: '{{hpack|HPACK}} compressed (binary)', right: 'Full text headers repeated per request' }, - { aspect: 'Data format', left: '{{binary-framing|Binary framing}} layer', right: 'Text-based HTTP semantics' }, - { aspect: 'Complexity', left: 'Requires [[tls|TLS]] in practice, binary debugging', right: 'Simple, human-readable, curl-friendly' } + { + aspect: 'Multiplexing', + left: 'Multiple concurrent streams natively', + right: 'One request per connection (uses multiple connections)' + }, + { + aspect: 'Direction', + left: '{{server-push|Server push}} for proactive delivery', + right: 'Client-initiated requests only' + }, + { + aspect: 'Header size', + left: '{{hpack|HPACK}} compressed (binary)', + right: 'Full text headers repeated per request' + }, + { + aspect: 'Data format', + left: '{{binary-framing|Binary framing}} layer', + right: 'Text-based HTTP semantics' + }, + { + aspect: 'Complexity', + left: 'Requires [[tls|TLS]] in practice, binary debugging', + right: 'Simple, human-readable, curl-friendly' + } ], useLeftWhen: [ 'Many resources are loaded concurrently (web pages with dozens of assets)', @@ -394,11 +670,31 @@ const vsPairs: ProtocolPair[] = [ summary: '[[mqtt|MQTT]] is ultra-lightweight pub/sub designed for constrained IoT devices; [[amqp|AMQP]] is a feature-rich {{broker|message broker}} protocol for enterprise messaging with routing, transactions, and delivery guarantees.', keyDifferences: [ - { aspect: 'Overhead', left: 'Feature-rich (higher overhead)', right: 'Minimal (2-byte header possible)' }, - { aspect: 'Data format', left: 'Binary with rich semantics', right: 'Binary with simple topic-based pub/sub' }, - { aspect: 'Reliability', left: 'Transactions, dead-lettering, acknowledgments', right: 'QoS 0/1/2 (fire-forget to exactly-once)' }, - { aspect: 'Complexity', left: 'Exchanges, queues, bindings, routing keys', right: 'Simple topic hierarchy with wildcards' }, - { aspect: 'Ecosystem', left: 'RabbitMQ, enterprise integration', right: 'Mosquitto, AWS IoT, Azure IoT Hub' } + { + aspect: 'Overhead', + left: 'Feature-rich (higher overhead)', + right: 'Minimal (2-byte header possible)' + }, + { + aspect: 'Data format', + left: 'Binary with rich semantics', + right: 'Binary with simple topic-based pub/sub' + }, + { + aspect: 'Reliability', + left: 'Transactions, dead-lettering, acknowledgments', + right: 'QoS 0/1/2 (fire-forget to exactly-once)' + }, + { + aspect: 'Complexity', + left: 'Exchanges, queues, bindings, routing keys', + right: 'Simple topic hierarchy with wildcards' + }, + { + aspect: 'Ecosystem', + left: 'RabbitMQ, enterprise integration', + right: 'Mosquitto, AWS IoT, Azure IoT Hub' + } ], useLeftWhen: [ 'You need complex routing (topic, direct, fanout, headers exchange)', @@ -419,11 +715,31 @@ const vsPairs: ProtocolPair[] = [ summary: '[[amqp|AMQP]] is a binary, feature-complete {{broker|message broker}} protocol; [[stomp|STOMP]] is a text-based, deliberately simple messaging protocol designed for easy client implementation.', keyDifferences: [ - { aspect: 'Data format', left: 'Binary with rich type system', right: 'Text-based (like HTTP, human-readable)' }, - { aspect: 'Complexity', left: 'Exchanges, queues, bindings, routing', right: 'Simple SEND/SUBSCRIBE/UNSUBSCRIBE' }, - { aspect: 'Reliability', left: 'Transactions, publisher confirms, dead-lettering', right: 'Basic acknowledgments only' }, - { aspect: 'Browser support', left: 'Requires [[amqp|AMQP]] client library', right: 'Easy over [[websockets|WebSocket]] (text protocol)' }, - { aspect: 'Ecosystem', left: 'RabbitMQ, Qpid, Azure Service Bus', right: 'ActiveMQ, RabbitMQ ([[stomp|STOMP]] plugin)' } + { + aspect: 'Data format', + left: 'Binary with rich type system', + right: 'Text-based (like HTTP, human-readable)' + }, + { + aspect: 'Complexity', + left: 'Exchanges, queues, bindings, routing', + right: 'Simple SEND/SUBSCRIBE/UNSUBSCRIBE' + }, + { + aspect: 'Reliability', + left: 'Transactions, publisher confirms, dead-lettering', + right: 'Basic acknowledgments only' + }, + { + aspect: 'Browser support', + left: 'Requires [[amqp|AMQP]] client library', + right: 'Easy over [[websockets|WebSocket]] (text protocol)' + }, + { + aspect: 'Ecosystem', + left: 'RabbitMQ, Qpid, Azure Service Bus', + right: 'ActiveMQ, RabbitMQ ([[stomp|STOMP]] plugin)' + } ], useLeftWhen: [ 'You need advanced routing, transactions, and delivery guarantees', @@ -444,11 +760,27 @@ const vsPairs: ProtocolPair[] = [ summary: '[[mqtt|MQTT]] is a pub/sub protocol connecting many devices through a central broker; [[coap|CoAP]] is a {{request-response|request-response}} protocol for direct device-to-device communication modeled after {{http-method|HTTP}}.', keyDifferences: [ - { aspect: 'Connection model', left: '{{request-response|Request-response}} (like HTTP)', right: 'Publish-subscribe via broker' }, - { aspect: 'Transport', left: '[[udp|UDP]] (connectionless)', right: '[[tcp|TCP]] (persistent connection to broker)' }, - { aspect: 'Direction', left: 'Client-server (device to device)', right: 'Many-to-many via central broker' }, + { + aspect: 'Connection model', + left: '{{request-response|Request-response}} (like HTTP)', + right: 'Publish-subscribe via broker' + }, + { + aspect: 'Transport', + left: '[[udp|UDP]] (connectionless)', + right: '[[tcp|TCP]] (persistent connection to broker)' + }, + { + aspect: 'Direction', + left: 'Client-server (device to device)', + right: 'Many-to-many via central broker' + }, { aspect: 'Overhead', left: '4-byte header, compact binary', right: '2-byte minimum header' }, - { aspect: 'Complexity', left: '[[rest|REST]]-like (GET, PUT, POST, DELETE)', right: 'Pub/sub (CONNECT, PUBLISH, SUBSCRIBE)' } + { + aspect: 'Complexity', + left: '[[rest|REST]]-like (GET, PUT, POST, DELETE)', + right: 'Pub/sub (CONNECT, PUBLISH, SUBSCRIBE)' + } ], useLeftWhen: [ 'Devices communicate directly without a central broker', @@ -469,11 +801,31 @@ const vsPairs: ProtocolPair[] = [ summary: '[[stomp|STOMP]] is a minimal text-based messaging protocol for queue/{{topic|topic}} messaging; [[xmpp|XMPP]] is a rich {{xml|XML}}-based protocol for presence-aware, federated real-time communication.', keyDifferences: [ - { aspect: 'Data format', left: 'Simple text frames (like HTTP)', right: '{{xml|XML}} stanzas (verbose but extensible)' }, - { aspect: 'Complexity', left: 'Minimal (SEND, SUBSCRIBE, {{ack|ACK}})', right: 'Rich (presence, roster, multi-user chat, extensions)' }, - { aspect: 'Direction', left: 'Queue/topic messaging via broker', right: '{{peer-to-peer|Peer-to-peer}} with optional server federation' }, - { aspect: 'Ecosystem', left: 'ActiveMQ, RabbitMQ [[stomp|STOMP]] plugin', right: 'ejabberd, Prosody, Openfire' }, - { aspect: 'Standardization', left: 'Simple spec, few extensions', right: 'Hundreds of XEPs (extension protocols)' } + { + aspect: 'Data format', + left: 'Simple text frames (like HTTP)', + right: '{{xml|XML}} stanzas (verbose but extensible)' + }, + { + aspect: 'Complexity', + left: 'Minimal (SEND, SUBSCRIBE, {{ack|ACK}})', + right: 'Rich (presence, roster, multi-user chat, extensions)' + }, + { + aspect: 'Direction', + left: 'Queue/topic messaging via broker', + right: '{{peer-to-peer|Peer-to-peer}} with optional server federation' + }, + { + aspect: 'Ecosystem', + left: 'ActiveMQ, RabbitMQ [[stomp|STOMP]] plugin', + right: 'ejabberd, Prosody, Openfire' + }, + { + aspect: 'Standardization', + left: 'Simple spec, few extensions', + right: 'Hundreds of XEPs (extension protocols)' + } ], useLeftWhen: [ 'You need simple, lightweight queue or topic messaging', @@ -494,11 +846,31 @@ const vsPairs: ProtocolPair[] = [ summary: '[[amqp|AMQP]] brokers (like RabbitMQ) route individual messages with rich delivery semantics; [[kafka|Kafka]] is a distributed log that persists ordered event streams for replay and high-throughput processing.', keyDifferences: [ - { aspect: 'Data format', left: '{{broker|Message broker}} (consume = delete)', right: 'Append-only log (consume = read offset)' }, - { aspect: 'Ordering', left: 'Per-queue ordering', right: 'Per-partition ordering (scalable)' }, - { aspect: 'Reliability', left: 'Per-message acknowledgments', right: '{{offset|Offset}}-based consumer tracking' }, - { aspect: 'Complexity', left: 'Rich routing (exchanges, bindings)', right: 'Simple topic/partition model' }, - { aspect: 'Throughput', left: 'Lower (routing overhead per message)', right: 'Very high (sequential I/O, batching)' } + { + aspect: 'Data format', + left: '{{broker|Message broker}} (consume = delete)', + right: 'Append-only log (consume = read offset)' + }, + { + aspect: 'Ordering', + left: 'Per-queue ordering', + right: 'Per-partition ordering (scalable)' + }, + { + aspect: 'Reliability', + left: 'Per-message acknowledgments', + right: '{{offset|Offset}}-based consumer tracking' + }, + { + aspect: 'Complexity', + left: 'Rich routing (exchanges, bindings)', + right: 'Simple topic/partition model' + }, + { + aspect: 'Throughput', + left: 'Lower (routing overhead per message)', + right: 'Very high (sequential I/O, batching)' + } ], useLeftWhen: [ 'You need complex message routing (fanout, topic, header-based)', @@ -520,13 +892,29 @@ const vsPairs: ProtocolPair[] = [ ids: ['dash', 'hls'], type: 'vs', summary: - '[[hls|HLS]] is {{apple|Apple}}\'s {{http-method|HTTP}}-based adaptive streaming protocol with near-universal player support; [[dash|DASH]] is the open, {{codec|codec}}-agnostic {{mpeg-org|MPEG}} standard for adaptive streaming.', + "[[hls|HLS]] is {{apple|Apple}}'s {{http-method|HTTP}}-based adaptive streaming protocol with near-universal player support; [[dash|DASH]] is the open, {{codec|codec}}-agnostic {{mpeg-org|MPEG}} standard for adaptive streaming.", keyDifferences: [ - { aspect: 'Standardization', left: 'Open MPEG standard (ISO/IEC 23009)', right: 'Apple proprietary (widely adopted)' }, + { + aspect: 'Standardization', + left: 'Open MPEG standard (ISO/IEC 23009)', + right: 'Apple proprietary (widely adopted)' + }, { aspect: 'Data format', left: 'MPD manifest ({{xml|XML}})', right: 'M3U8 playlist (text)' }, - { aspect: 'Complexity', left: 'Codec-agnostic, more flexible', right: 'Simpler, opinionated defaults' }, - { aspect: 'Browser support', left: 'Requires MSE/JavaScript player', right: 'Native in Safari/iOS, MSE elsewhere' }, - { aspect: 'Ecosystem', left: 'YouTube, Netflix, Disney+', right: 'Apple TV+, Twitch, most live streams' } + { + aspect: 'Complexity', + left: 'Codec-agnostic, more flexible', + right: 'Simpler, opinionated defaults' + }, + { + aspect: 'Browser support', + left: 'Requires MSE/JavaScript player', + right: 'Native in Safari/iOS, MSE elsewhere' + }, + { + aspect: 'Ecosystem', + left: 'YouTube, Netflix, Disney+', + right: 'Apple TV+, Twitch, most live streams' + } ], useLeftWhen: [ 'You need codec flexibility (AV1, VP9) beyond H.264/H.265', @@ -547,11 +935,31 @@ const vsPairs: ProtocolPair[] = [ summary: '[[rtp|RTP]] delivers real-time audio/video over [[udp|UDP]] for interactive communication; [[rtmp|RTMP]] delivers live streams over [[tcp|TCP]] for broadcasting to media servers.', keyDifferences: [ - { aspect: 'Transport', left: '[[udp|UDP]] (low latency, tolerates loss)', right: '[[tcp|TCP]] (reliable, higher latency)' }, - { aspect: 'Direction', left: '{{peer-to-peer|Peer-to-peer}} or multicast', right: 'Client-to-server (ingest)' }, - { aspect: 'Overhead', left: 'Minimal [[rtp|RTP]] header (12 bytes)', right: 'Chunked message format with handshake' }, - { aspect: 'Complexity', left: 'Paired with {{rtcp|RTCP}} for feedback', right: 'Self-contained streaming protocol' }, - { aspect: 'Ecosystem', left: '[[webrtc|WebRTC]], VoIP, video conferencing', right: 'OBS, Twitch ingest, Facebook Live' } + { + aspect: 'Transport', + left: '[[udp|UDP]] (low latency, tolerates loss)', + right: '[[tcp|TCP]] (reliable, higher latency)' + }, + { + aspect: 'Direction', + left: '{{peer-to-peer|Peer-to-peer}} or multicast', + right: 'Client-to-server (ingest)' + }, + { + aspect: 'Overhead', + left: 'Minimal [[rtp|RTP]] header (12 bytes)', + right: 'Chunked message format with handshake' + }, + { + aspect: 'Complexity', + left: 'Paired with {{rtcp|RTCP}} for feedback', + right: 'Self-contained streaming protocol' + }, + { + aspect: 'Ecosystem', + left: '[[webrtc|WebRTC]], VoIP, video conferencing', + right: 'OBS, Twitch ingest, Facebook Live' + } ], useLeftWhen: [ 'You are building interactive audio/video (calls, conferences)', @@ -572,11 +980,31 @@ const vsPairs: ProtocolPair[] = [ summary: '[[sip|SIP]] is the traditional telephony {{signaling|signaling}} protocol for {{voip|VoIP}} and video calls; [[webrtc|WebRTC]] provides browser-native {{peer-to-peer|peer-to-peer}} real-time communication without plugins.', keyDifferences: [ - { aspect: 'Browser support', left: 'Requires [[sip|SIP]] client/softphone', right: 'Native in all modern browsers' }, - { aspect: 'Connection model', left: 'Client-server via [[sip|SIP]] proxy/registrar', right: '{{peer-to-peer|Peer-to-peer}} with STUN/TURN fallback' }, - { aspect: 'Complexity', left: 'Mature telecom stack ([[sip|SIP]]/[[sdp|SDP]]/[[rtp|RTP]])', right: 'Integrated (ICE, {{dtls|DTLS}}-{{srtp|SRTP}}, [[sctp|SCTP]])' }, - { aspect: 'Ecosystem', left: 'Asterisk, FreeSWITCH, telecom carriers', right: 'Browsers, Twilio, Daily, Jitsi' }, - { aspect: 'Standardization', left: '{{ietf|IETF}} [[rfc:3261|RFC 3261]] (telecom-oriented)', right: '{{w3c|W3C}} + {{ietf|IETF}} (web-oriented)' } + { + aspect: 'Browser support', + left: 'Requires [[sip|SIP]] client/softphone', + right: 'Native in all modern browsers' + }, + { + aspect: 'Connection model', + left: 'Client-server via [[sip|SIP]] proxy/registrar', + right: '{{peer-to-peer|Peer-to-peer}} with STUN/TURN fallback' + }, + { + aspect: 'Complexity', + left: 'Mature telecom stack ([[sip|SIP]]/[[sdp|SDP]]/[[rtp|RTP]])', + right: 'Integrated (ICE, {{dtls|DTLS}}-{{srtp|SRTP}}, [[sctp|SCTP]])' + }, + { + aspect: 'Ecosystem', + left: 'Asterisk, FreeSWITCH, telecom carriers', + right: 'Browsers, Twilio, Daily, Jitsi' + }, + { + aspect: 'Standardization', + left: '{{ietf|IETF}} [[rfc:3261|RFC 3261]] (telecom-oriented)', + right: '{{w3c|W3C}} + {{ietf|IETF}} (web-oriented)' + } ], useLeftWhen: [ 'You are integrating with existing telephony infrastructure (PBX, PSTN)', @@ -597,11 +1025,31 @@ const vsPairs: ProtocolPair[] = [ summary: '[[rtmp|RTMP]] is used for live stream ingest from encoders to servers; [[hls|HLS]] is used for delivery from servers to viewers via {{http-method|HTTP}}-based adaptive streaming.', keyDifferences: [ - { aspect: 'Transport', left: 'HTTP (segment-based delivery)', right: '[[tcp|TCP]] (persistent chunked stream)' }, - { aspect: 'Direction', left: 'Server-to-viewer (playback)', right: 'Encoder-to-server (ingest/publish)' }, - { aspect: 'Overhead', left: 'Segment-based (~2-6s chunks)', right: 'Low-latency continuous stream' }, - { aspect: 'Browser support', left: 'Native in Safari, MSE elsewhere', right: 'No browser support (Flash deprecated)' }, - { aspect: 'Ecosystem', left: 'Viewers: all devices and CDNs', right: 'Ingest: OBS, Wirecast, FFmpeg' } + { + aspect: 'Transport', + left: 'HTTP (segment-based delivery)', + right: '[[tcp|TCP]] (persistent chunked stream)' + }, + { + aspect: 'Direction', + left: 'Server-to-viewer (playback)', + right: 'Encoder-to-server (ingest/publish)' + }, + { + aspect: 'Overhead', + left: 'Segment-based (~2-6s chunks)', + right: 'Low-latency continuous stream' + }, + { + aspect: 'Browser support', + left: 'Native in Safari, MSE elsewhere', + right: 'No browser support (Flash deprecated)' + }, + { + aspect: 'Ecosystem', + left: 'Viewers: all devices and CDNs', + right: 'Ingest: OBS, Wirecast, FFmpeg' + } ], useLeftWhen: [ 'You are delivering video to end viewers (playback side)', @@ -622,11 +1070,31 @@ const vsPairs: ProtocolPair[] = [ summary: '[[rtmp|RTMP]] is a persistent [[tcp|TCP]]-based protocol for live stream ingest; [[dash|DASH]] is an {{http-method|HTTP}}-based adaptive streaming protocol for scalable video delivery to viewers.', keyDifferences: [ - { aspect: 'Transport', left: 'HTTP (segment downloads)', right: '[[tcp|TCP]] (persistent connection)' }, - { aspect: 'Direction', left: 'Server-to-viewer (delivery)', right: 'Encoder-to-server (ingest)' }, - { aspect: 'Standardization', left: 'Open MPEG standard', right: 'Originally Adobe (now open)' }, - { aspect: 'Complexity', left: 'Adaptive bitrate with MPD manifests', right: 'Simple publish/play model' }, - { aspect: 'Browser support', left: 'Via MSE/JavaScript player', right: 'No browser support (Flash deprecated)' } + { + aspect: 'Transport', + left: 'HTTP (segment downloads)', + right: '[[tcp|TCP]] (persistent connection)' + }, + { + aspect: 'Direction', + left: 'Server-to-viewer (delivery)', + right: 'Encoder-to-server (ingest)' + }, + { + aspect: 'Standardization', + left: 'Open MPEG standard', + right: 'Originally Adobe (now open)' + }, + { + aspect: 'Complexity', + left: 'Adaptive bitrate with MPD manifests', + right: 'Simple publish/play model' + }, + { + aspect: 'Browser support', + left: 'Via MSE/JavaScript player', + right: 'No browser support (Flash deprecated)' + } ], useLeftWhen: [ 'You are building the viewer-facing delivery pipeline', @@ -650,11 +1118,31 @@ const vsPairs: ProtocolPair[] = [ summary: '[[tls|TLS]] secures arbitrary application protocols transparently (HTTPS, SMTPS); [[ssh|SSH]] provides an encrypted channel specifically for remote shell access, file transfer, and {{port-forwarding|port forwarding}}.', keyDifferences: [ - { aspect: 'Connection model', left: 'Interactive shell + channels (multiplex)', right: 'Transparent wrapper around any protocol' }, - { aspect: 'Complexity', left: 'Built-in auth, shell, file transfer, tunneling', right: 'Pure encryption/auth layer (no application features)' }, - { aspect: 'Data format', left: 'Channel-based (shell, SCP, SFTP, port forward)', right: 'Stream encryption (application handles framing)' }, - { aspect: 'Ecosystem', left: 'OpenSSH, PuTTY, remote administration', right: 'Web browsers, email servers, API gateways' }, - { aspect: 'Browser support', left: 'No browser support (terminal clients)', right: 'Native in all browsers (HTTPS)' } + { + aspect: 'Connection model', + left: 'Interactive shell + channels (multiplex)', + right: 'Transparent wrapper around any protocol' + }, + { + aspect: 'Complexity', + left: 'Built-in auth, shell, file transfer, tunneling', + right: 'Pure encryption/auth layer (no application features)' + }, + { + aspect: 'Data format', + left: 'Channel-based (shell, SCP, SFTP, port forward)', + right: 'Stream encryption (application handles framing)' + }, + { + aspect: 'Ecosystem', + left: 'OpenSSH, PuTTY, remote administration', + right: 'Web browsers, email servers, API gateways' + }, + { + aspect: 'Browser support', + left: 'No browser support (terminal clients)', + right: 'Native in all browsers (HTTPS)' + } ], useLeftWhen: [ 'You need remote shell access or command execution on servers', @@ -666,7 +1154,7 @@ const vsPairs: ProtocolPair[] = [ 'You are securing a web protocol (HTTP, [[smtp|SMTP]], [[ftp|FTP]], [[mqtt|MQTT]])', 'Browser clients must connect securely without special software', 'Your application needs transparent encryption without changing its protocol', - 'Certificate-based trust via public CAs (Let\'s Encrypt) is preferred' + "Certificate-based trust via public CAs (Let's Encrypt) is preferred" ] }, @@ -696,7 +1184,8 @@ const vsPairs: ProtocolPair[] = [ { aspect: 'Command format', left: 'Tagged commands (A001 {{imap-select|SELECT}} INBOX) β€” enables {{pipelining|pipelining}}', - right: 'Sequential commands ({{ehlo|EHLO}} β†’ {{smtp-mail-from|MAIL FROM}} β†’ {{smtp-data|DATA}})' + right: + 'Sequential commands ({{ehlo|EHLO}} β†’ {{smtp-mail-from|MAIL FROM}} β†’ {{smtp-data|DATA}})' }, { aspect: 'Default port', @@ -726,11 +1215,31 @@ const vsPairs: ProtocolPair[] = [ summary: '[[ethernet|Ethernet]] uses cables for reliable, high-speed {{lan|LAN}} connectivity; [[wifi|Wi-Fi]] uses radio waves for wireless flexibility at the cost of shared {{airtime|airtime}} and lower throughput.', keyDifferences: [ - { aspect: 'Medium', left: 'Copper/fiber cables (dedicated per link)', right: 'Radio waves (shared airtime)' }, - { aspect: 'Access control', left: 'Full duplex on switched links (no collisions)', right: 'CSMA/{{certificate-authority|CA}} β€” collision avoidance on shared medium' }, - { aspect: 'Speed (typical)', left: '1-100 Gbps', right: '100 Mbps–9.6 Gbps ([[wifi|Wi-Fi]] 6E/7)' }, - { aspect: 'Security', left: 'Physical access required (inherently private)', right: '{{encryption|Encryption}} mandatory (WPA2/WPA3)' }, - { aspect: 'Addressing', left: '2 MAC addresses per frame (src, dst)', right: '3-4 MAC addresses per frame (RA, TA, DA, SA)' } + { + aspect: 'Medium', + left: 'Copper/fiber cables (dedicated per link)', + right: 'Radio waves (shared airtime)' + }, + { + aspect: 'Access control', + left: 'Full duplex on switched links (no collisions)', + right: 'CSMA/{{certificate-authority|CA}} β€” collision avoidance on shared medium' + }, + { + aspect: 'Speed (typical)', + left: '1-100 Gbps', + right: '100 Mbps–9.6 Gbps ([[wifi|Wi-Fi]] 6E/7)' + }, + { + aspect: 'Security', + left: 'Physical access required (inherently private)', + right: '{{encryption|Encryption}} mandatory (WPA2/WPA3)' + }, + { + aspect: 'Addressing', + left: '2 MAC addresses per frame (src, dst)', + right: '3-4 MAC addresses per frame (RA, TA, DA, SA)' + } ], useLeftWhen: [ 'Maximum speed and minimum latency are required (data centers, server rooms)', @@ -752,11 +1261,31 @@ const vsPairs: ProtocolPair[] = [ summary: '[[ip|IPv4]] uses 32-bit addresses (4.3 billion) and has served since 1981; [[ipv6|IPv6]] uses 128-bit addresses (340 undecillion) with a simplified header and no {{nat|NAT}} needed.', keyDifferences: [ - { aspect: 'Address size', left: '32-bit (192.168.1.1) β€” 4.3 billion addresses', right: '128-bit (2001:db8::1) β€” 340 undecillion addresses' }, - { aspect: 'Header', left: 'Variable 20-60 bytes, header checksum, options', right: 'Fixed 40 bytes, no checksum, extension header chain' }, - { aspect: 'Fragmentation', left: 'Routers and hosts can fragment', right: 'Only source host fragments ({{path-mtu-discovery|Path MTU Discovery}})' }, - { aspect: 'Address resolution', left: '[[arp|ARP]] broadcasts (FF:FF:FF:FF:FF:FF)', right: '{{ndp|NDP}} solicited-node multicast (far more efficient)' }, - { aspect: 'Auto-configuration', left: 'Requires [[dhcp|DHCP]] server', right: '{{slaac|SLAAC}} β€” hosts self-configure from router prefix' } + { + aspect: 'Address size', + left: '32-bit (192.168.1.1) β€” 4.3 billion addresses', + right: '128-bit (2001:db8::1) β€” 340 undecillion addresses' + }, + { + aspect: 'Header', + left: 'Variable 20-60 bytes, header checksum, options', + right: 'Fixed 40 bytes, no checksum, extension header chain' + }, + { + aspect: 'Fragmentation', + left: 'Routers and hosts can fragment', + right: 'Only source host fragments ({{path-mtu-discovery|Path MTU Discovery}})' + }, + { + aspect: 'Address resolution', + left: '[[arp|ARP]] broadcasts (FF:FF:FF:FF:FF:FF)', + right: '{{ndp|NDP}} solicited-node multicast (far more efficient)' + }, + { + aspect: 'Auto-configuration', + left: 'Requires [[dhcp|DHCP]] server', + right: '{{slaac|SLAAC}} β€” hosts self-configure from router prefix' + } ], useLeftWhen: [ 'You are operating in legacy environments where [[ipv6|IPv6]] is not yet supported', @@ -780,11 +1309,31 @@ const vsPairs: ProtocolPair[] = [ summary: '[[soap|SOAP]] provides formal {{xml|XML}} contracts and enterprise features (transactions, security); [[rest|REST]] favors simplicity with {{json|JSON}} over {{http-method|HTTP}} and standard methods.', keyDifferences: [ - { aspect: 'Data format', left: '{{xml|XML}} only (strict schema)', right: '{{json|JSON}}, {{xml|XML}}, or any format (flexible)' }, - { aspect: 'Contract', left: 'WSDL β€” formal, machine-readable service definition', right: 'OpenAPI/Swagger β€” optional, documentation-oriented' }, - { aspect: 'Transport', left: 'HTTP POST only (protocol-agnostic in theory)', right: 'Full HTTP semantics (GET, POST, PUT, DELETE)' }, - { aspect: 'Error handling', left: '[[soap|SOAP]] Fault β€” structured {{xml|XML}} error envelopes', right: 'HTTP status codes (404, 500, etc.)' }, - { aspect: 'Ecosystem', left: 'WS-Security, WS-ReliableMessaging, WS-AtomicTransaction', right: 'Lightweight β€” use [[tls|TLS]], retries, saga pattern separately' } + { + aspect: 'Data format', + left: '{{xml|XML}} only (strict schema)', + right: '{{json|JSON}}, {{xml|XML}}, or any format (flexible)' + }, + { + aspect: 'Contract', + left: 'WSDL β€” formal, machine-readable service definition', + right: 'OpenAPI/Swagger β€” optional, documentation-oriented' + }, + { + aspect: 'Transport', + left: 'HTTP POST only (protocol-agnostic in theory)', + right: 'Full HTTP semantics (GET, POST, PUT, DELETE)' + }, + { + aspect: 'Error handling', + left: '[[soap|SOAP]] Fault β€” structured {{xml|XML}} error envelopes', + right: 'HTTP status codes (404, 500, etc.)' + }, + { + aspect: 'Ecosystem', + left: 'WS-Security, WS-ReliableMessaging, WS-AtomicTransaction', + right: 'Lightweight β€” use [[tls|TLS]], retries, saga pattern separately' + } ], useLeftWhen: [ 'You need formal service contracts with strict schema validation (banking, insurance)', @@ -805,11 +1354,31 @@ const vsPairs: ProtocolPair[] = [ summary: 'Both use strict contracts and code generation, but [[soap|SOAP]] wraps calls in verbose {{xml|XML}} envelopes while [[grpc|gRPC]] uses compact binary Protobuf over [[http2|HTTP/2]].', keyDifferences: [ - { aspect: 'Serialization', left: '{{xml|XML}} (text-based, verbose)', right: '{{protocol-buffers|Protocol Buffers}} (binary, compact)' }, - { aspect: 'Contract', left: 'WSDL ({{xml|XML}} Schema)', right: '.proto files ({{protocol-buffers|Protocol Buffers}} IDL)' }, - { aspect: 'Transport', left: '[[http1|HTTP/1.1]] POST', right: '[[http2|HTTP/2]] with multiplexing and streaming' }, - { aspect: 'Streaming', left: 'Not supported natively', right: 'Bidirectional streaming built-in' }, - { aspect: 'Ecosystem', left: 'Mature enterprise (Java, .NET)', right: 'Modern polyglot (Go, Rust, Python, Java, JS)' } + { + aspect: 'Serialization', + left: '{{xml|XML}} (text-based, verbose)', + right: '{{protocol-buffers|Protocol Buffers}} (binary, compact)' + }, + { + aspect: 'Contract', + left: 'WSDL ({{xml|XML}} Schema)', + right: '.proto files ({{protocol-buffers|Protocol Buffers}} IDL)' + }, + { + aspect: 'Transport', + left: '[[http1|HTTP/1.1]] POST', + right: '[[http2|HTTP/2]] with multiplexing and streaming' + }, + { + aspect: 'Streaming', + left: 'Not supported natively', + right: 'Bidirectional streaming built-in' + }, + { + aspect: 'Ecosystem', + left: 'Mature enterprise (Java, .NET)', + right: 'Modern polyglot (Go, Rust, Python, Java, JS)' + } ], useLeftWhen: [ 'You are in a regulated industry requiring WSDL-based formal contracts', @@ -830,11 +1399,31 @@ const vsPairs: ProtocolPair[] = [ summary: '[[soap|SOAP]] defines rigid operations via {{wsdl|WSDL}}; [[graphql|GraphQL]] lets clients specify exactly the data they need in a single flexible query.', keyDifferences: [ - { aspect: 'Query model', left: 'Fixed operations defined in WSDL', right: 'Client specifies exact fields and relationships' }, - { aspect: 'Data format', left: '{{xml|XML}} envelopes with {{xml|XML}} Schema', right: '{{json|JSON}} responses with typed schema' }, - { aspect: 'Over/under-fetching', left: 'Returns entire operation result (over-fetching)', right: 'Returns exactly requested fields (precise)' }, - { aspect: 'Versioning', left: 'WSDL versioning (breaking changes)', right: 'Schema evolution (additive, non-breaking)' }, - { aspect: 'Introspection', left: 'WSDL document download', right: 'Built-in schema introspection queries' } + { + aspect: 'Query model', + left: 'Fixed operations defined in WSDL', + right: 'Client specifies exact fields and relationships' + }, + { + aspect: 'Data format', + left: '{{xml|XML}} envelopes with {{xml|XML}} Schema', + right: '{{json|JSON}} responses with typed schema' + }, + { + aspect: 'Over/under-fetching', + left: 'Returns entire operation result (over-fetching)', + right: 'Returns exactly requested fields (precise)' + }, + { + aspect: 'Versioning', + left: 'WSDL versioning (breaking changes)', + right: 'Schema evolution (additive, non-breaking)' + }, + { + aspect: 'Introspection', + left: 'WSDL document download', + right: 'Built-in schema introspection queries' + } ], useLeftWhen: [ 'You need formal, validated contracts for enterprise integration', @@ -858,11 +1447,31 @@ const vsPairs: ProtocolPair[] = [ summary: '[[oauth2|OAuth 2.0]] handles authorization (who can access what); [[tls|TLS]] handles {{encryption|encryption}} (protecting data in {{transit|transit}}). Different problems, complementary solutions β€” [[oauth2|OAuth]] requires [[tls|TLS]].', keyDifferences: [ - { aspect: 'Problem solved', left: 'Authorization β€” delegated access to resources', right: '{{encryption|Encryption}} β€” confidentiality and integrity of data in transit' }, - { aspect: 'OSI layer', left: 'Application layer (HTTP redirects, tokens)', right: 'Session/transport layer (encrypts byte streams)' }, - { aspect: 'Scope', left: 'Per-resource access control (scopes, tokens)', right: 'Per-connection encryption (entire data stream)' }, - { aspect: 'User involvement', left: 'User consents to grant access', right: 'Transparent to the user (lock icon in browser)' }, - { aspect: 'Dependency', left: 'Requires [[tls|TLS]] for security (tokens in cleartext = disaster)', right: 'Independent β€” works without [[oauth2|OAuth]]' } + { + aspect: 'Problem solved', + left: 'Authorization β€” delegated access to resources', + right: '{{encryption|Encryption}} β€” confidentiality and integrity of data in transit' + }, + { + aspect: 'OSI layer', + left: 'Application layer (HTTP redirects, tokens)', + right: 'Session/transport layer (encrypts byte streams)' + }, + { + aspect: 'Scope', + left: 'Per-resource access control (scopes, tokens)', + right: 'Per-connection encryption (entire data stream)' + }, + { + aspect: 'User involvement', + left: 'User consents to grant access', + right: 'Transparent to the user (lock icon in browser)' + }, + { + aspect: 'Dependency', + left: 'Requires [[tls|TLS]] for security (tokens in cleartext = disaster)', + right: 'Independent β€” works without [[oauth2|OAuth]]' + } ], useLeftWhen: [ 'Third-party apps need access to user resources without passwords', @@ -886,11 +1495,31 @@ const vsPairs: ProtocolPair[] = [ summary: '[[rest|REST]] maps operations to {{http-method|HTTP}} verbs and multiple resource URLs; [[json-rpc|JSON-RPC]] sends method names to a single endpoint. [[rest|REST]] is resource-oriented, [[json-rpc|JSON-RPC]] is action-oriented.', keyDifferences: [ - { aspect: 'Data format', left: 'Method name + params in {{json|JSON}} body', right: 'HTTP verbs + resource URLs' }, - { aspect: 'Caching', left: 'Not cacheable (all POSTs)', right: 'HTTP-level caching (GET is cacheable)' }, - { aspect: 'Complexity', left: 'Minimal spec, single endpoint', right: 'Convention-heavy, multiple endpoints' }, - { aspect: 'Ecosystem', left: 'Growing (blockchain, AI agents)', right: 'Dominant (most public APIs)' }, - { aspect: 'Overhead', left: 'Batch requests reduce round trips', right: 'One HTTP request per operation' } + { + aspect: 'Data format', + left: 'Method name + params in {{json|JSON}} body', + right: 'HTTP verbs + resource URLs' + }, + { + aspect: 'Caching', + left: 'Not cacheable (all POSTs)', + right: 'HTTP-level caching (GET is cacheable)' + }, + { + aspect: 'Complexity', + left: 'Minimal spec, single endpoint', + right: 'Convention-heavy, multiple endpoints' + }, + { + aspect: 'Ecosystem', + left: 'Growing (blockchain, AI agents)', + right: 'Dominant (most public APIs)' + }, + { + aspect: 'Overhead', + left: 'Batch requests reduce round trips', + right: 'One HTTP request per operation' + } ], useLeftWhen: [ 'Your API is action-oriented rather than resource-oriented (execute, calculate, query)', @@ -911,11 +1540,31 @@ const vsPairs: ProtocolPair[] = [ summary: '[[grpc|gRPC]] uses binary {{protocol-buffers|Protocol Buffers}} and [[http2|HTTP/2]] for maximum performance with code generation; [[json-rpc|JSON-RPC]] uses human-readable {{json|JSON}} over any transport for maximum simplicity.', keyDifferences: [ - { aspect: 'Data format', left: 'Binary ({{protocol-buffers|Protocol Buffers}})', right: 'Text ({{json|JSON}})' }, - { aspect: 'Transport', left: '[[http2|HTTP/2]] only', right: 'Any (HTTP, [[websockets|WebSocket]], stdio, [[tcp|TCP]])' }, - { aspect: 'Direction', left: 'Unary + bidirectional streaming', right: '{{request-response|Request-response}} + notifications' }, - { aspect: 'Complexity', left: '.proto files + code generation', right: 'No schema, no build step' }, - { aspect: 'Ecosystem', left: 'Mature (Google-backed, 11 languages)', right: 'Lightweight (blockchain, AI, editors)' } + { + aspect: 'Data format', + left: 'Binary ({{protocol-buffers|Protocol Buffers}})', + right: 'Text ({{json|JSON}})' + }, + { + aspect: 'Transport', + left: '[[http2|HTTP/2]] only', + right: 'Any (HTTP, [[websockets|WebSocket]], stdio, [[tcp|TCP]])' + }, + { + aspect: 'Direction', + left: 'Unary + bidirectional streaming', + right: '{{request-response|Request-response}} + notifications' + }, + { + aspect: 'Complexity', + left: '.proto files + code generation', + right: 'No schema, no build step' + }, + { + aspect: 'Ecosystem', + left: 'Mature (Google-backed, 11 languages)', + right: 'Lightweight (blockchain, AI, editors)' + } ], useLeftWhen: [ 'You need maximum throughput between internal microservices', @@ -936,11 +1585,31 @@ const vsPairs: ProtocolPair[] = [ summary: '[[graphql|GraphQL]] lets clients {{imap-select|select}} exactly which fields they need via a query language; [[json-rpc|JSON-RPC]] calls methods by name and returns whatever the method returns β€” no field selection.', keyDifferences: [ - { aspect: 'Data format', left: 'Query language with field selection', right: 'Method name + params, fixed response' }, - { aspect: 'Complexity', left: 'Schema, resolvers, query parsing', right: 'No schema, direct method dispatch' }, - { aspect: 'Overhead', left: 'Query parsing + validation per request', right: 'Minimal β€” {{json|JSON}} parse + method lookup' }, - { aspect: 'Direction', left: '{{request-response|Request-response}} + subscriptions', right: '{{request-response|Request-response}} + notifications' }, - { aspect: 'Ecosystem', left: 'Web frontends, mobile apps', right: 'Infrastructure, blockchain, AI agents' } + { + aspect: 'Data format', + left: 'Query language with field selection', + right: 'Method name + params, fixed response' + }, + { + aspect: 'Complexity', + left: 'Schema, resolvers, query parsing', + right: 'No schema, direct method dispatch' + }, + { + aspect: 'Overhead', + left: 'Query parsing + validation per request', + right: 'Minimal β€” {{json|JSON}} parse + method lookup' + }, + { + aspect: 'Direction', + left: '{{request-response|Request-response}} + subscriptions', + right: '{{request-response|Request-response}} + notifications' + }, + { + aspect: 'Ecosystem', + left: 'Web frontends, mobile apps', + right: 'Infrastructure, blockchain, AI agents' + } ], useLeftWhen: [ 'Clients have varied data needs and over-fetching is a problem', @@ -961,11 +1630,31 @@ const vsPairs: ProtocolPair[] = [ summary: '[[soap|SOAP]] wraps {{rpc|RPC}} calls in verbose {{xml|XML}} envelopes with formal {{wsdl|WSDL}} contracts and {{ws-star|WS-*}} extensions; [[json-rpc|JSON-RPC]] does the same thing in a few lines of {{json|JSON}} with no ceremony.', keyDifferences: [ - { aspect: 'Data format', left: '{{json|JSON}} (lightweight text)', right: '{{xml|XML}} (verbose, structured envelopes)' }, - { aspect: 'Complexity', left: 'One-page spec, no schema required', right: 'WSDL, XSD, WS-* extensions' }, - { aspect: 'Overhead', left: '~60 bytes for a simple call', right: '500+ bytes for the same call in {{xml|XML}}' }, - { aspect: 'Standardization', left: 'Community spec (jsonrpc.org)', right: '{{w3c|W3C}} standard with enterprise extensions' }, - { aspect: 'Ecosystem', left: 'Modern infrastructure and AI', right: 'Enterprise banking, healthcare, government' } + { + aspect: 'Data format', + left: '{{json|JSON}} (lightweight text)', + right: '{{xml|XML}} (verbose, structured envelopes)' + }, + { + aspect: 'Complexity', + left: 'One-page spec, no schema required', + right: 'WSDL, XSD, WS-* extensions' + }, + { + aspect: 'Overhead', + left: '~60 bytes for a simple call', + right: '500+ bytes for the same call in {{xml|XML}}' + }, + { + aspect: 'Standardization', + left: 'Community spec (jsonrpc.org)', + right: '{{w3c|W3C}} standard with enterprise extensions' + }, + { + aspect: 'Ecosystem', + left: 'Modern infrastructure and AI', + right: 'Enterprise banking, healthcare, government' + } ], useLeftWhen: [ 'You want RPC without the overhead of {{xml|XML}} and WSDL', @@ -989,11 +1678,31 @@ const vsPairs: ProtocolPair[] = [ summary: '[[mcp|MCP]] connects an {{ai|AI}} agent to tools and data sources; [[a2a|A2A]] connects {{ai|AI}} agents to each other for multi-agent collaboration. They are complementary, not competing.', keyDifferences: [ - { aspect: 'Purpose', left: 'Agent-to-agent collaboration', right: 'Agent-to-tool integration' }, - { aspect: 'Discovery', left: 'Agent Cards at /.well-known/agent.json', right: 'Capabilities handshake (initialize)' }, - { aspect: 'Transparency', left: 'Opaque (skills only, no internals)', right: 'Transparent (tool schemas, resource URIs)' }, - { aspect: 'Unit of work', left: 'Task with lifecycle (stateful)', right: 'Tool call (stateless {{request-response|request-response}})' }, - { aspect: 'Transport', left: 'HTTP, [[sse|SSE]], webhooks, [[grpc|gRPC]]', right: 'stdio, Streamable HTTP' } + { + aspect: 'Purpose', + left: 'Agent-to-agent collaboration', + right: 'Agent-to-tool integration' + }, + { + aspect: 'Discovery', + left: 'Agent Cards at /.well-known/agent.json', + right: 'Capabilities handshake (initialize)' + }, + { + aspect: 'Transparency', + left: 'Opaque (skills only, no internals)', + right: 'Transparent (tool schemas, resource URIs)' + }, + { + aspect: 'Unit of work', + left: 'Task with lifecycle (stateful)', + right: 'Tool call (stateless {{request-response|request-response}})' + }, + { + aspect: 'Transport', + left: 'HTTP, [[sse|SSE]], webhooks, [[grpc|gRPC]]', + right: 'stdio, Streamable HTTP' + } ], useLeftWhen: [ 'You need multiple AI agents to collaborate on complex tasks', @@ -1014,11 +1723,31 @@ const vsPairs: ProtocolPair[] = [ summary: '[[rest|REST]] is a general-purpose {{api|API}} style for any client; [[a2a|A2A]] is specifically designed for {{ai|AI}} agent communication with discovery, task lifecycle, and streaming built in.', keyDifferences: [ - { aspect: 'Purpose', left: 'AI agent-to-agent collaboration', right: 'General-purpose API access' }, - { aspect: 'Discovery', left: 'Agent Cards with skills and auth', right: 'OpenAPI/Swagger documentation' }, - { aspect: 'Statefulness', left: '{{stateful|Stateful}} tasks with lifecycle', right: '{{stateless|Stateless}} {{request-response|request-response}}' }, - { aspect: 'Direction', left: 'Bidirectional ([[sse|SSE]], webhooks)', right: 'Client-initiated only' }, - { aspect: 'Data format', left: '[[json-rpc|JSON-RPC]] methods + Parts/Artifacts', right: 'HTTP verbs + resource URLs' } + { + aspect: 'Purpose', + left: 'AI agent-to-agent collaboration', + right: 'General-purpose API access' + }, + { + aspect: 'Discovery', + left: 'Agent Cards with skills and auth', + right: 'OpenAPI/Swagger documentation' + }, + { + aspect: 'Statefulness', + left: '{{stateful|Stateful}} tasks with lifecycle', + right: '{{stateless|Stateless}} {{request-response|request-response}}' + }, + { + aspect: 'Direction', + left: 'Bidirectional ([[sse|SSE]], webhooks)', + right: 'Client-initiated only' + }, + { + aspect: 'Data format', + left: '[[json-rpc|JSON-RPC]] methods + Parts/Artifacts', + right: 'HTTP verbs + resource URLs' + } ], useLeftWhen: [ 'You are building multi-agent AI systems that need to delegate and coordinate', @@ -1039,11 +1768,27 @@ const vsPairs: ProtocolPair[] = [ summary: '[[rest|REST]] exposes resources via {{http-method|HTTP}} for any client; [[mcp|MCP]] exposes tools, resources, and prompts specifically for {{ai|AI}} applications with {{llm|LLM}}-native semantics like {{sampling|sampling}} and tool schemas.', keyDifferences: [ - { aspect: 'Purpose', left: 'AI-native tool and data access', right: 'General-purpose API access' }, - { aspect: 'Discovery', left: 'Dynamic capability negotiation', right: 'Static OpenAPI documentation' }, - { aspect: 'Data format', left: '[[json-rpc|JSON-RPC]] methods (tools/call)', right: 'HTTP verbs + resource URLs' }, + { + aspect: 'Purpose', + left: 'AI-native tool and data access', + right: 'General-purpose API access' + }, + { + aspect: 'Discovery', + left: 'Dynamic capability negotiation', + right: 'Static OpenAPI documentation' + }, + { + aspect: 'Data format', + left: '[[json-rpc|JSON-RPC]] methods (tools/call)', + right: 'HTTP verbs + resource URLs' + }, { aspect: 'Transport', left: 'stdio + Streamable HTTP', right: 'HTTP only' }, - { aspect: 'Ecosystem', left: 'AI apps (Claude, ChatGPT, Cursor)', right: 'Universal (any HTTP client)' } + { + aspect: 'Ecosystem', + left: 'AI apps (Claude, ChatGPT, Cursor)', + right: 'Universal (any HTTP client)' + } ], useLeftWhen: [ 'You are building tools for AI applications to consume (not human developers)', @@ -1064,11 +1809,31 @@ const vsPairs: ProtocolPair[] = [ summary: '[[grpc|gRPC]] is a general-purpose {{rpc|RPC}} framework for microservices; [[a2a|A2A]] is specifically designed for {{ai|AI}} agent communication with agent discovery, task lifecycle, and opaque collaboration.', keyDifferences: [ - { aspect: 'Purpose', left: 'AI agent collaboration', right: 'General-purpose microservice RPC' }, - { aspect: 'Discovery', left: 'Agent Cards with skills', right: 'Protobuf service reflection' }, - { aspect: 'Data format', left: '[[json-rpc|JSON-RPC]] 2.0 (text)', right: '{{protocol-buffers|Protocol Buffers}} (binary)' }, - { aspect: 'Statefulness', left: '{{stateful|Stateful}} tasks with lifecycle', right: '{{stateless|Stateless}} unary or streaming calls' }, - { aspect: 'Ecosystem', left: 'AI agents (Google, Salesforce, SAP)', right: 'Microservices (Kubernetes, {{service-mesh|service mesh}})' } + { + aspect: 'Purpose', + left: 'AI agent collaboration', + right: 'General-purpose microservice RPC' + }, + { + aspect: 'Discovery', + left: 'Agent Cards with skills', + right: 'Protobuf service reflection' + }, + { + aspect: 'Data format', + left: '[[json-rpc|JSON-RPC]] 2.0 (text)', + right: '{{protocol-buffers|Protocol Buffers}} (binary)' + }, + { + aspect: 'Statefulness', + left: '{{stateful|Stateful}} tasks with lifecycle', + right: '{{stateless|Stateless}} unary or streaming calls' + }, + { + aspect: 'Ecosystem', + left: 'AI agents (Google, Salesforce, SAP)', + right: 'Microservices (Kubernetes, {{service-mesh|service mesh}})' + } ], useLeftWhen: [ 'You are orchestrating opaque AI agents that need to discover and delegate tasks', @@ -1100,7 +1865,8 @@ const relationshipPairs: ProtocolPair[] = [ howTheyWork: '[[tcp|TCP]] first establishes a reliable connection via its 3-way {{handshake|handshake}}. Then [[tls|TLS]] performs its own {{handshake|handshake}} on top of that [[tcp|TCP]] connection, negotiating cipher suites and exchanging keys. Once both handshakes complete, all application data flows through [[tls|TLS]] {{encryption|encryption}} over the [[tcp|TCP]] stream.', leftRole: '[[tcp|TCP]] provides reliable, ordered byte-stream delivery between endpoints.', - rightRole: '[[tls|TLS]] provides confidentiality, integrity, and authentication for the data [[tcp|TCP]] carries.' + rightRole: + '[[tls|TLS]] provides confidentiality, integrity, and authentication for the data [[tcp|TCP]] carries.' }, { ids: ['amqp', 'tcp'], @@ -1108,9 +1874,11 @@ const relationshipPairs: ProtocolPair[] = [ summary: '[[amqp|AMQP]] runs over [[tcp|TCP]], relying on its reliable byte stream to guarantee that messages, acknowledgments, and routing commands between clients and brokers are never lost or reordered.', howTheyWork: - 'An [[amqp|AMQP]] client opens a [[tcp|TCP]] connection to the broker (typically port 5672) and performs the [[amqp|AMQP]] protocol {{handshake|handshake}} to negotiate capabilities. [[amqp|AMQP]] then multiplexes multiple logical channels over this single [[tcp|TCP]] connection, using [[tcp|TCP]]\'s reliability to ensure every published message, acknowledgment, and broker command arrives intact and in order.', - leftRole: '[[amqp|AMQP]] provides message routing, queuing, acknowledgment, and delivery guarantee semantics.', - rightRole: '[[tcp|TCP]] provides the reliable, ordered byte-stream transport that [[amqp|AMQP]] frames are carried over.' + "An [[amqp|AMQP]] client opens a [[tcp|TCP]] connection to the broker (typically port 5672) and performs the [[amqp|AMQP]] protocol {{handshake|handshake}} to negotiate capabilities. [[amqp|AMQP]] then multiplexes multiple logical channels over this single [[tcp|TCP]] connection, using [[tcp|TCP]]'s reliability to ensure every published message, acknowledgment, and broker command arrives intact and in order.", + leftRole: + '[[amqp|AMQP]] provides message routing, queuing, acknowledgment, and delivery guarantee semantics.', + rightRole: + '[[tcp|TCP]] provides the reliable, ordered byte-stream transport that [[amqp|AMQP]] frames are carried over.' }, { ids: ['dns', 'tcp'], @@ -1119,8 +1887,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[dns|DNS]] falls back to [[tcp|TCP]] when responses exceed the 512-byte [[udp|UDP]] limit or when zone transfers require reliable delivery of complete [[dns|DNS]] records.', howTheyWork: 'When a [[dns|DNS]] response is too large for a single [[udp|UDP]] datagram (common with {{dnssec|DNSSEC}} or many records), the server signals truncation and the client retries over [[tcp|TCP]] port 53. Zone transfers (AXFR/IXFR) between authoritative servers always use [[tcp|TCP]] to ensure the complete zone dataset is delivered reliably without loss or reordering.', - leftRole: '[[dns|DNS]] defines the query/response protocol for name resolution and zone transfer operations.', - rightRole: '[[tcp|TCP]] provides reliable delivery for large [[dns|DNS]] responses and complete zone transfers that exceed [[udp|UDP]]\'s practical limits.' + leftRole: + '[[dns|DNS]] defines the query/response protocol for name resolution and zone transfer operations.', + rightRole: + "[[tcp|TCP]] provides reliable delivery for large [[dns|DNS]] responses and complete zone transfers that exceed [[udp|UDP]]'s practical limits." }, { ids: ['ftp', 'tcp'], @@ -1128,19 +1898,23 @@ const relationshipPairs: ProtocolPair[] = [ summary: '[[ftp|FTP]] uses [[tcp|TCP]] for both its control channel (commands and responses) and its separate data channel (file transfers), relying on reliable delivery to ensure files arrive intact.', howTheyWork: - '[[ftp|FTP]] establishes a [[tcp|TCP]] control connection on port 21 for exchanging commands (LIST, RETR, STOR) and status replies. For each file transfer, a separate [[tcp|TCP]] data connection is opened β€” either from server to client (active mode) or client to server (passive mode). [[tcp|TCP]]\'s reliability guarantees that transferred files are complete and uncorrupted.', - leftRole: '[[ftp|FTP]] provides the command protocol for file listing, upload, download, and directory navigation.', - rightRole: '[[tcp|TCP]] provides reliable, ordered delivery for both the [[ftp|FTP]] control channel and file data transfers.' + "[[ftp|FTP]] establishes a [[tcp|TCP]] control connection on port 21 for exchanging commands (LIST, RETR, STOR) and status replies. For each file transfer, a separate [[tcp|TCP]] data connection is opened β€” either from server to client (active mode) or client to server (passive mode). [[tcp|TCP]]'s reliability guarantees that transferred files are complete and uncorrupted.", + leftRole: + '[[ftp|FTP]] provides the command protocol for file listing, upload, download, and directory navigation.', + rightRole: + '[[tcp|TCP]] provides reliable, ordered delivery for both the [[ftp|FTP]] control channel and file data transfers.' }, { ids: ['http1', 'tcp'], type: 'relationship', summary: - '[[http1|[[http1|HTTP/1]].1]] sends requests and responses as plaintext over [[tcp|TCP]] connections, relying on [[tcp|TCP]]\'s reliable delivery to ensure every header and body byte arrives in order.', + "[[http1|[[http1|HTTP/1]].1]] sends requests and responses as plaintext over [[tcp|TCP]] connections, relying on [[tcp|TCP]]'s reliable delivery to ensure every header and body byte arrives in order.", howTheyWork: - 'The client opens a [[tcp|TCP]] connection (typically port 80 or 443 with [[tls|TLS]]) and sends an {{http-method|HTTP}} request as a text stream. The server responds over the same connection, which can be reused for subsequent requests via {{keep-alive|keep-alive}}. Each {{request-response|request-response}} pair is serialized on the connection, meaning [[http1|[[http1|HTTP/1]].1]] inherits [[tcp|TCP]]\'s {{head-of-line-blocking|head-of-line blocking}}.', - leftRole: '[[http1|[[http1|HTTP/1]].1]] provides the {{request-response|request-response}} semantics, headers, methods, and status codes for web communication.', - rightRole: '[[tcp|TCP]] provides the reliable, ordered byte stream that [[http1|[[http1|HTTP/1]].1]] messages are transmitted over.' + "The client opens a [[tcp|TCP]] connection (typically port 80 or 443 with [[tls|TLS]]) and sends an {{http-method|HTTP}} request as a text stream. The server responds over the same connection, which can be reused for subsequent requests via {{keep-alive|keep-alive}}. Each {{request-response|request-response}} pair is serialized on the connection, meaning [[http1|[[http1|HTTP/1]].1]] inherits [[tcp|TCP]]'s {{head-of-line-blocking|head-of-line blocking}}.", + leftRole: + '[[http1|[[http1|HTTP/1]].1]] provides the {{request-response|request-response}} semantics, headers, methods, and status codes for web communication.', + rightRole: + '[[tcp|TCP]] provides the reliable, ordered byte stream that [[http1|[[http1|HTTP/1]].1]] messages are transmitted over.' }, { ids: ['http2', 'tcp'], @@ -1149,8 +1923,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[http2|HTTP/2]] multiplexes many {{request-response|request-response}} streams over a single [[tcp|TCP]] connection, gaining efficiency but inheriting [[tcp|TCP]]-level {{head-of-line-blocking|head-of-line blocking}} when packets are lost.', howTheyWork: '[[http2|HTTP/2]] opens one [[tcp|TCP]] connection per origin and sends all requests as interleaved binary frames across independent logical streams. [[tcp|TCP]] sees this as a single byte stream and guarantees ordered delivery. If any [[tcp|TCP]] segment is lost, all [[http2|HTTP/2]] streams stall until {{retransmission|retransmission}} completes β€” this [[tcp|TCP]]-level {{head-of-line-blocking|head-of-line blocking}} is what [[http3|HTTP/3]] ([[quic|QUIC]]) was designed to solve.', - leftRole: '[[http2|HTTP/2]] provides {{binary-framing|binary framing}}, multiplexed streams, header compression, and {{server-push|server push}}.', - rightRole: '[[tcp|TCP]] provides the single reliable byte stream over which all [[http2|HTTP/2]] frames are delivered.' + leftRole: + '[[http2|HTTP/2]] provides {{binary-framing|binary framing}}, multiplexed streams, header compression, and {{server-push|server push}}.', + rightRole: + '[[tcp|TCP]] provides the single reliable byte stream over which all [[http2|HTTP/2]] frames are delivered.' }, { ids: ['kafka', 'tcp'], @@ -1158,19 +1934,23 @@ const relationshipPairs: ProtocolPair[] = [ summary: '[[kafka|Kafka]] uses persistent [[tcp|TCP]] connections between producers, consumers, and brokers to reliably stream high-throughput event data with ordering guarantees.', howTheyWork: - '[[kafka|Kafka]] clients open long-lived [[tcp|TCP]] connections to brokers (default port 9092) and use [[kafka|Kafka]]\'s binary protocol to produce and consume messages in batches. [[tcp|TCP]]\'s reliable delivery ensures that large batches of events, {{offset|offset}} commits, and metadata requests are never lost or reordered. Clients maintain connections to multiple brokers for {{partition|partition}}-aware routing.', - leftRole: '[[kafka|Kafka]] provides distributed log storage, partitioned {{topic|topic}} streaming, and {{consumer-group|consumer group}} coordination.', - rightRole: '[[tcp|TCP]] provides the reliable, persistent connections needed for high-throughput event delivery between [[kafka|Kafka]] clients and brokers.' + "[[kafka|Kafka]] clients open long-lived [[tcp|TCP]] connections to brokers (default port 9092) and use [[kafka|Kafka]]'s binary protocol to produce and consume messages in batches. [[tcp|TCP]]'s reliable delivery ensures that large batches of events, {{offset|offset}} commits, and metadata requests are never lost or reordered. Clients maintain connections to multiple brokers for {{partition|partition}}-aware routing.", + leftRole: + '[[kafka|Kafka]] provides distributed log storage, partitioned {{topic|topic}} streaming, and {{consumer-group|consumer group}} coordination.', + rightRole: + '[[tcp|TCP]] provides the reliable, persistent connections needed for high-throughput event delivery between [[kafka|Kafka]] clients and brokers.' }, { ids: ['mqtt', 'tcp'], type: 'relationship', summary: - '[[mqtt|MQTT]] uses [[tcp|TCP]] as its default transport, relying on [[tcp|TCP]]\'s reliable delivery to carry lightweight pub/sub messages between IoT devices and brokers.', + "[[mqtt|MQTT]] uses [[tcp|TCP]] as its default transport, relying on [[tcp|TCP]]'s reliable delivery to carry lightweight pub/sub messages between IoT devices and brokers.", howTheyWork: - 'An [[mqtt|MQTT]] client opens a [[tcp|TCP]] connection to the broker (typically port 1883, or 8883 with [[tls|TLS]]) and sends a {{mqtt-connect|CONNECT}} packet to establish the session. [[tcp|TCP]]\'s reliability ensures that {{mqtt-publish|PUBLISH}}, {{mqtt-subscribe|SUBSCRIBE}}, and acknowledgment packets arrive intact, which [[mqtt|MQTT]] layers its own QoS levels on top of. The persistent [[tcp|TCP]] connection also enables the broker to push messages to clients at any time.', - leftRole: '[[mqtt|MQTT]] provides lightweight {{mqtt-publish|publish}}-{{mqtt-subscribe|subscribe}} messaging with QoS levels, retained messages, and last-will semantics.', - rightRole: '[[tcp|TCP]] provides the reliable, persistent connection that [[mqtt|MQTT]] uses to deliver messages between clients and the broker.' + "An [[mqtt|MQTT]] client opens a [[tcp|TCP]] connection to the broker (typically port 1883, or 8883 with [[tls|TLS]]) and sends a {{mqtt-connect|CONNECT}} packet to establish the session. [[tcp|TCP]]'s reliability ensures that {{mqtt-publish|PUBLISH}}, {{mqtt-subscribe|SUBSCRIBE}}, and acknowledgment packets arrive intact, which [[mqtt|MQTT]] layers its own QoS levels on top of. The persistent [[tcp|TCP]] connection also enables the broker to push messages to clients at any time.", + leftRole: + '[[mqtt|MQTT]] provides lightweight {{mqtt-publish|publish}}-{{mqtt-subscribe|subscribe}} messaging with QoS levels, retained messages, and last-will semantics.', + rightRole: + '[[tcp|TCP]] provides the reliable, persistent connection that [[mqtt|MQTT]] uses to deliver messages between clients and the broker.' }, { ids: ['rtmp', 'tcp'], @@ -1178,9 +1958,11 @@ const relationshipPairs: ProtocolPair[] = [ summary: '[[rtmp|RTMP]] runs over persistent [[tcp|TCP]] connections to reliably deliver live audio, video, and data streams from encoders to media servers.', howTheyWork: - '[[rtmp|RTMP]] establishes a [[tcp|TCP]] connection (default port 1935) and performs its own {{handshake|handshake}} to negotiate the session. It then multiplexes audio, video, and command messages as interleaved chunks over this single [[tcp|TCP]] connection. [[tcp|TCP]]\'s reliable delivery ensures no media chunks are lost, which is critical since [[rtmp|RTMP]]\'s chunk-based protocol cannot recover from gaps.', - leftRole: '[[rtmp|RTMP]] provides the media chunking, {{multiplexing|multiplexing}}, and stream control protocol for live streaming.', - rightRole: '[[tcp|TCP]] provides the reliable, persistent connection that ensures every media chunk is delivered in order.' + "[[rtmp|RTMP]] establishes a [[tcp|TCP]] connection (default port 1935) and performs its own {{handshake|handshake}} to negotiate the session. It then multiplexes audio, video, and command messages as interleaved chunks over this single [[tcp|TCP]] connection. [[tcp|TCP]]'s reliable delivery ensures no media chunks are lost, which is critical since [[rtmp|RTMP]]'s chunk-based protocol cannot recover from gaps.", + leftRole: + '[[rtmp|RTMP]] provides the media chunking, {{multiplexing|multiplexing}}, and stream control protocol for live streaming.', + rightRole: + '[[tcp|TCP]] provides the reliable, persistent connection that ensures every media chunk is delivered in order.' }, { ids: ['sip', 'tcp'], @@ -1189,8 +1971,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[sip|SIP]] can use [[tcp|TCP]] for {{signaling|signaling}} when messages are too large for [[udp|UDP]] datagrams or when reliable delivery of call setup and teardown is required.', howTheyWork: '[[sip|SIP]] operates over [[tcp|TCP]] (port 5060, or 5061 with [[tls|TLS]]) when message sizes exceed the {{mtu|MTU}} or when the deployment requires guaranteed delivery of {{sip-invite|INVITE}}, BYE, and REGISTER transactions. [[tcp|TCP]] ensures that large [[sip|SIP]] messages with [[sdp|SDP]] bodies, authentication headers, or multiple Via hops are delivered complete and in order.', - leftRole: '[[sip|SIP]] provides the {{signaling|signaling}} protocol for initiating, modifying, and terminating multimedia sessions.', - rightRole: '[[tcp|TCP]] provides reliable delivery for [[sip|SIP]] messages that are too large for [[udp|UDP]] or require guaranteed transport.' + leftRole: + '[[sip|SIP]] provides the {{signaling|signaling}} protocol for initiating, modifying, and terminating multimedia sessions.', + rightRole: + '[[tcp|TCP]] provides reliable delivery for [[sip|SIP]] messages that are too large for [[udp|UDP]] or require guaranteed transport.' }, { ids: ['smtp', 'tcp'], @@ -1198,9 +1982,11 @@ const relationshipPairs: ProtocolPair[] = [ summary: '[[smtp|SMTP]] uses [[tcp|TCP]] to reliably deliver email messages and commands between mail clients and servers, ensuring no message data is lost in {{transit|transit}}.', howTheyWork: - 'An [[smtp|SMTP]] client opens a [[tcp|TCP]] connection to the mail server on port 25 (or 587 for submission) and exchanges text commands ({{ehlo|EHLO}}, {{smtp-mail-from|MAIL FROM}}, {{smtp-rcpt-to|RCPT TO}}, {{smtp-data|DATA}}) in a synchronous dialogue. [[tcp|TCP]]\'s reliable delivery guarantees that every command, response code, and email body byte arrives in order, which is essential since [[smtp|SMTP]] has no mechanism to recover from lost data at the application layer.', - leftRole: '[[smtp|SMTP]] provides the command protocol for routing and delivering email messages between servers.', - rightRole: '[[tcp|TCP]] provides the reliable, ordered connection that [[smtp|SMTP]]\'s synchronous command-response dialogue requires.' + "An [[smtp|SMTP]] client opens a [[tcp|TCP]] connection to the mail server on port 25 (or 587 for submission) and exchanges text commands ({{ehlo|EHLO}}, {{smtp-mail-from|MAIL FROM}}, {{smtp-rcpt-to|RCPT TO}}, {{smtp-data|DATA}}) in a synchronous dialogue. [[tcp|TCP]]'s reliable delivery guarantees that every command, response code, and email body byte arrives in order, which is essential since [[smtp|SMTP]] has no mechanism to recover from lost data at the application layer.", + leftRole: + '[[smtp|SMTP]] provides the command protocol for routing and delivering email messages between servers.', + rightRole: + "[[tcp|TCP]] provides the reliable, ordered connection that [[smtp|SMTP]]'s synchronous command-response dialogue requires." }, { ids: ['ssh', 'tcp'], @@ -1208,19 +1994,23 @@ const relationshipPairs: ProtocolPair[] = [ summary: '[[ssh|SSH]] runs over [[tcp|TCP]] to provide encrypted remote shell access, file transfer, and {{port-forwarding|port forwarding}} over a reliable transport.', howTheyWork: - '[[ssh|SSH]] opens a [[tcp|TCP]] connection (default port 22) and immediately begins its own key {{exchange|exchange}} and authentication {{handshake|handshake}}. Once the encrypted tunnel is established, [[ssh|SSH]] multiplexes multiple channels (shell sessions, port forwards, file transfers) over the single [[tcp|TCP]] connection. [[tcp|TCP]]\'s reliability is essential because [[ssh|SSH]]\'s encrypted stream cannot tolerate missing or reordered bytes.', - leftRole: '[[ssh|SSH]] provides encrypted channels for remote shell access, file transfer, and {{port-forwarding|port forwarding}}.', - rightRole: '[[tcp|TCP]] provides the reliable, ordered byte stream that [[ssh|SSH]]\'s encrypted tunnel requires to function correctly.' + "[[ssh|SSH]] opens a [[tcp|TCP]] connection (default port 22) and immediately begins its own key {{exchange|exchange}} and authentication {{handshake|handshake}}. Once the encrypted tunnel is established, [[ssh|SSH]] multiplexes multiple channels (shell sessions, port forwards, file transfers) over the single [[tcp|TCP]] connection. [[tcp|TCP]]'s reliability is essential because [[ssh|SSH]]'s encrypted stream cannot tolerate missing or reordered bytes.", + leftRole: + '[[ssh|SSH]] provides encrypted channels for remote shell access, file transfer, and {{port-forwarding|port forwarding}}.', + rightRole: + "[[tcp|TCP]] provides the reliable, ordered byte stream that [[ssh|SSH]]'s encrypted tunnel requires to function correctly." }, { ids: ['stomp', 'tcp'], type: 'relationship', summary: - '[[stomp|STOMP]] sends its text-based messaging frames over [[tcp|TCP]] connections, relying on [[tcp|TCP]]\'s reliability to ensure message commands and acknowledgments are delivered intact.', + "[[stomp|STOMP]] sends its text-based messaging frames over [[tcp|TCP]] connections, relying on [[tcp|TCP]]'s reliability to ensure message commands and acknowledgments are delivered intact.", howTheyWork: 'A [[stomp|STOMP]] client opens a [[tcp|TCP]] connection to the broker and sends a {{mqtt-connect|CONNECT}} frame to initiate the session. All subsequent SEND, {{mqtt-subscribe|SUBSCRIBE}}, and {{ack|ACK}} frames are transmitted as text over this [[tcp|TCP]] connection. [[tcp|TCP]] guarantees that these frames arrive complete and in order, which [[stomp|STOMP]] depends on since its simple text framing has no built-in {{retransmission|retransmission}} or reordering logic.', - leftRole: '[[stomp|STOMP]] provides a simple, text-based messaging protocol with SEND, {{mqtt-subscribe|SUBSCRIBE}}, and {{ack|ACK}} commands.', - rightRole: '[[tcp|TCP]] provides the reliable transport that ensures [[stomp|STOMP]]\'s text frames are delivered without loss or reordering.' + leftRole: + '[[stomp|STOMP]] provides a simple, text-based messaging protocol with SEND, {{mqtt-subscribe|SUBSCRIBE}}, and {{ack|ACK}} commands.', + rightRole: + "[[tcp|TCP]] provides the reliable transport that ensures [[stomp|STOMP]]'s text frames are delivered without loss or reordering." }, { ids: ['tcp', 'websockets'], @@ -1228,9 +2018,11 @@ const relationshipPairs: ProtocolPair[] = [ summary: '[[websockets|WebSocket]] runs over [[tcp|TCP]], using an {{http-method|HTTP}} upgrade {{handshake|handshake}} to establish a persistent, {{full-duplex|full-duplex}} message channel over a reliable transport.', howTheyWork: - 'The client sends an [[http1|[[http1|HTTP/1]].1]] Upgrade request over an existing [[tcp|TCP]] connection, and the server responds with 101 Switching Protocols. From that point, the [[tcp|TCP]] connection carries [[websockets|WebSocket]] frames instead of {{http-method|HTTP}}. [[tcp|TCP]]\'s reliable, ordered delivery ensures that [[websockets|WebSocket]] messages β€” which can be fragmented across multiple frames β€” are reassembled correctly on both sides.', - leftRole: '[[tcp|TCP]] provides the reliable, persistent connection that [[websockets|WebSocket]] frames are transmitted over.', - rightRole: '[[websockets|WebSocket]] provides {{full-duplex|full-duplex}}, message-oriented communication with lightweight framing over the [[tcp|TCP]] connection.' + "The client sends an [[http1|[[http1|HTTP/1]].1]] Upgrade request over an existing [[tcp|TCP]] connection, and the server responds with 101 Switching Protocols. From that point, the [[tcp|TCP]] connection carries [[websockets|WebSocket]] frames instead of {{http-method|HTTP}}. [[tcp|TCP]]'s reliable, ordered delivery ensures that [[websockets|WebSocket]] messages β€” which can be fragmented across multiple frames β€” are reassembled correctly on both sides.", + leftRole: + '[[tcp|TCP]] provides the reliable, persistent connection that [[websockets|WebSocket]] frames are transmitted over.', + rightRole: + '[[websockets|WebSocket]] provides {{full-duplex|full-duplex}}, message-oriented communication with lightweight framing over the [[tcp|TCP]] connection.' }, { ids: ['tcp', 'xmpp'], @@ -1238,9 +2030,11 @@ const relationshipPairs: ProtocolPair[] = [ summary: '[[xmpp|XMPP]] maintains long-lived [[tcp|TCP]] connections to stream {{xml|XML}} stanzas between clients and servers, relying on [[tcp|TCP]] for reliable delivery of presence, messages, and IQ queries.', howTheyWork: - 'An [[xmpp|XMPP]] client opens a persistent [[tcp|TCP]] connection (default port 5222, with {{starttls|STARTTLS}} upgrade) and begins an {{xml|XML}} stream. All communication β€” presence updates, chat messages, and IQ stanzas β€” flows as {{xml|XML}} fragments over this single [[tcp|TCP]] connection. [[tcp|TCP]]\'s reliability ensures that {{xml|XML}} stanzas are never lost or reordered, which is critical since [[xmpp|XMPP]]\'s {{xml|XML}} parser requires a well-formed, sequential byte stream.', - leftRole: '[[tcp|TCP]] provides the persistent, reliable connection that carries [[xmpp|XMPP]]\'s continuous {{xml|XML}} stream.', - rightRole: '[[xmpp|XMPP]] provides real-time messaging, presence, and extensible communication semantics via {{xml|XML}} stanzas over the [[tcp|TCP]] stream.' + "An [[xmpp|XMPP]] client opens a persistent [[tcp|TCP]] connection (default port 5222, with {{starttls|STARTTLS}} upgrade) and begins an {{xml|XML}} stream. All communication β€” presence updates, chat messages, and IQ stanzas β€” flows as {{xml|XML}} fragments over this single [[tcp|TCP]] connection. [[tcp|TCP]]'s reliability ensures that {{xml|XML}} stanzas are never lost or reordered, which is critical since [[xmpp|XMPP]]'s {{xml|XML}} parser requires a well-formed, sequential byte stream.", + leftRole: + "[[tcp|TCP]] provides the persistent, reliable connection that carries [[xmpp|XMPP]]'s continuous {{xml|XML}} stream.", + rightRole: + '[[xmpp|XMPP]] provides real-time messaging, presence, and extensible communication semantics via {{xml|XML}} stanzas over the [[tcp|TCP]] stream.' }, // ── UDP as transport ───────────────────────────────────────── @@ -1252,18 +2046,22 @@ const relationshipPairs: ProtocolPair[] = [ '[[dns|DNS]] uses [[udp|UDP]] as its primary transport for fast, single-packet query-response lookups, keeping name resolution lightweight and low-{{latency|latency}}.', howTheyWork: 'A [[dns|DNS]] client sends a query as a single [[udp|UDP]] datagram (typically under 512 bytes) to a resolver on port 53. The resolver responds with another [[udp|UDP]] datagram containing the answer. No connection setup is needed, making lookups fast. For responses exceeding 512 bytes or requiring reliability, [[dns|DNS]] falls back to [[tcp|TCP]].', - leftRole: '[[dns|DNS]] defines the query/response format for translating domain names to [[ip|IP]] addresses.', - rightRole: '[[udp|UDP]] provides the fast, {{connectionless|connectionless}} transport that makes single-packet [[dns|DNS]] lookups efficient.' + leftRole: + '[[dns|DNS]] defines the query/response format for translating domain names to [[ip|IP]] addresses.', + rightRole: + '[[udp|UDP]] provides the fast, {{connectionless|connectionless}} transport that makes single-packet [[dns|DNS]] lookups efficient.' }, { ids: ['coap', 'udp'], type: 'relationship', summary: - '[[coap|CoAP]] runs over [[udp|UDP]] to provide a lightweight [[rest|REST]]-like {{request-response|request-response}} model for constrained IoT devices that cannot afford [[tcp|TCP]]\'s overhead.', + "[[coap|CoAP]] runs over [[udp|UDP]] to provide a lightweight [[rest|REST]]-like {{request-response|request-response}} model for constrained IoT devices that cannot afford [[tcp|TCP]]'s overhead.", howTheyWork: - '[[coap|CoAP]] sends compact binary messages as [[udp|UDP]] datagrams, using a 4-byte fixed header and message IDs for optional reliability via confirmable messages. The client sends a [[coap|CoAP]] request (GET, PUT, POST, DELETE) in a single [[udp|UDP]] packet to the server, which replies with a response in another datagram. [[coap|CoAP]] adds its own simple {{retransmission|retransmission}} over [[udp|UDP]] rather than requiring [[tcp|TCP]]\'s full connection management.', - leftRole: '[[coap|CoAP]] provides RESTful resource semantics (methods, URIs, {{content-negotiation|content negotiation}}) optimized for constrained networks.', - rightRole: '[[udp|UDP]] provides the minimal, {{connectionless|connectionless}} transport that keeps [[coap|CoAP]] lightweight enough for battery-powered sensors.' + "[[coap|CoAP]] sends compact binary messages as [[udp|UDP]] datagrams, using a 4-byte fixed header and message IDs for optional reliability via confirmable messages. The client sends a [[coap|CoAP]] request (GET, PUT, POST, DELETE) in a single [[udp|UDP]] packet to the server, which replies with a response in another datagram. [[coap|CoAP]] adds its own simple {{retransmission|retransmission}} over [[udp|UDP]] rather than requiring [[tcp|TCP]]'s full connection management.", + leftRole: + '[[coap|CoAP]] provides RESTful resource semantics (methods, URIs, {{content-negotiation|content negotiation}}) optimized for constrained networks.', + rightRole: + '[[udp|UDP]] provides the minimal, {{connectionless|connectionless}} transport that keeps [[coap|CoAP]] lightweight enough for battery-powered sensors.' }, { ids: ['dhcp', 'udp'], @@ -1271,29 +2069,35 @@ const relationshipPairs: ProtocolPair[] = [ summary: '[[dhcp|DHCP]] uses [[udp|UDP]] for automatic [[ip|IP]] address assignment, since clients cannot establish [[tcp|TCP]] connections before they have an [[ip|IP]] address.', howTheyWork: - 'A [[dhcp|DHCP]] client broadcasts a DISCOVER message from port 68 as a [[udp|UDP]] datagram because it has no [[ip|IP]] address yet and cannot perform [[tcp|TCP]]\'s {{handshake|handshake}}. The [[dhcp|DHCP]] server listens on port 67 and responds with an OFFER, also via [[udp|UDP]] {{broadcast|broadcast}} or {{unicast|unicast}}. This bootstrap problem makes [[udp|UDP]] the only viable transport β€” [[tcp|TCP]] requires an established [[ip|IP]] address on both sides before communication can begin.', - leftRole: '[[dhcp|DHCP]] provides the protocol logic for discovering servers, requesting leases, and assigning [[ip|IP]] configuration.', - rightRole: '[[udp|UDP]] provides the {{connectionless|connectionless}} transport necessary for communication before a client has an [[ip|IP]] address.' + "A [[dhcp|DHCP]] client broadcasts a DISCOVER message from port 68 as a [[udp|UDP]] datagram because it has no [[ip|IP]] address yet and cannot perform [[tcp|TCP]]'s {{handshake|handshake}}. The [[dhcp|DHCP]] server listens on port 67 and responds with an OFFER, also via [[udp|UDP]] {{broadcast|broadcast}} or {{unicast|unicast}}. This bootstrap problem makes [[udp|UDP]] the only viable transport β€” [[tcp|TCP]] requires an established [[ip|IP]] address on both sides before communication can begin.", + leftRole: + '[[dhcp|DHCP]] provides the protocol logic for discovering servers, requesting leases, and assigning [[ip|IP]] configuration.', + rightRole: + '[[udp|UDP]] provides the {{connectionless|connectionless}} transport necessary for communication before a client has an [[ip|IP]] address.' }, { ids: ['http3', 'udp'], type: 'relationship', summary: - '[[http3|HTTP/3]] runs over [[quic|QUIC]], which itself runs over [[udp|UDP]], giving [[http3|HTTP/3]] multiplexed streams without [[tcp|TCP]]\'s {{head-of-line-blocking|head-of-line blocking}} while remaining deployable on existing networks.', + "[[http3|HTTP/3]] runs over [[quic|QUIC]], which itself runs over [[udp|UDP]], giving [[http3|HTTP/3]] multiplexed streams without [[tcp|TCP]]'s {{head-of-line-blocking|head-of-line blocking}} while remaining deployable on existing networks.", howTheyWork: - '[[udp|UDP]] carries [[quic|QUIC]] packets, which in turn carry [[http3|HTTP/3]] frames. [[quic|QUIC]] builds reliable, encrypted, multiplexed streams on top of [[udp|UDP]] datagrams, and [[http3|HTTP/3]] maps its {{request-response|request-response}} semantics onto those [[quic|QUIC]] streams. [[udp|UDP]]\'s universal {{nat|NAT}} and {{firewall|firewall}} traversal makes [[quic|QUIC]] deployable without changes to network infrastructure.', - leftRole: '[[http3|HTTP/3]] provides the application-layer {{request-response|request-response}} semantics, header compression ({{qpack|QPACK}}), and {{server-push|server push}}.', - rightRole: '[[udp|UDP]] provides the underlying datagram delivery that allows [[quic|QUIC]] and [[http3|HTTP/3]] to bypass [[tcp|TCP]]\'s {{head-of-line-blocking|head-of-line blocking}}.' + "[[udp|UDP]] carries [[quic|QUIC]] packets, which in turn carry [[http3|HTTP/3]] frames. [[quic|QUIC]] builds reliable, encrypted, multiplexed streams on top of [[udp|UDP]] datagrams, and [[http3|HTTP/3]] maps its {{request-response|request-response}} semantics onto those [[quic|QUIC]] streams. [[udp|UDP]]'s universal {{nat|NAT}} and {{firewall|firewall}} traversal makes [[quic|QUIC]] deployable without changes to network infrastructure.", + leftRole: + '[[http3|HTTP/3]] provides the application-layer {{request-response|request-response}} semantics, header compression ({{qpack|QPACK}}), and {{server-push|server push}}.', + rightRole: + "[[udp|UDP]] provides the underlying datagram delivery that allows [[quic|QUIC]] and [[http3|HTTP/3]] to bypass [[tcp|TCP]]'s {{head-of-line-blocking|head-of-line blocking}}." }, { ids: ['ntp', 'udp'], type: 'relationship', summary: - '[[ntp|NTP]] uses [[udp|UDP]] for clock synchronization because accurate timekeeping requires minimal, predictable {{latency|latency}} that [[tcp|TCP]]\'s {{handshake|handshake}} and retransmissions would distort.', + "[[ntp|NTP]] uses [[udp|UDP]] for clock synchronization because accurate timekeeping requires minimal, predictable {{latency|latency}} that [[tcp|TCP]]'s {{handshake|handshake}} and retransmissions would distort.", howTheyWork: - 'An [[ntp|NTP]] client sends a small [[udp|UDP]] datagram (48 bytes) to a time server on port 123, recording its send timestamp. The server stamps the packet with its receive and transmit times, then replies via [[udp|UDP]]. The client uses all four timestamps to calculate network delay and clock {{offset|offset}}. [[tcp|TCP]]\'s variable {{latency|latency}} from connection setup and {{retransmission|retransmission}} would corrupt these precise timing measurements.', - leftRole: '[[ntp|NTP]] provides the timestamping protocol and algorithms for calculating clock {{offset|offset}} and drift.', - rightRole: '[[udp|UDP]] provides the lightweight, fixed-overhead transport that preserves the timing accuracy [[ntp|NTP]] requires.' + "An [[ntp|NTP]] client sends a small [[udp|UDP]] datagram (48 bytes) to a time server on port 123, recording its send timestamp. The server stamps the packet with its receive and transmit times, then replies via [[udp|UDP]]. The client uses all four timestamps to calculate network delay and clock {{offset|offset}}. [[tcp|TCP]]'s variable {{latency|latency}} from connection setup and {{retransmission|retransmission}} would corrupt these precise timing measurements.", + leftRole: + '[[ntp|NTP]] provides the timestamping protocol and algorithms for calculating clock {{offset|offset}} and drift.', + rightRole: + '[[udp|UDP]] provides the lightweight, fixed-overhead transport that preserves the timing accuracy [[ntp|NTP]] requires.' }, { ids: ['rtp', 'udp'], @@ -1301,9 +2105,11 @@ const relationshipPairs: ProtocolPair[] = [ summary: '[[rtp|RTP]] carries real-time audio and video over [[udp|UDP]], accepting occasional packet loss in {{exchange|exchange}} for the low {{latency|latency}} that interactive media demands.', howTheyWork: - '[[rtp|RTP]] adds a 12-byte header to each media packet with sequence numbers, timestamps, and {{payload|payload}} type identifiers, then sends them as [[udp|UDP]] datagrams. The receiver uses sequence numbers to detect loss and reorder packets, and timestamps to synchronize playback. [[udp|UDP]]\'s lack of {{retransmission|retransmission}} is a feature here β€” retransmitting a dropped video frame would arrive too late to be useful.', - leftRole: '[[rtp|RTP]] provides media framing, sequencing, timestamping, and {{payload|payload}} identification for audio/video streams.', - rightRole: '[[udp|UDP]] provides the low-{{latency|latency}}, no-{{retransmission|retransmission}} transport that real-time media playback requires.' + "[[rtp|RTP]] adds a 12-byte header to each media packet with sequence numbers, timestamps, and {{payload|payload}} type identifiers, then sends them as [[udp|UDP]] datagrams. The receiver uses sequence numbers to detect loss and reorder packets, and timestamps to synchronize playback. [[udp|UDP]]'s lack of {{retransmission|retransmission}} is a feature here β€” retransmitting a dropped video frame would arrive too late to be useful.", + leftRole: + '[[rtp|RTP]] provides media framing, sequencing, timestamping, and {{payload|payload}} identification for audio/video streams.', + rightRole: + '[[udp|UDP]] provides the low-{{latency|latency}}, no-{{retransmission|retransmission}} transport that real-time media playback requires.' }, { ids: ['sctp', 'udp'], @@ -1312,18 +2118,22 @@ const relationshipPairs: ProtocolPair[] = [ '[[sctp|SCTP]] can be encapsulated inside [[udp|UDP]] datagrams to traverse NATs and firewalls that would otherwise block native [[sctp|SCTP]] packets.', howTheyWork: 'Since most {{nat|NAT}} devices and firewalls only understand [[tcp|TCP]] and [[udp|UDP]], [[sctp|SCTP]] packets are wrapped inside [[udp|UDP]] datagrams ([[rfc:6951|RFC 6951]]) to pass through unmodified network infrastructure. The [[udp|UDP]] header provides the {{nat|NAT}}-traversal capability while [[sctp|SCTP]] inside provides multi-streaming, message boundaries, and {{multi-homing|multi-homing}}. This {{encapsulation|encapsulation}} is how [[webrtc|WebRTC]] data channels deliver [[sctp|SCTP]] over the public internet.', - leftRole: '[[sctp|SCTP]] provides multi-stream, message-oriented reliable delivery with built-in {{multi-homing|multi-homing}}.', - rightRole: '[[udp|UDP]] provides the {{nat|NAT}}-traversable envelope that lets [[sctp|SCTP]] packets cross firewalls and middleboxes on the public internet.' + leftRole: + '[[sctp|SCTP]] provides multi-stream, message-oriented reliable delivery with built-in {{multi-homing|multi-homing}}.', + rightRole: + '[[udp|UDP]] provides the {{nat|NAT}}-traversable envelope that lets [[sctp|SCTP]] packets cross firewalls and middleboxes on the public internet.' }, { ids: ['sip', 'udp'], type: 'relationship', summary: - '[[sip|SIP]] commonly uses [[udp|UDP]] for {{voip|VoIP}} call {{signaling|signaling}} because its short, independent messages benefit from [[udp|UDP]]\'s low overhead and fast delivery.', + "[[sip|SIP]] commonly uses [[udp|UDP]] for {{voip|VoIP}} call {{signaling|signaling}} because its short, independent messages benefit from [[udp|UDP]]'s low overhead and fast delivery.", howTheyWork: - '[[sip|SIP]] sends {{signaling|signaling}} messages ({{sip-invite|INVITE}}, {{ack|ACK}}, BYE) as [[udp|UDP]] datagrams, typically on port 5060. Each [[sip|SIP]] message is self-contained and fits within a single datagram, making [[tcp|TCP]]\'s connection overhead unnecessary for most call setups. [[sip|SIP]] includes its own application-layer {{retransmission|retransmission}} timers for reliability, re-sending requests if no response arrives within the timeout period.', - leftRole: '[[sip|SIP]] provides the {{signaling|signaling}} protocol for initiating, modifying, and terminating multimedia sessions.', - rightRole: '[[udp|UDP]] provides the fast, {{connectionless|connectionless}} transport that keeps call setup {{latency|latency}} low for {{voip|VoIP}} {{signaling|signaling}}.' + "[[sip|SIP]] sends {{signaling|signaling}} messages ({{sip-invite|INVITE}}, {{ack|ACK}}, BYE) as [[udp|UDP]] datagrams, typically on port 5060. Each [[sip|SIP]] message is self-contained and fits within a single datagram, making [[tcp|TCP]]'s connection overhead unnecessary for most call setups. [[sip|SIP]] includes its own application-layer {{retransmission|retransmission}} timers for reliability, re-sending requests if no response arrives within the timeout period.", + leftRole: + '[[sip|SIP]] provides the {{signaling|signaling}} protocol for initiating, modifying, and terminating multimedia sessions.', + rightRole: + '[[udp|UDP]] provides the fast, {{connectionless|connectionless}} transport that keeps call setup {{latency|latency}} low for {{voip|VoIP}} {{signaling|signaling}}.' }, { ids: ['udp', 'webrtc'], @@ -1331,9 +2141,11 @@ const relationshipPairs: ProtocolPair[] = [ summary: '[[webrtc|WebRTC]] uses [[udp|UDP]] as its primary transport for {{peer-to-peer|peer-to-peer}} audio, video, and data channels, prioritizing low {{latency|latency}} over guaranteed delivery.', howTheyWork: - '[[webrtc|WebRTC]]\'s media stack sends {{srtp|SRTP}}-encrypted audio/video packets as [[udp|UDP]] datagrams between peers, using {{ice|ICE}} for {{nat|NAT}} traversal via {{stun|STUN}}/{{turn|TURN}}. Data channels use [[sctp|SCTP]] encapsulated in {{dtls|DTLS}} over [[udp|UDP]]. The entire [[webrtc|WebRTC]] transport is built on [[udp|UDP]] because interactive communication requires packets to arrive quickly or not at all β€” [[tcp|TCP]]\'s {{retransmission|retransmission}} would add unacceptable delay.', - leftRole: '[[udp|UDP]] provides the low-{{latency|latency}} datagram transport that all [[webrtc|WebRTC]] media and data channels are built upon.', - rightRole: '[[webrtc|WebRTC]] provides the {{peer-to-peer|peer-to-peer}} media framework, {{encryption|encryption}} ({{dtls|DTLS}}/{{srtp|SRTP}}), {{nat|NAT}} traversal ({{ice|ICE}}), and data channels on top.' + "[[webrtc|WebRTC]]'s media stack sends {{srtp|SRTP}}-encrypted audio/video packets as [[udp|UDP]] datagrams between peers, using {{ice|ICE}} for {{nat|NAT}} traversal via {{stun|STUN}}/{{turn|TURN}}. Data channels use [[sctp|SCTP]] encapsulated in {{dtls|DTLS}} over [[udp|UDP]]. The entire [[webrtc|WebRTC]] transport is built on [[udp|UDP]] because interactive communication requires packets to arrive quickly or not at all β€” [[tcp|TCP]]'s {{retransmission|retransmission}} would add unacceptable delay.", + leftRole: + '[[udp|UDP]] provides the low-{{latency|latency}} datagram transport that all [[webrtc|WebRTC]] media and data channels are built upon.', + rightRole: + '[[webrtc|WebRTC]] provides the {{peer-to-peer|peer-to-peer}} media framework, {{encryption|encryption}} ({{dtls|DTLS}}/{{srtp|SRTP}}), {{nat|NAT}} traversal ({{ice|ICE}}), and data channels on top.' }, // ── TLS encryption ─────────────────────────────────────────── @@ -1345,8 +2157,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[tls|TLS]] wraps [[amqp|AMQP]] connections to create AMQPS, encrypting all {{broker|message broker}} communication between clients and servers.', howTheyWork: 'An [[amqp|AMQP]] client connects to port 5671 (AMQPS) and performs a [[tls|TLS]] {{handshake|handshake}} before any [[amqp|AMQP]] protocol negotiation begins. Once [[tls|TLS]] is established, the standard [[amqp|AMQP]] {{handshake|handshake}} and all subsequent message publishing, consuming, and acknowledgments flow through the encrypted channel. Without [[tls|TLS]], credentials and message payloads travel in plaintext on the default port 5672.', - leftRole: '[[amqp|AMQP]] provides the {{broker|message broker}} semantics β€” exchanges, queues, bindings, and delivery guarantees.', - rightRole: '[[tls|TLS]] provides confidentiality, integrity, and authentication for all [[amqp|AMQP]] traffic.' + leftRole: + '[[amqp|AMQP]] provides the {{broker|message broker}} semantics β€” exchanges, queues, bindings, and delivery guarantees.', + rightRole: + '[[tls|TLS]] provides confidentiality, integrity, and authentication for all [[amqp|AMQP]] traffic.' }, { ids: ['dash', 'tls'], @@ -1355,8 +2169,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[dash|DASH]] delivers adaptive streaming segments over HTTPS, relying on [[tls|TLS]] to protect video content and {{drm|DRM}} license exchanges in {{transit|transit}}.', howTheyWork: 'A [[dash|DASH]] player fetches the {{mpd|MPD}} {{manifest|manifest}} and all media segments via HTTPS requests, each secured by [[tls|TLS]]. The [[tls|TLS]] layer encrypts segment downloads and prevents tampering, which is especially critical when {{drm|DRM}} license acquisition URLs are embedded in the {{manifest|manifest}}.', - leftRole: '[[dash|DASH]] defines the {{adaptive-bitrate|adaptive bitrate streaming}} logic, {{manifest|manifest}} format, and segment request pattern.', - rightRole: '[[tls|TLS]] provides confidentiality and integrity for {{manifest|manifest}} and segment downloads over HTTPS.' + leftRole: + '[[dash|DASH]] defines the {{adaptive-bitrate|adaptive bitrate streaming}} logic, {{manifest|manifest}} format, and segment request pattern.', + rightRole: + '[[tls|TLS]] provides confidentiality and integrity for {{manifest|manifest}} and segment downloads over HTTPS.' }, { ids: ['dns', 'tls'], @@ -1365,8 +2181,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[dns|DNS]] over [[tls|TLS]] (DoT) encrypts [[dns|DNS]] queries by wrapping them in a [[tls|TLS]] connection on port 853, preventing eavesdropping and manipulation of name resolution.', howTheyWork: 'A [[dns|DNS]] client establishes a [[tls|TLS]] connection to a resolver on port 853 ([[rfc:7858|RFC 7858]]) before sending any [[dns|DNS]] queries. Each query and response travels through the encrypted [[tls|TLS]] channel, preventing network observers from seeing which domains are being resolved. Without DoT, standard [[dns|DNS]] queries on port 53 are sent in plaintext and are trivially observable or spoofable.', - leftRole: '[[dns|DNS]] provides the query/response protocol for translating domain names to [[ip|IP]] addresses.', - rightRole: '[[tls|TLS]] provides confidentiality and integrity, preventing eavesdropping and tampering of [[dns|DNS]] lookups.' + leftRole: + '[[dns|DNS]] provides the query/response protocol for translating domain names to [[ip|IP]] addresses.', + rightRole: + '[[tls|TLS]] provides confidentiality and integrity, preventing eavesdropping and tampering of [[dns|DNS]] lookups.' }, { ids: ['ftp', 'tls'], @@ -1375,8 +2193,10 @@ const relationshipPairs: ProtocolPair[] = [ '{{ftps|FTPS}} adds [[tls|TLS]] {{encryption|encryption}} to [[ftp|FTP]], securing both the control channel (commands and credentials) and data channel (file transfers).', howTheyWork: 'In explicit {{ftps|FTPS}}, the client connects to port 21 and issues an {{smtp-auth|AUTH}} [[tls|TLS]] command to upgrade the control connection to [[tls|TLS]] before sending credentials. In implicit {{ftps|FTPS}}, the client connects directly to port 990 where [[tls|TLS]] is required from the start. Both modes can also encrypt the data channel, ensuring file contents are protected in {{transit|transit}}.', - leftRole: '[[ftp|FTP]] provides the file transfer commands, directory listing, and data channel negotiation.', - rightRole: '[[tls|TLS]] provides confidentiality, integrity, and authentication for [[ftp|FTP]] control and data channels.' + leftRole: + '[[ftp|FTP]] provides the file transfer commands, directory listing, and data channel negotiation.', + rightRole: + '[[tls|TLS]] provides confidentiality, integrity, and authentication for [[ftp|FTP]] control and data channels.' }, { ids: ['grpc', 'tls'], @@ -1385,8 +2205,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[grpc|gRPC]] strongly recommends [[tls|TLS]] for all connections, and most deployments require it to authenticate services and encrypt Protobuf payloads in {{transit|transit}}.', howTheyWork: '[[grpc|gRPC]] runs over [[http2|HTTP/2]], which in practice requires [[tls|TLS]]. The [[tls|TLS]] {{handshake|handshake}} authenticates the server (and optionally the client via mutual [[tls|TLS]]) before any {{rpc|RPC}} calls are made. [[grpc|gRPC]] channel credentials are configured with [[tls|TLS]] certificates, and the framework rejects insecure connections by default in production configurations.', - leftRole: '[[grpc|gRPC]] provides the {{rpc|RPC}} framework, Protobuf {{serialization|serialization}}, and service definition layer.', - rightRole: '[[tls|TLS]] provides confidentiality, integrity, and mutual authentication for [[grpc|gRPC]] channels.' + leftRole: + '[[grpc|gRPC]] provides the {{rpc|RPC}} framework, Protobuf {{serialization|serialization}}, and service definition layer.', + rightRole: + '[[tls|TLS]] provides confidentiality, integrity, and mutual authentication for [[grpc|gRPC]] channels.' }, { ids: ['hls', 'tls'], @@ -1395,8 +2217,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[hls|HLS]] delivers adaptive streaming playlists and media segments over HTTPS, relying on [[tls|TLS]] to protect content and {{encryption|encryption}} keys in {{transit|transit}}.', howTheyWork: 'An [[hls|HLS]] player fetches M3U8 playlists and .ts/.fmp4 segments via HTTPS, with [[tls|TLS]] encrypting every request. This is critical because [[hls|HLS]] playlists often reference {{aes-128|AES-128}} key URIs for content protection β€” without [[tls|TLS]], these decryption keys could be intercepted. {{apple|Apple}} requires HTTPS for all [[hls|HLS]] content in App Transport Security.', - leftRole: '[[hls|HLS]] defines the playlist format, segment structure, and adaptive bitrate switching logic.', - rightRole: '[[tls|TLS]] provides confidentiality and integrity for playlist, segment, and {{encryption|encryption}} key downloads.' + leftRole: + '[[hls|HLS]] defines the playlist format, segment structure, and adaptive bitrate switching logic.', + rightRole: + '[[tls|TLS]] provides confidentiality and integrity for playlist, segment, and {{encryption|encryption}} key downloads.' }, { ids: ['http1', 'tls'], @@ -1405,8 +2229,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[tls|TLS]] encrypts [[http1|[[http1|HTTP/1]].1]] connections to create HTTPS, the foundational secure web protocol serving the majority of internet traffic on port 443.', howTheyWork: 'A client connects to port 443 and completes a [[tls|TLS]] {{handshake|handshake}}, authenticating the server via its {{certificate|certificate}} and negotiating {{encryption|encryption}} keys. Once the [[tls|TLS]] channel is established, standard [[http1|[[http1|HTTP/1]].1]] requests and responses flow through it with full {{encryption|encryption}}. Without [[tls|TLS]], [[http1|[[http1|HTTP/1]].1]] on port 80 transmits headers, cookies, and body content in plaintext.', - leftRole: '[[http1|[[http1|HTTP/1]].1]] provides the {{request-response|request-response}} semantics, methods, headers, and {{content-negotiation|content negotiation}}.', - rightRole: '[[tls|TLS]] provides confidentiality, integrity, and server authentication for all {{http-method|HTTP}} traffic.' + leftRole: + '[[http1|[[http1|HTTP/1]].1]] provides the {{request-response|request-response}} semantics, methods, headers, and {{content-negotiation|content negotiation}}.', + rightRole: + '[[tls|TLS]] provides confidentiality, integrity, and server authentication for all {{http-method|HTTP}} traffic.' }, { ids: ['http2', 'tls'], @@ -1415,8 +2241,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[http2|HTTP/2]] effectively requires [[tls|TLS]] in practice, using the {{alpn|ALPN}} extension during the [[tls|TLS]] {{handshake|handshake}} to negotiate the h2 protocol without an extra round trip.', howTheyWork: 'Although [[http2|HTTP/2]] technically allows cleartext (h2c), all major browsers only support [[http2|HTTP/2]] over [[tls|TLS]]. During the [[tls|TLS]] {{handshake|handshake}}, the client advertises "h2" via {{alpn|ALPN}} ({{alpn|Application-Layer Protocol Negotiation}}), and the server selects it. This eliminates the need for an {{http-method|HTTP}} Upgrade dance and ensures the multiplexed binary connection is always encrypted.', - leftRole: '[[http2|HTTP/2]] provides multiplexed streams, header compression, and {{server-push|server push}} over a single connection.', - rightRole: '[[tls|TLS]] provides {{encryption|encryption}} and enables h2 protocol negotiation via the {{alpn|ALPN}} extension.' + leftRole: + '[[http2|HTTP/2]] provides multiplexed streams, header compression, and {{server-push|server push}} over a single connection.', + rightRole: + '[[tls|TLS]] provides {{encryption|encryption}} and enables h2 protocol negotiation via the {{alpn|ALPN}} extension.' }, { ids: ['http3', 'tls'], @@ -1425,8 +2253,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[http3|HTTP/3]] integrates [[tls|TLS]] 1.3 directly into the [[quic|QUIC]] transport layer, making {{encryption|encryption}} mandatory and reducing connection setup to a single round trip.', howTheyWork: 'Unlike [[http1|[[http1|HTTP/1]].1]] and [[http2|HTTP/2]] where [[tls|TLS]] is a separate layer on top of [[tcp|TCP]], [[quic|QUIC]] embeds the [[tls|TLS]] 1.3 {{handshake|handshake}} into its own transport {{handshake|handshake}}. Cryptographic key negotiation happens simultaneously with connection establishment, achieving {{one-rtt|1-RTT}} setup (or {{zero-rtt|0-RTT}} for resumed connections). Every [[quic|QUIC]] packet is authenticated and encrypted β€” there is no unencrypted [[http3|HTTP/3]].', - leftRole: '[[http3|HTTP/3]] provides multiplexed {{request-response|request-response}} streams over [[quic|QUIC]] without {{head-of-line-blocking|head-of-line blocking}}.', - rightRole: '[[tls|TLS]] 1.3 provides the cryptographic {{handshake|handshake}} and {{encryption|encryption}} integrated directly into [[quic|QUIC]].' + leftRole: + '[[http3|HTTP/3]] provides multiplexed {{request-response|request-response}} streams over [[quic|QUIC]] without {{head-of-line-blocking|head-of-line blocking}}.', + rightRole: + '[[tls|TLS]] 1.3 provides the cryptographic {{handshake|handshake}} and {{encryption|encryption}} integrated directly into [[quic|QUIC]].' }, { ids: ['kafka', 'tls'], @@ -1435,8 +2265,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[kafka|Kafka]] supports [[tls|TLS]] to encrypt all communication between producers, consumers, and brokers, as well as inter-broker replication traffic.', howTheyWork: '[[kafka|Kafka]] listeners can be configured with {{ssl|SSL}}/[[tls|TLS]] security, requiring clients to perform a [[tls|TLS]] {{handshake|handshake}} when connecting to brokers. [[tls|TLS]] encrypts produce requests, {{imap-fetch|fetch}} responses, and metadata exchanges. Combined with {{sasl|SASL}} authentication, [[tls|TLS]] also enables mutual authentication between clients and brokers and secures inter-broker replication across data centers.', - leftRole: '[[kafka|Kafka]] provides the distributed log, {{topic|topic}} partitioning, consumer groups, and replication.', - rightRole: '[[tls|TLS]] provides confidentiality, integrity, and optional mutual authentication for [[kafka|Kafka]] connections.' + leftRole: + '[[kafka|Kafka]] provides the distributed log, {{topic|topic}} partitioning, consumer groups, and replication.', + rightRole: + '[[tls|TLS]] provides confidentiality, integrity, and optional mutual authentication for [[kafka|Kafka]] connections.' }, { ids: ['mptcp', 'tls'], @@ -1445,8 +2277,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[tls|TLS]] encrypts [[mptcp|MPTCP]] connections just as it does standard [[tcp|TCP]], securing data flowing across multiple network paths simultaneously.', howTheyWork: '[[mptcp|MPTCP]] establishes multiple [[tcp|TCP]] subflows across different network interfaces (e.g., [[wifi|Wi-Fi]] and cellular). [[tls|TLS]] operates on the [[mptcp|MPTCP]] connection as a whole, performing its {{handshake|handshake}} once over the initial {{subflow|subflow}}. The encrypted [[tls|TLS]] session then transparently spans all subflows, so data remains protected regardless of which network path carries it.', - leftRole: '[[mptcp|MPTCP]] provides multi-path transport, aggregating {{bandwidth|bandwidth}} and enabling seamless {{failover|failover}}.', - rightRole: '[[tls|TLS]] provides confidentiality, integrity, and authentication across all [[mptcp|MPTCP]] subflows.' + leftRole: + '[[mptcp|MPTCP]] provides multi-path transport, aggregating {{bandwidth|bandwidth}} and enabling seamless {{failover|failover}}.', + rightRole: + '[[tls|TLS]] provides confidentiality, integrity, and authentication across all [[mptcp|MPTCP]] subflows.' }, { ids: ['mqtt', 'tls'], @@ -1455,8 +2289,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[tls|TLS]] wraps [[mqtt|MQTT]] connections to create MQTTS, encrypting all pub/sub messaging between IoT devices and the broker on port 8883.', howTheyWork: 'An [[mqtt|MQTT]] client connects to the broker on port 8883 (MQTTS) and completes a [[tls|TLS]] {{handshake|handshake}} before sending the [[mqtt|MQTT]] {{mqtt-connect|CONNECT}} packet. All subsequent {{mqtt-publish|PUBLISH}}, {{mqtt-subscribe|SUBSCRIBE}}, and acknowledgment packets are encrypted. This is critical for IoT deployments where sensor data and device credentials traverse untrusted networks.', - leftRole: '[[mqtt|MQTT]] provides lightweight pub/sub messaging with {{topic|topic}} hierarchies and QoS levels.', - rightRole: '[[tls|TLS]] provides confidentiality, integrity, and authentication for all [[mqtt|MQTT]] broker communication.' + leftRole: + '[[mqtt|MQTT]] provides lightweight pub/sub messaging with {{topic|topic}} hierarchies and QoS levels.', + rightRole: + '[[tls|TLS]] provides confidentiality, integrity, and authentication for all [[mqtt|MQTT]] broker communication.' }, { ids: ['quic', 'tls'], @@ -1465,8 +2301,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[quic|QUIC]] deeply integrates [[tls|TLS]] 1.3 into its transport {{handshake|handshake}}, making {{encryption|encryption}} inseparable from connection establishment rather than an optional add-on layer.', howTheyWork: '[[quic|QUIC]] embeds the [[tls|TLS]] 1.3 {{handshake|handshake}} within its own transport {{handshake|handshake}} messages, combining cryptographic negotiation with connection setup in a single round trip. [[tls|TLS]] provides the key {{exchange|exchange}} and cipher negotiation, while [[quic|QUIC]] uses the derived keys to encrypt every packet including most header fields. Unlike [[tcp|TCP]]+[[tls|TLS]], there is no unencrypted [[quic|QUIC]] β€” the protocols are fused by design.', - leftRole: '[[quic|QUIC]] provides multiplexed streams, {{congestion-control|congestion control}}, and {{connection-migration|connection migration}} over [[udp|UDP]].', - rightRole: '[[tls|TLS]] 1.3 provides the cryptographic {{handshake|handshake}}, key derivation, and {{cipher-suite|cipher suite}} negotiation within [[quic|QUIC]].' + leftRole: + '[[quic|QUIC]] provides multiplexed streams, {{congestion-control|congestion control}}, and {{connection-migration|connection migration}} over [[udp|UDP]].', + rightRole: + '[[tls|TLS]] 1.3 provides the cryptographic {{handshake|handshake}}, key derivation, and {{cipher-suite|cipher suite}} negotiation within [[quic|QUIC]].' }, { ids: ['rtmp', 'tls'], @@ -1475,8 +2313,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[tls|TLS]] wraps [[rtmp|RTMP]] connections to create RTMPS, encrypting live stream ingest traffic between encoders and media servers on port 443.', howTheyWork: 'An encoder (e.g., OBS) connects to the media server on port 443 and performs a [[tls|TLS]] {{handshake|handshake}} before beginning the [[rtmp|RTMP]] {{handshake|handshake}}. All subsequent [[rtmp|RTMP]] chunks β€” including the stream key, audio, and video data β€” flow through the encrypted channel. RTMPS is now required by major platforms like Facebook Live and YouTube Live for stream ingest.', - leftRole: '[[rtmp|RTMP]] provides the live streaming protocol for publishing audio/video chunks to media servers.', - rightRole: '[[tls|TLS]] provides confidentiality and integrity, protecting stream keys and media content in {{transit|transit}}.' + leftRole: + '[[rtmp|RTMP]] provides the live streaming protocol for publishing audio/video chunks to media servers.', + rightRole: + '[[tls|TLS]] provides confidentiality and integrity, protecting stream keys and media content in {{transit|transit}}.' }, { ids: ['sip', 'tls'], @@ -1485,8 +2325,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[tls|TLS]] secures [[sip|SIP]] {{signaling|signaling}} to create SIPS, encrypting call setup, authentication, and routing between {{voip|VoIP}} endpoints and proxies.', howTheyWork: 'A [[sip|SIP]] client connects to a proxy or registrar over [[tls|TLS]] (typically port 5061), encrypting all {{signaling|signaling}} messages including REGISTER, {{sip-invite|INVITE}}, and BYE requests. The SIPS {{uri|URI}} scheme (sips:) mandates [[tls|TLS]] hop-by-hop across the {{signaling|signaling}} path. Without [[tls|TLS]], [[sip|SIP]] headers expose caller identity, credentials, and call routing in plaintext.', - leftRole: '[[sip|SIP]] provides the {{signaling|signaling}} protocol for establishing, modifying, and terminating voice/video sessions.', - rightRole: '[[tls|TLS]] provides confidentiality and integrity for [[sip|SIP]] {{signaling|signaling}}, protecting credentials and call metadata.' + leftRole: + '[[sip|SIP]] provides the {{signaling|signaling}} protocol for establishing, modifying, and terminating voice/video sessions.', + rightRole: + '[[tls|TLS]] provides confidentiality and integrity for [[sip|SIP]] {{signaling|signaling}}, protecting credentials and call metadata.' }, { ids: ['smtp', 'tls'], @@ -1495,8 +2337,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[tls|TLS]] secures [[smtp|SMTP]] email delivery via {{starttls|STARTTLS}} (opportunistic upgrade on port 587) or SMTPS (implicit [[tls|TLS]] on port 465), encrypting messages between mail servers.', howTheyWork: 'An [[smtp|SMTP]] client connects to a mail server and issues the {{starttls|STARTTLS}} command to upgrade the plaintext connection to [[tls|TLS]] before sending credentials or message content. Alternatively, implicit [[tls|TLS]] on port 465 establishes {{encryption|encryption}} immediately. {{mta|MTA}}-{{sts|STS}} and DANE policies can enforce [[tls|TLS]] to prevent downgrade attacks between mail servers.', - leftRole: '[[smtp|SMTP]] provides the email delivery protocol for routing messages between mail transfer agents.', - rightRole: '[[tls|TLS]] provides confidentiality and integrity for email content and authentication credentials in {{transit|transit}}.' + leftRole: + '[[smtp|SMTP]] provides the email delivery protocol for routing messages between mail transfer agents.', + rightRole: + '[[tls|TLS]] provides confidentiality and integrity for email content and authentication credentials in {{transit|transit}}.' }, { ids: ['tls', 'websockets'], @@ -1505,8 +2349,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[tls|TLS]] secures [[websockets|WebSocket]] connections to create WSS (wss://), encrypting the {{full-duplex|full-duplex}} message channel between browsers and servers.', howTheyWork: 'A client connects to port 443, completes a [[tls|TLS]] {{handshake|handshake}}, and then performs the [[websockets|WebSocket]] {{http-method|HTTP}} Upgrade over the encrypted connection. Once upgraded, all [[websockets|WebSocket]] frames β€” both text and binary β€” flow through the [[tls|TLS]] channel. WSS is effectively required in production because most browsers block mixed content and many proxies interfere with unencrypted [[websockets|WebSocket]] connections.', - leftRole: '[[tls|TLS]] provides confidentiality, integrity, and authentication for the [[websockets|WebSocket]] connection.', - rightRole: '[[websockets|WebSocket]] provides persistent, {{full-duplex|full-duplex}}, message-oriented communication over the secure channel.' + leftRole: + '[[tls|TLS]] provides confidentiality, integrity, and authentication for the [[websockets|WebSocket]] connection.', + rightRole: + '[[websockets|WebSocket]] provides persistent, {{full-duplex|full-duplex}}, message-oriented communication over the secure channel.' }, { ids: ['tls', 'webrtc'], @@ -1515,8 +2361,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[webrtc|WebRTC]] uses {{dtls|DTLS}} (Datagram [[tls|TLS]]) to perform key {{exchange|exchange}} over [[udp|UDP]], establishing the {{encryption|encryption}} keys used by {{srtp|SRTP}} to protect real-time media streams.', howTheyWork: 'After {{ice|ICE}} connectivity checks establish a [[udp|UDP]] path between peers, a {{dtls|DTLS}} {{handshake|handshake}} occurs over that path to authenticate both endpoints and derive shared {{encryption|encryption}} keys. These keys are then used by {{srtp|SRTP}} to encrypt audio/video media and by [[sctp|SCTP]] (tunneled over {{dtls|DTLS}}) to encrypt data channel messages. Without {{dtls|DTLS}}, [[webrtc|WebRTC]] peers could not establish trust or derive {{encryption|encryption}} keys over {{connectionless|connectionless}} [[udp|UDP]].', - leftRole: '[[tls|TLS]] (as {{dtls|DTLS}}) provides the key {{exchange|exchange}}, peer authentication, and key derivation over [[udp|UDP]].', - rightRole: '[[webrtc|WebRTC]] uses {{dtls|DTLS}}-derived keys for {{srtp|SRTP}} media {{encryption|encryption}} and [[sctp|SCTP]] data channel security.' + leftRole: + '[[tls|TLS]] (as {{dtls|DTLS}}) provides the key {{exchange|exchange}}, peer authentication, and key derivation over [[udp|UDP]].', + rightRole: + '[[webrtc|WebRTC]] uses {{dtls|DTLS}}-derived keys for {{srtp|SRTP}} media {{encryption|encryption}} and [[sctp|SCTP]] data channel security.' }, { ids: ['tls', 'xmpp'], @@ -1525,8 +2373,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[xmpp|XMPP]] uses {{starttls|STARTTLS}} to upgrade client-to-server and server-to-server connections to [[tls|TLS]], encrypting all messaging, presence, and roster data.', howTheyWork: 'After opening an {{xml|XML}} stream, an [[xmpp|XMPP]] client or server sends a {{starttls|STARTTLS}} request to upgrade the connection. Once the [[tls|TLS]] {{handshake|handshake}} completes, a new {{xml|XML}} stream is opened over the encrypted channel. Modern [[xmpp|XMPP]] deployments mandate [[tls|TLS]], and XEP-0368 defines direct [[tls|TLS]] connections on port 5223 as an alternative to the {{starttls|STARTTLS}} upgrade mechanism.', - leftRole: '[[tls|TLS]] provides confidentiality, integrity, and authentication for all [[xmpp|XMPP]] communication.', - rightRole: '[[xmpp|XMPP]] provides the messaging, presence, and roster protocol operating over the encrypted channel.' + leftRole: + '[[tls|TLS]] provides confidentiality, integrity, and authentication for all [[xmpp|XMPP]] communication.', + rightRole: + '[[xmpp|XMPP]] provides the messaging, presence, and roster protocol operating over the encrypted channel.' }, // ── HTTP as transport ──────────────────────────────────────── @@ -1537,9 +2387,11 @@ const relationshipPairs: ProtocolPair[] = [ summary: '[[grpc|gRPC]] uses [[http2|HTTP/2]] as its transport layer, leveraging its multiplexed streams and {{binary-framing|binary framing}} to deliver high-performance remote procedure calls.', howTheyWork: - '[[grpc|gRPC]] maps each {{rpc|RPC}} call to an [[http2|HTTP/2]] stream, using [[http2|HTTP/2]] headers for metadata (method, status, {{content-type|content-type}}) and {{smtp-data|DATA}} frames for serialized Protocol Buffer payloads. [[http2|HTTP/2]]\'s {{multiplexing|multiplexing}} allows many concurrent RPCs over a single [[tcp|TCP]] connection without {{head-of-line-blocking|head-of-line blocking}} at the {{http-method|HTTP}} level.', - leftRole: '[[http2|HTTP/2]] provides multiplexed {{binary-framing|binary framing}}, {{flow-control|flow control}}, and header compression as the transport.', - rightRole: '[[grpc|gRPC]] provides the {{rpc|RPC}} semantics, Protobuf {{serialization|serialization}}, and service definition framework on top.' + "[[grpc|gRPC]] maps each {{rpc|RPC}} call to an [[http2|HTTP/2]] stream, using [[http2|HTTP/2]] headers for metadata (method, status, {{content-type|content-type}}) and {{smtp-data|DATA}} frames for serialized Protocol Buffer payloads. [[http2|HTTP/2]]'s {{multiplexing|multiplexing}} allows many concurrent RPCs over a single [[tcp|TCP]] connection without {{head-of-line-blocking|head-of-line blocking}} at the {{http-method|HTTP}} level.", + leftRole: + '[[http2|HTTP/2]] provides multiplexed {{binary-framing|binary framing}}, {{flow-control|flow control}}, and header compression as the transport.', + rightRole: + '[[grpc|gRPC]] provides the {{rpc|RPC}} semantics, Protobuf {{serialization|serialization}}, and service definition framework on top.' }, { ids: ['dash', 'http1'], @@ -1548,8 +2400,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[dash|DASH]] delivers adaptive video by requesting media segments over [[http1|[[http1|HTTP/1]].1]], using standard web infrastructure for scalable streaming delivery.', howTheyWork: 'The [[dash|DASH]] client fetches an {{mpd|MPD}} {{manifest|manifest}} over [[http1|[[http1|HTTP/1]].1]], then requests individual media segments as standard {{http-method|HTTP}} GET requests. Each segment is a separate [[http1|[[http1|HTTP/1]].1]] {{request-response|request-response}} cycle, which means multiple [[tcp|TCP]] connections are used in parallel to {{imap-fetch|fetch}} video and audio segments at the appropriate bitrate.', - leftRole: '[[dash|DASH]] defines the {{manifest|manifest}} format, segment addressing, and adaptive bitrate switching logic.', - rightRole: '[[http1|[[http1|HTTP/1]].1]] provides the {{request-response|request-response}} transport for fetching manifests and media segments.' + leftRole: + '[[dash|DASH]] defines the {{manifest|manifest}} format, segment addressing, and adaptive bitrate switching logic.', + rightRole: + '[[http1|[[http1|HTTP/1]].1]] provides the {{request-response|request-response}} transport for fetching manifests and media segments.' }, { ids: ['dash', 'http2'], @@ -1557,9 +2411,11 @@ const relationshipPairs: ProtocolPair[] = [ summary: '[[dash|DASH]] delivers adaptive video over [[http2|HTTP/2]], benefiting from multiplexed streams to {{imap-fetch|fetch}} manifests and media segments more efficiently on a single connection.', howTheyWork: - 'The [[dash|DASH]] client fetches the {{mpd|MPD}} {{manifest|manifest}} and subsequent media segments as [[http2|HTTP/2]] requests multiplexed over a single [[tcp|TCP]] connection. [[http2|HTTP/2]]\'s stream {{multiplexing|multiplexing}} eliminates the need for multiple parallel connections, and header compression reduces the overhead of repeated segment requests to the same origin.', - leftRole: '[[dash|DASH]] defines the {{manifest|manifest}} format, segment addressing, and adaptive bitrate switching logic.', - rightRole: '[[http2|HTTP/2]] provides multiplexed, header-compressed transport for efficient parallel segment delivery.' + "The [[dash|DASH]] client fetches the {{mpd|MPD}} {{manifest|manifest}} and subsequent media segments as [[http2|HTTP/2]] requests multiplexed over a single [[tcp|TCP]] connection. [[http2|HTTP/2]]'s stream {{multiplexing|multiplexing}} eliminates the need for multiple parallel connections, and header compression reduces the overhead of repeated segment requests to the same origin.", + leftRole: + '[[dash|DASH]] defines the {{manifest|manifest}} format, segment addressing, and adaptive bitrate switching logic.', + rightRole: + '[[http2|HTTP/2]] provides multiplexed, header-compressed transport for efficient parallel segment delivery.' }, { ids: ['graphql', 'http1'], @@ -1568,8 +2424,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[graphql|GraphQL]] sends queries and mutations as [[http1|[[http1|HTTP/1]].1]] POST requests to a single endpoint, using standard {{http-method|HTTP}} as its most common transport.', howTheyWork: 'The client sends a [[graphql|GraphQL]] query as a {{json|JSON}} {{payload|payload}} in an [[http1|[[http1|HTTP/1]].1]] POST request to a single endpoint (typically /graphql). The server parses the query, resolves the requested fields, and returns a {{json|JSON}} response. Each query-response cycle is an independent [[http1|[[http1|HTTP/1]].1]] request, making it compatible with existing {{http-method|HTTP}} infrastructure.', - leftRole: '[[graphql|GraphQL]] defines the query language, schema, and resolver execution model.', - rightRole: '[[http1|[[http1|HTTP/1]].1]] provides the {{request-response|request-response}} transport for sending queries and receiving results.' + leftRole: + '[[graphql|GraphQL]] defines the query language, schema, and resolver execution model.', + rightRole: + '[[http1|[[http1|HTTP/1]].1]] provides the {{request-response|request-response}} transport for sending queries and receiving results.' }, { ids: ['graphql', 'http2'], @@ -1578,8 +2436,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[graphql|GraphQL]] queries are sent over [[http2|HTTP/2]], benefiting from multiplexed streams when clients issue multiple queries or when responses are large with compressed headers.', howTheyWork: '[[graphql|GraphQL]] queries are sent as [[http2|HTTP/2]] POST requests to a single endpoint, just as with [[http1|[[http1|HTTP/1]].1]], but [[http2|HTTP/2]] multiplexes concurrent queries over a single connection. This is especially beneficial when a client fires multiple [[graphql|GraphQL]] queries in parallel, as they share one connection with compressed headers instead of requiring separate [[tcp|TCP]] connections.', - leftRole: '[[graphql|GraphQL]] defines the query language, schema, and resolver execution model.', - rightRole: '[[http2|HTTP/2]] provides multiplexed, header-compressed transport for concurrent query delivery.' + leftRole: + '[[graphql|GraphQL]] defines the query language, schema, and resolver execution model.', + rightRole: + '[[http2|HTTP/2]] provides multiplexed, header-compressed transport for concurrent query delivery.' }, { ids: ['graphql', 'websockets'], @@ -1588,8 +2448,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[graphql|GraphQL]] subscriptions use [[websockets|WebSocket]] as a persistent transport to push real-time data updates from the server to subscribed clients.', howTheyWork: 'The client establishes a [[websockets|WebSocket]] connection to the [[graphql|GraphQL]] server and sends subscription queries using a sub-protocol like graphql-ws. The server keeps the connection open and pushes data whenever the subscribed fields change. This complements the {{http-method|HTTP}}-based query/mutation model by adding server-initiated real-time updates.', - leftRole: '[[graphql|GraphQL]] defines the subscription query syntax and the data pushed when subscribed fields change.', - rightRole: '[[websockets|WebSocket]] provides the persistent, bidirectional channel needed for real-time subscription delivery.' + leftRole: + '[[graphql|GraphQL]] defines the subscription query syntax and the data pushed when subscribed fields change.', + rightRole: + '[[websockets|WebSocket]] provides the persistent, bidirectional channel needed for real-time subscription delivery.' }, { ids: ['hls', 'http1'], @@ -1598,8 +2460,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[hls|HLS]] delivers adaptive video by serving M3U8 playlists and media segments as standard [[http1|[[http1|HTTP/1]].1]] file downloads, leveraging existing web infrastructure and CDNs.', howTheyWork: 'The [[hls|HLS]] client fetches an M3U8 playlist over [[http1|[[http1|HTTP/1]].1]] to discover available bitrates and segment URLs. It then requests individual media segments as standard {{http-method|HTTP}} GET requests. Each segment is a self-contained file served like any static asset, making [[hls|HLS]] fully compatible with {{http-method|HTTP}} caches, CDNs, and standard web servers.', - leftRole: '[[hls|HLS]] defines the playlist format, segment structure, and adaptive bitrate selection algorithm.', - rightRole: '[[http1|[[http1|HTTP/1]].1]] provides the file-serving transport for delivering playlist and segment files.' + leftRole: + '[[hls|HLS]] defines the playlist format, segment structure, and adaptive bitrate selection algorithm.', + rightRole: + '[[http1|[[http1|HTTP/1]].1]] provides the file-serving transport for delivering playlist and segment files.' }, { ids: ['hls', 'http2'], @@ -1608,8 +2472,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[hls|HLS]] delivers adaptive video over [[http2|HTTP/2]], where multiplexed streams allow playlist refreshes and segment fetches to share a single connection efficiently.', howTheyWork: 'The [[hls|HLS]] client fetches M3U8 playlists and media segments over [[http2|HTTP/2]], {{multiplexing|multiplexing}} requests on a single connection instead of opening multiple parallel [[tcp|TCP]] connections. For live streams, this is especially beneficial since frequent playlist refreshes and segment requests can interleave without {{head-of-line-blocking|head-of-line blocking}} at the {{http-method|HTTP}} layer.', - leftRole: '[[hls|HLS]] defines the playlist format, segment structure, and adaptive bitrate selection algorithm.', - rightRole: '[[http2|HTTP/2]] provides multiplexed transport for efficient parallel delivery of playlists and segments.' + leftRole: + '[[hls|HLS]] defines the playlist format, segment structure, and adaptive bitrate selection algorithm.', + rightRole: + '[[http2|HTTP/2]] provides multiplexed transport for efficient parallel delivery of playlists and segments.' }, { ids: ['http1', 'rest'], @@ -1618,8 +2484,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[rest|REST]] APIs are most commonly served over [[http1|[[http1|HTTP/1]].1]], using its methods (GET, POST, PUT, DELETE), status codes, and headers to implement resource-oriented APIs.', howTheyWork: '[[rest|REST]] maps {{crud|CRUD}} operations to [[http1|[[http1|HTTP/1]].1]] methods: GET for reading, POST for creating, PUT/PATCH for updating, and DELETE for removing resources. [[http1|[[http1|HTTP/1]].1]] status codes communicate outcomes, headers handle {{content-negotiation|content negotiation}} and caching, and URLs identify resources. [[http1|[[http1|HTTP/1]].1]] provides all the semantics [[rest|REST]] relies on as an architectural style.', - leftRole: '[[http1|[[http1|HTTP/1]].1]] provides the methods, status codes, headers, and {{url|URL}} structure that [[rest|REST]] builds upon.', - rightRole: '[[rest|REST]] defines the architectural conventions for mapping resource operations onto {{http-method|HTTP}} semantics.' + leftRole: + '[[http1|[[http1|HTTP/1]].1]] provides the methods, status codes, headers, and {{url|URL}} structure that [[rest|REST]] builds upon.', + rightRole: + '[[rest|REST]] defines the architectural conventions for mapping resource operations onto {{http-method|HTTP}} semantics.' }, { ids: ['http1', 'websockets'], @@ -1628,8 +2496,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[websockets|WebSocket]] connections begin with an [[http1|[[http1|HTTP/1]].1]] Upgrade {{handshake|handshake}}, then switch to a persistent, bidirectional {{binary-framing|binary framing}} protocol.', howTheyWork: 'The client sends an [[http1|[[http1|HTTP/1]].1]] GET request with Upgrade: websocket and Connection: Upgrade headers, plus a Sec-[[websockets|WebSocket]]-Key. If the server accepts, it responds with 101 Switching Protocols and the connection transitions from {{http-method|HTTP}} to [[websockets|WebSocket]] framing. After the upgrade, the [[tcp|TCP]] connection carries [[websockets|WebSocket]] frames instead of {{http-method|HTTP}} messages.', - leftRole: '[[http1|[[http1|HTTP/1]].1]] provides the initial {{handshake|handshake}} and Upgrade mechanism to establish the connection.', - rightRole: '[[websockets|WebSocket]] provides the persistent, {{full-duplex|full-duplex}} message framing protocol after the upgrade completes.' + leftRole: + '[[http1|[[http1|HTTP/1]].1]] provides the initial {{handshake|handshake}} and Upgrade mechanism to establish the connection.', + rightRole: + '[[websockets|WebSocket]] provides the persistent, {{full-duplex|full-duplex}} message framing protocol after the upgrade completes.' }, { ids: ['http2', 'sse'], @@ -1638,8 +2508,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[sse|SSE]] streams server-pushed events over [[http2|HTTP/2]], where {{multiplexing|multiplexing}} allows multiple [[sse|SSE]] streams to share a single connection without blocking other requests.', howTheyWork: 'The client opens an [[sse|SSE]] connection by sending a GET request with Accept: text/event-stream. Over [[http2|HTTP/2]], this [[sse|SSE]] stream becomes one of many multiplexed streams on a single connection, so other {{api|API}} requests proceed in parallel without being blocked. This eliminates the browser connection limit problem that restricts [[sse|SSE]] to six concurrent streams per origin on [[http1|[[http1|HTTP/1]].1]].', - leftRole: '[[http2|HTTP/2]] provides multiplexed streams that let [[sse|SSE]] connections coexist with other requests on one connection.', - rightRole: '[[sse|SSE]] provides the text/event-stream format and {{eventsource|EventSource API}} for server-to-client push.' + leftRole: + '[[http2|HTTP/2]] provides multiplexed streams that let [[sse|SSE]] connections coexist with other requests on one connection.', + rightRole: + '[[sse|SSE]] provides the text/event-stream format and {{eventsource|EventSource API}} for server-to-client push.' }, { ids: ['http3', 'rest'], @@ -1648,8 +2520,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[rest|REST]] APIs can be served over [[http3|HTTP/3]], gaining faster connection setup, independent stream {{multiplexing|multiplexing}}, and built-in {{encryption|encryption}} from the [[quic|QUIC]] transport.', howTheyWork: '[[rest|REST]] semantics (methods, status codes, headers, URLs) work identically over [[http3|HTTP/3]] as they do over [[http1|[[http1|HTTP/1]].1]] or [[http2|HTTP/2]] β€” only the transport changes. [[http3|HTTP/3]] runs over [[quic|QUIC]], providing {{zero-rtt|0-RTT}} connection establishment, stream-level independence (no {{head-of-line-blocking|head-of-line blocking}}), and mandatory [[tls|TLS]] 1.3. [[rest|REST]] APIs benefit automatically without any changes to {{api|API}} design.', - leftRole: '[[http3|HTTP/3]] provides the [[quic|QUIC]]-based transport with {{zero-rtt|0-RTT}} setup and independent stream {{multiplexing|multiplexing}}.', - rightRole: '[[rest|REST]] defines the resource-oriented {{api|API}} architecture that rides on [[http3|HTTP/3]] semantics.' + leftRole: + '[[http3|HTTP/3]] provides the [[quic|QUIC]]-based transport with {{zero-rtt|0-RTT}} setup and independent stream {{multiplexing|multiplexing}}.', + rightRole: + '[[rest|REST]] defines the resource-oriented {{api|API}} architecture that rides on [[http3|HTTP/3]] semantics.' }, // ── WebSocket as transport ─────────────────────────────────── @@ -1661,8 +2535,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[amqp|AMQP]] can be tunneled over [[websockets|WebSocket]] to allow browser-based clients to {{mqtt-connect|connect}} to message brokers without direct [[tcp|TCP]] access.', howTheyWork: 'The browser establishes a [[websockets|WebSocket]] connection to the {{broker|message broker}} (or a gateway), then speaks the [[amqp|AMQP]] protocol over that [[websockets|WebSocket]] channel. The [[websockets|WebSocket]] connection wraps [[amqp|AMQP]] frames so they can traverse {{http-method|HTTP}} proxies and firewalls that would otherwise block raw [[tcp|TCP]] [[amqp|AMQP]] connections on port 5672.', - leftRole: '[[amqp|AMQP]] provides the messaging semantics β€” exchanges, queues, bindings, and delivery guarantees.', - rightRole: '[[websockets|WebSocket]] provides the browser-compatible transport tunnel that carries [[amqp|AMQP]] frames over {{http-method|HTTP}}.' + leftRole: + '[[amqp|AMQP]] provides the messaging semantics β€” exchanges, queues, bindings, and delivery guarantees.', + rightRole: + '[[websockets|WebSocket]] provides the browser-compatible transport tunnel that carries [[amqp|AMQP]] frames over {{http-method|HTTP}}.' }, { ids: ['mqtt', 'websockets'], @@ -1671,18 +2547,22 @@ const relationshipPairs: ProtocolPair[] = [ '[[mqtt|MQTT]] over [[websockets|WebSocket]] enables browser-based IoT dashboards and web apps to {{mqtt-subscribe|subscribe}} to [[mqtt|MQTT]] topics directly from the browser.', howTheyWork: 'The browser opens a [[websockets|WebSocket]] connection to the [[mqtt|MQTT]] broker (typically on port 8083/8084). [[mqtt|MQTT]] packets are sent as [[websockets|WebSocket]] binary frames, allowing the browser to {{mqtt-publish|publish}}, {{mqtt-subscribe|subscribe}}, and receive messages using standard [[mqtt|MQTT]] semantics. This avoids the need for a custom [[rest|REST]] bridge between the browser and the [[mqtt|MQTT]] broker.', - leftRole: '[[mqtt|MQTT]] provides the lightweight pub/sub messaging protocol with {{topic|topic}} hierarchy and QoS levels.', - rightRole: '[[websockets|WebSocket]] provides the browser-accessible transport that carries [[mqtt|MQTT]] packets over {{http-method|HTTP}}.' + leftRole: + '[[mqtt|MQTT]] provides the lightweight pub/sub messaging protocol with {{topic|topic}} hierarchy and QoS levels.', + rightRole: + '[[websockets|WebSocket]] provides the browser-accessible transport that carries [[mqtt|MQTT]] packets over {{http-method|HTTP}}.' }, { ids: ['stomp', 'websockets'], type: 'relationship', summary: - '[[stomp|STOMP]] over [[websockets|WebSocket]] allows browser clients to {{mqtt-connect|connect}} to message brokers using [[stomp|STOMP]]\'s simple text-based messaging commands.', + "[[stomp|STOMP]] over [[websockets|WebSocket]] allows browser clients to {{mqtt-connect|connect}} to message brokers using [[stomp|STOMP]]'s simple text-based messaging commands.", howTheyWork: - 'The browser establishes a [[websockets|WebSocket]] connection to the {{broker|message broker}} (e.g., RabbitMQ with [[stomp|STOMP]] plugin, or Spring\'s [[stomp|STOMP]] broker). [[stomp|STOMP]] text frames ({{mqtt-connect|CONNECT}}, SEND, {{mqtt-subscribe|SUBSCRIBE}}, MESSAGE) are sent as [[websockets|WebSocket]] text messages. [[stomp|STOMP]]\'s {{http-method|HTTP}}-like text format makes it especially natural to carry over [[websockets|WebSocket]], requiring minimal client-side code.', - leftRole: '[[stomp|STOMP]] provides the text-based messaging commands for sending, subscribing, and acknowledging messages.', - rightRole: '[[websockets|WebSocket]] provides the browser-compatible bidirectional channel that carries [[stomp|STOMP]] frames.' + "The browser establishes a [[websockets|WebSocket]] connection to the {{broker|message broker}} (e.g., RabbitMQ with [[stomp|STOMP]] plugin, or Spring's [[stomp|STOMP]] broker). [[stomp|STOMP]] text frames ({{mqtt-connect|CONNECT}}, SEND, {{mqtt-subscribe|SUBSCRIBE}}, MESSAGE) are sent as [[websockets|WebSocket]] text messages. [[stomp|STOMP]]'s {{http-method|HTTP}}-like text format makes it especially natural to carry over [[websockets|WebSocket]], requiring minimal client-side code.", + leftRole: + '[[stomp|STOMP]] provides the text-based messaging commands for sending, subscribing, and acknowledging messages.', + rightRole: + '[[websockets|WebSocket]] provides the browser-compatible bidirectional channel that carries [[stomp|STOMP]] frames.' }, { ids: ['websockets', 'xmpp'], @@ -1691,8 +2571,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[xmpp|XMPP]] over [[websockets|WebSocket]] enables browser-based chat clients to participate in the [[xmpp|XMPP]] network without long-polling hacks like BOSH.', howTheyWork: 'The browser opens a [[websockets|WebSocket]] connection to the [[xmpp|XMPP]] server using the [[xmpp|XMPP]] sub-protocol ([[rfc:7395|RFC 7395]]). [[xmpp|XMPP]] stanzas (message, presence, iq) are sent as [[websockets|WebSocket]] text frames, providing the same real-time {{xml|XML}} stream as a native [[tcp|TCP]] [[xmpp|XMPP]] connection. This replaces the older BOSH (Bidirectional-streams Over Synchronous {{http-method|HTTP}}) approach with a cleaner, lower-{{latency|latency}} transport.', - leftRole: '[[websockets|WebSocket]] provides the persistent, low-{{latency|latency}} bidirectional transport between browser and [[xmpp|XMPP]] server.', - rightRole: '[[xmpp|XMPP]] provides the messaging semantics β€” presence, roster, stanzas, and {{federation|federation}}.' + leftRole: + '[[websockets|WebSocket]] provides the persistent, low-{{latency|latency}} bidirectional transport between browser and [[xmpp|XMPP]] server.', + rightRole: + '[[xmpp|XMPP]] provides the messaging semantics β€” presence, roster, stanzas, and {{federation|federation}}.' }, // ── Real-time A/V ──────────────────────────────────────────── @@ -1704,8 +2586,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[sdp|SDP]] describes the parameters of an [[rtp|RTP]] session β€” codecs, {{payload|payload}} types, ports, and addresses β€” so both endpoints agree on how to send and receive media.', howTheyWork: 'Before [[rtp|RTP]] media can flow, endpoints {{exchange|exchange}} [[sdp|SDP]] descriptions (via [[sip|SIP]], [[webrtc|WebRTC]] {{signaling|signaling}}, or other means) that specify the [[ip|IP]] addresses, port numbers, codecs, and {{payload|payload}} type mappings for each media stream. [[rtp|RTP]] then uses these negotiated parameters to deliver audio and video packets between the endpoints.', - leftRole: '[[rtp|RTP]] carries the actual audio and video media packets using parameters negotiated by [[sdp|SDP]].', - rightRole: '[[sdp|SDP]] describes the session parameters (codecs, ports, addresses) that configure the [[rtp|RTP]] streams.' + leftRole: + '[[rtp|RTP]] carries the actual audio and video media packets using parameters negotiated by [[sdp|SDP]].', + rightRole: + '[[sdp|SDP]] describes the session parameters (codecs, ports, addresses) that configure the [[rtp|RTP]] streams.' }, { ids: ['rtp', 'sip'], @@ -1714,8 +2598,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[sip|SIP]] establishes and manages call sessions (ringing, answering, hanging up), while [[rtp|RTP]] carries the actual audio and video media during the call.', howTheyWork: '[[sip|SIP]] handles call {{signaling|signaling}} β€” {{sip-invite|INVITE}} to initiate, 200 OK to accept, BYE to terminate β€” and carries [[sdp|SDP]] in its message bodies to negotiate media parameters. Once the [[sip|SIP]] {{signaling|signaling}} establishes a session, [[rtp|RTP]] streams flow directly between the media endpoints on the ports and codecs specified by [[sdp|SDP]]. [[sip|SIP]] manages the call lifecycle; [[rtp|RTP]] handles the media.', - leftRole: '[[rtp|RTP]] carries the real-time audio and video streams between endpoints during the call.', - rightRole: '[[sip|SIP]] provides the {{signaling|signaling}} to establish, modify, and tear down the call session.' + leftRole: + '[[rtp|RTP]] carries the real-time audio and video streams between endpoints during the call.', + rightRole: + '[[sip|SIP]] provides the {{signaling|signaling}} to establish, modify, and tear down the call session.' }, { ids: ['rtp', 'webrtc'], @@ -1724,8 +2610,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[webrtc|WebRTC]] uses {{srtp|SRTP}} (Secure [[rtp|RTP]]) as its media transport, encrypting all audio and video packets with {{dtls|DTLS}}-derived keys for secure {{peer-to-peer|peer-to-peer}} communication.', howTheyWork: '[[webrtc|WebRTC]] establishes a peer connection using {{ice|ICE}} for {{nat|NAT}} traversal and {{dtls|DTLS}} for key {{exchange|exchange}}. Once the secure channel is established, audio and video are transmitted as {{srtp|SRTP}} packets β€” [[rtp|RTP]] with {{aes|AES}} {{encryption|encryption}}. [[webrtc|WebRTC]] mandates {{srtp|SRTP}} (not plain [[rtp|RTP]]) to ensure all media is encrypted end-to-end by default.', - leftRole: '[[rtp|RTP]] (as {{srtp|SRTP}}) carries the encrypted audio and video packets between [[webrtc|WebRTC]] peers.', - rightRole: '[[webrtc|WebRTC]] provides the peer connection framework, {{ice|ICE}} negotiation, and {{dtls|DTLS}} key {{exchange|exchange}} around {{srtp|SRTP}}.' + leftRole: + '[[rtp|RTP]] (as {{srtp|SRTP}}) carries the encrypted audio and video packets between [[webrtc|WebRTC]] peers.', + rightRole: + '[[webrtc|WebRTC]] provides the peer connection framework, {{ice|ICE}} negotiation, and {{dtls|DTLS}} key {{exchange|exchange}} around {{srtp|SRTP}}.' }, { ids: ['sctp', 'webrtc'], @@ -1733,9 +2621,11 @@ const relationshipPairs: ProtocolPair[] = [ summary: '[[webrtc|WebRTC]] data channels use [[sctp|SCTP]] tunneled over {{dtls|DTLS}} to provide reliable, ordered, and configurable message delivery between peers.', howTheyWork: - '[[webrtc|WebRTC]] establishes a {{dtls|DTLS}} connection over the {{ice|ICE}}-negotiated path, then runs [[sctp|SCTP]] on top of that {{dtls|DTLS}} tunnel. Each data channel maps to an [[sctp|SCTP]] stream, and [[sctp|SCTP]]\'s multi-stream support allows independent channels without {{head-of-line-blocking|head-of-line blocking}}. Channels can be configured as reliable/ordered or unreliable/unordered per-channel.', - leftRole: '[[sctp|SCTP]] provides the multi-stream, message-oriented transport with configurable reliability for each data channel.', - rightRole: '[[webrtc|WebRTC]] provides the peer connection, {{dtls|DTLS}} {{encryption|encryption}}, and {{ice|ICE}} traversal that [[sctp|SCTP]] runs over.' + "[[webrtc|WebRTC]] establishes a {{dtls|DTLS}} connection over the {{ice|ICE}}-negotiated path, then runs [[sctp|SCTP]] on top of that {{dtls|DTLS}} tunnel. Each data channel maps to an [[sctp|SCTP]] stream, and [[sctp|SCTP]]'s multi-stream support allows independent channels without {{head-of-line-blocking|head-of-line blocking}}. Channels can be configured as reliable/ordered or unreliable/unordered per-channel.", + leftRole: + '[[sctp|SCTP]] provides the multi-stream, message-oriented transport with configurable reliability for each data channel.', + rightRole: + '[[webrtc|WebRTC]] provides the peer connection, {{dtls|DTLS}} {{encryption|encryption}}, and {{ice|ICE}} traversal that [[sctp|SCTP]] runs over.' }, { ids: ['sdp', 'sip'], @@ -1744,8 +2634,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[sip|SIP]] carries [[sdp|SDP]] payloads in its {{sip-invite|INVITE}} and response messages to negotiate the media parameters (codecs, ports, addresses) for a call session.', howTheyWork: 'When a [[sip|SIP]] client sends an {{sip-invite|INVITE}}, it includes an [[sdp|SDP]] offer in the message body describing its supported codecs, [[ip|IP]] address, and port. The callee responds with a [[sip|SIP]] 200 OK containing an [[sdp|SDP]] answer with its own media capabilities. This offer/answer {{exchange|exchange}} within [[sip|SIP]] messages establishes the agreed-upon parameters for the subsequent [[rtp|RTP]] media streams.', - leftRole: '[[sdp|SDP]] provides the session description format that specifies codecs, ports, and media parameters.', - rightRole: '[[sip|SIP]] provides the {{signaling|signaling}} protocol that carries [[sdp|SDP]] offers and answers in its messages.' + leftRole: + '[[sdp|SDP]] provides the session description format that specifies codecs, ports, and media parameters.', + rightRole: + '[[sip|SIP]] provides the {{signaling|signaling}} protocol that carries [[sdp|SDP]] offers and answers in its messages.' }, { ids: ['sdp', 'webrtc'], @@ -1754,8 +2646,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[webrtc|WebRTC]] uses [[sdp|SDP]] in its offer/answer model to negotiate media capabilities, {{ice|ICE}} candidates, and {{dtls|DTLS}} fingerprints between peers.', howTheyWork: 'When a [[webrtc|WebRTC]] peer connection is created, the browser generates an [[sdp|SDP]] offer describing supported codecs, {{ice|ICE}} candidates, {{dtls|DTLS}} fingerprints, and media directions. This [[sdp|SDP]] is sent to the remote peer via an application-defined {{signaling|signaling}} channel. The remote peer generates an [[sdp|SDP]] answer, and both sides apply the negotiated parameters to configure their media and data channels.', - leftRole: '[[sdp|SDP]] describes the session parameters β€” codecs, {{ice|ICE}} candidates, and {{dtls|DTLS}} fingerprints β€” for [[webrtc|WebRTC]] negotiation.', - rightRole: '[[webrtc|WebRTC]] provides the peer connection {{api|API}} that generates, exchanges, and applies [[sdp|SDP]] descriptions.' + leftRole: + '[[sdp|SDP]] describes the session parameters β€” codecs, {{ice|ICE}} candidates, and {{dtls|DTLS}} fingerprints β€” for [[webrtc|WebRTC]] negotiation.', + rightRole: + '[[webrtc|WebRTC]] provides the peer connection {{api|API}} that generates, exchanges, and applies [[sdp|SDP]] descriptions.' }, // ── Utility / Other ────────────────────────────────────────── @@ -1767,8 +2661,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[dhcp|DHCP]] provides [[dns|DNS]] server addresses to clients as part of network configuration, telling devices where to send their [[dns|DNS]] queries.', howTheyWork: 'When a device joins a network, [[dhcp|DHCP]] assigns it an [[ip|IP]] address along with other configuration including the [[dns|DNS]] server addresses (option 6 in DHCPv4). The client then uses these [[dns|DNS]] server addresses for all subsequent name resolution. Without [[dhcp|DHCP]] providing this information, clients would need manually configured [[dns|DNS]] servers.', - leftRole: '[[dhcp|DHCP]] provides network configuration including the [[dns|DNS]] server addresses clients should use.', - rightRole: '[[dns|DNS]] provides name resolution services at the server addresses distributed by [[dhcp|DHCP]].' + leftRole: + '[[dhcp|DHCP]] provides network configuration including the [[dns|DNS]] server addresses clients should use.', + rightRole: + '[[dns|DNS]] provides name resolution services at the server addresses distributed by [[dhcp|DHCP]].' }, { ids: ['dns', 'smtp'], @@ -1777,8 +2673,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[smtp|SMTP]] relies on [[dns|DNS]] {{mx-record|MX}} (Mail Exchanger) records to determine which mail server should receive email for a given domain.', howTheyWork: 'When an [[smtp|SMTP]] server needs to deliver mail to user@example.com, it queries [[dns|DNS]] for the {{mx-record|MX}} records of example.com. [[dns|DNS]] returns one or more mail server hostnames with priority values. The [[smtp|SMTP]] server then resolves those hostnames to [[ip|IP]] addresses (A/{{aaaa-record|AAAA}} records) and connects to the highest-priority server to deliver the message.', - leftRole: '[[dns|DNS]] provides the {{mx-record|MX record}} lookups that map email domains to their mail server hostnames.', - rightRole: '[[smtp|SMTP]] uses {{mx-record|MX}} records from [[dns|DNS]] to route and deliver email to the correct destination mail server.' + leftRole: + '[[dns|DNS]] provides the {{mx-record|MX record}} lookups that map email domains to their mail server hostnames.', + rightRole: + '[[smtp|SMTP]] uses {{mx-record|MX}} records from [[dns|DNS]] to route and deliver email to the correct destination mail server.' }, { ids: ['ftp', 'ssh'], @@ -1787,18 +2685,22 @@ const relationshipPairs: ProtocolPair[] = [ '{{sftp|SFTP}} ([[ssh|SSH]] File Transfer Protocol) runs entirely within an [[ssh|SSH]] channel, providing encrypted file transfer with strong authentication as a secure replacement for [[ftp|FTP]].', howTheyWork: '{{sftp|SFTP}} is a subsystem of [[ssh|SSH]], not a variant of [[ftp|FTP]] β€” it uses a completely different binary protocol. The client establishes an [[ssh|SSH]] connection with key-based or password authentication, then opens an {{sftp|SFTP}} subsystem channel. All file operations (list, upload, download, rename, delete) are sent as binary {{sftp|SFTP}} packets within the encrypted [[ssh|SSH]] tunnel on a single port (22).', - leftRole: '[[ftp|FTP]]-style file operations (list, get, put, delete) are provided by the {{sftp|SFTP}} subsystem within [[ssh|SSH]].', - rightRole: '[[ssh|SSH]] provides the encrypted tunnel, authentication, and channel {{multiplexing|multiplexing}} that {{sftp|SFTP}} runs inside.' + leftRole: + '[[ftp|FTP]]-style file operations (list, get, put, delete) are provided by the {{sftp|SFTP}} subsystem within [[ssh|SSH]].', + rightRole: + '[[ssh|SSH]] provides the encrypted tunnel, authentication, and channel {{multiplexing|multiplexing}} that {{sftp|SFTP}} runs inside.' }, { ids: ['http3', 'quic'], type: 'relationship', summary: - '[[http3|HTTP/3]] is the first major protocol built specifically for [[quic|QUIC]], mapping {{http-method|HTTP}} semantics onto [[quic|QUIC]]\'s multiplexed, encrypted streams for head-of-line-blocking-free web delivery.', + "[[http3|HTTP/3]] is the first major protocol built specifically for [[quic|QUIC]], mapping {{http-method|HTTP}} semantics onto [[quic|QUIC]]'s multiplexed, encrypted streams for head-of-line-blocking-free web delivery.", howTheyWork: '[[http3|HTTP/3]] maps each {{request-response|request-response}} {{exchange|exchange}} to an independent [[quic|QUIC]] stream. [[quic|QUIC]] provides reliable, ordered delivery per-stream with [[tls|TLS]] 1.3 {{encryption|encryption}}, {{connection-migration|connection migration}}, and {{zero-rtt|0-RTT}} resumption. Unlike [[http2|HTTP/2]] over [[tcp|TCP]], losing a packet on one stream does not block others β€” each [[quic|QUIC]] stream is independently reliable.', - leftRole: '[[http3|HTTP/3]] provides the {{http-method|HTTP}} semantics (methods, headers, status codes) and {{qpack|QPACK}} header compression.', - rightRole: '[[quic|QUIC]] provides the multiplexed, encrypted transport with per-stream reliability and fast connection setup.' + leftRole: + '[[http3|HTTP/3]] provides the {{http-method|HTTP}} semantics (methods, headers, status codes) and {{qpack|QPACK}} header compression.', + rightRole: + '[[quic|QUIC]] provides the multiplexed, encrypted transport with per-stream reliability and fast connection setup.' }, { ids: ['quic', 'tcp'], @@ -1806,9 +2708,11 @@ const relationshipPairs: ProtocolPair[] = [ summary: '[[quic|QUIC]] is designed as a modern replacement for the [[tcp|TCP]]+[[tls|TLS]] stack, providing reliable, multiplexed, encrypted transport over [[udp|UDP]] with faster connection setup.', howTheyWork: - '[[quic|QUIC]] implements the reliability, ordering, and {{congestion-control|congestion control}} features of [[tcp|TCP]] but runs over [[udp|UDP]] datagrams to avoid kernel-level [[tcp|TCP]] limitations and middlebox interference. It integrates [[tls|TLS]] 1.3 directly into its {{handshake|handshake}} (achieving {{one-rtt|1-RTT}} or {{zero-rtt|0-RTT}} setup) and provides independent stream {{multiplexing|multiplexing}} that eliminates [[tcp|TCP]]\'s {{head-of-line-blocking|head-of-line blocking}} problem.', - leftRole: '[[quic|QUIC]] provides the modern multiplexed, encrypted transport that aims to supersede [[tcp|TCP]]+[[tls|TLS]].', - rightRole: '[[tcp|TCP]] provides the traditional reliable transport that [[quic|QUIC]] was designed to replace and improve upon.' + "[[quic|QUIC]] implements the reliability, ordering, and {{congestion-control|congestion control}} features of [[tcp|TCP]] but runs over [[udp|UDP]] datagrams to avoid kernel-level [[tcp|TCP]] limitations and middlebox interference. It integrates [[tls|TLS]] 1.3 directly into its {{handshake|handshake}} (achieving {{one-rtt|1-RTT}} or {{zero-rtt|0-RTT}} setup) and provides independent stream {{multiplexing|multiplexing}} that eliminates [[tcp|TCP]]'s {{head-of-line-blocking|head-of-line blocking}} problem.", + leftRole: + '[[quic|QUIC]] provides the modern multiplexed, encrypted transport that aims to supersede [[tcp|TCP]]+[[tls|TLS]].', + rightRole: + '[[tcp|TCP]] provides the traditional reliable transport that [[quic|QUIC]] was designed to replace and improve upon.' }, { ids: ['rest', 'sse'], @@ -1816,9 +2720,11 @@ const relationshipPairs: ProtocolPair[] = [ summary: '[[sse|SSE]] is commonly used within [[rest|REST]] APIs to add a server-push capability, streaming real-time updates to clients over a standard {{http-method|HTTP}} connection.', howTheyWork: - 'A [[rest|REST]] {{api|API}} exposes an [[sse|SSE]] endpoint (e.g., GET /events) that returns a text/event-stream response. The client connects using the {{eventsource|EventSource API}} and receives server-pushed events as they occur, while continuing to use regular [[rest|REST]] endpoints for queries and mutations. [[sse|SSE]] complements [[rest|REST]]\'s {{request-response|request-response}} model by adding unidirectional real-time updates.', - leftRole: '[[rest|REST]] provides the {{request-response|request-response}} {{api|API}} structure that [[sse|SSE]] endpoints are integrated into.', - rightRole: '[[sse|SSE]] provides the server-push streaming mechanism that extends [[rest|REST]] with real-time event delivery.' + "A [[rest|REST]] {{api|API}} exposes an [[sse|SSE]] endpoint (e.g., GET /events) that returns a text/event-stream response. The client connects using the {{eventsource|EventSource API}} and receives server-pushed events as they occur, while continuing to use regular [[rest|REST]] endpoints for queries and mutations. [[sse|SSE]] complements [[rest|REST]]'s {{request-response|request-response}} model by adding unidirectional real-time updates.", + leftRole: + '[[rest|REST]] provides the {{request-response|request-response}} {{api|API}} structure that [[sse|SSE]] endpoints are integrated into.', + rightRole: + '[[sse|SSE]] provides the server-push streaming mechanism that extends [[rest|REST]] with real-time event delivery.' }, // ── BGP relationships ─────────────────────────────────────── @@ -1827,9 +2733,9 @@ const relationshipPairs: ProtocolPair[] = [ ids: ['bgp', 'tcp'], type: 'relationship', summary: - '[[bgp|BGP]] runs over [[tcp|TCP]] port 179, relying on [[tcp|TCP]]\'s reliable delivery to guarantee that routing updates are never lost, duplicated, or reordered between autonomous systems.', + "[[bgp|BGP]] runs over [[tcp|TCP]] port 179, relying on [[tcp|TCP]]'s reliable delivery to guarantee that routing updates are never lost, duplicated, or reordered between autonomous systems.", howTheyWork: - '[[bgp|BGP]] peers establish a [[tcp|TCP]] connection on port 179 before exchanging OPEN messages. All subsequent {{bgp-update|UPDATE}}, {{bgp-keepalive|KEEPALIVE}}, and {{notification|NOTIFICATION}} messages flow over this persistent [[tcp|TCP]] connection. [[tcp|TCP]]\'s reliability is critical because a lost route announcement could create routing loops or black holes in the internet.', + "[[bgp|BGP]] peers establish a [[tcp|TCP]] connection on port 179 before exchanging OPEN messages. All subsequent {{bgp-update|UPDATE}}, {{bgp-keepalive|KEEPALIVE}}, and {{notification|NOTIFICATION}} messages flow over this persistent [[tcp|TCP]] connection. [[tcp|TCP]]'s reliability is critical because a lost route announcement could create routing loops or black holes in the internet.", leftRole: '[[bgp|BGP]] provides the routing logic β€” path selection, {{autonomous-system|AS}} path attributes, and network reachability advertisements between autonomous systems.', rightRole: @@ -1839,7 +2745,7 @@ const relationshipPairs: ProtocolPair[] = [ ids: ['bgp', 'dns'], type: 'relationship', summary: - '[[bgp|BGP]] determines how [[ip|IP]] packets are routed between networks, while [[dns|DNS]] translates domain names to the [[ip|IP]] addresses that [[bgp|BGP]] routes. Together they form the internet\'s addressing and reachability system.', + "[[bgp|BGP]] determines how [[ip|IP]] packets are routed between networks, while [[dns|DNS]] translates domain names to the [[ip|IP]] addresses that [[bgp|BGP]] routes. Together they form the internet's addressing and reachability system.", howTheyWork: '[[dns|DNS]] resolves domain names to [[ip|IP]] addresses, and [[bgp|BGP]] determines how to reach those [[ip|IP]] addresses across {{autonomous-system|autonomous system}} boundaries. When a [[dns|DNS]] query returns an [[ip|IP]], the packets follow [[bgp|BGP]]-established routes to reach it. [[dns|DNS]] {{anycast|anycast}} relies on [[bgp|BGP]] to advertise the same [[ip|IP]] prefix from multiple geographic locations.', leftRole: @@ -1868,7 +2774,7 @@ const relationshipPairs: ProtocolPair[] = [ summary: '[[icmp|ICMP]] reports network-level errors for [[tcp|TCP]] connections β€” when a [[tcp|TCP]] segment cannot be delivered, an [[icmp|ICMP]] Destination Unreachable message tells the sender why.', howTheyWork: - 'When a [[tcp|TCP]] {{syn-cookies|SYN}} reaches a host with no listening service, the host sends back [[icmp|ICMP]] Port Unreachable (Type 3, Code 3). When a router can\'t forward a [[tcp|TCP]] packet, it sends [[icmp|ICMP]] Network Unreachable. [[tcp|TCP]] {{path-mtu-discovery|Path MTU Discovery}} relies on [[icmp|ICMP]] Packet Too Big messages to determine the {{mss|maximum segment size}} without {{fragmentation|fragmentation}}.', + "When a [[tcp|TCP]] {{syn-cookies|SYN}} reaches a host with no listening service, the host sends back [[icmp|ICMP]] Port Unreachable (Type 3, Code 3). When a router can't forward a [[tcp|TCP]] packet, it sends [[icmp|ICMP]] Network Unreachable. [[tcp|TCP]] {{path-mtu-discovery|Path MTU Discovery}} relies on [[icmp|ICMP]] Packet Too Big messages to determine the {{mss|maximum segment size}} without {{fragmentation|fragmentation}}.", leftRole: '[[icmp|ICMP]] provides error reporting and diagnostics β€” notifying [[tcp|TCP]] of unreachable destinations, {{ttl|TTL}} expiry, and {{mtu|MTU}} constraints.', rightRole: @@ -1883,11 +2789,11 @@ const relationshipPairs: ProtocolPair[] = [ summary: '[[imap|IMAP]] uses [[tcp|TCP]] for reliable delivery of email commands, message data, and mailbox state synchronization between clients and servers.', howTheyWork: - 'An [[imap|IMAP]] client opens a [[tcp|TCP]] connection to the mail server on port 993 (with [[tls|TLS]]) or 143 (plaintext). The tagged command-response protocol requires [[tcp|TCP]]\'s reliable, ordered delivery to ensure command tags match responses correctly. [[imap|IMAP]]\'s {{imap-idle|IDLE}} mode keeps the [[tcp|TCP]] connection open for real-time server-push notifications.', + "An [[imap|IMAP]] client opens a [[tcp|TCP]] connection to the mail server on port 993 (with [[tls|TLS]]) or 143 (plaintext). The tagged command-response protocol requires [[tcp|TCP]]'s reliable, ordered delivery to ensure command tags match responses correctly. [[imap|IMAP]]'s {{imap-idle|IDLE}} mode keeps the [[tcp|TCP]] connection open for real-time server-push notifications.", leftRole: '[[imap|IMAP]] provides the email retrieval protocol β€” mailbox selection, message fetching, searching, and flag management.', rightRole: - '[[tcp|TCP]] provides the reliable, persistent connection that [[imap|IMAP]]\'s {{stateful|stateful}}, tagged command-response dialogue requires.' + "[[tcp|TCP]] provides the reliable, persistent connection that [[imap|IMAP]]'s {{stateful|stateful}}, tagged command-response dialogue requires." }, { ids: ['imap', 'tls'], @@ -1910,7 +2816,7 @@ const relationshipPairs: ProtocolPair[] = [ summary: '[[arp|ARP]] resolves [[ip|IP]] addresses to {{mac-address|MAC}} addresses so that [[ethernet|Ethernet]] frames can be addressed correctly on the local network.', howTheyWork: - 'When a host needs to send an [[ip|IP]] packet to a local destination, it first checks its [[arp|ARP]] cache for the destination\'s {{mac-address|MAC address}}. On a cache miss, it broadcasts an [[arp|ARP]] Request (EtherType 0x0806) to all devices on the [[ethernet|Ethernet]] segment. The target host replies with its {{mac-address|MAC address}}, which is cached for future [[ethernet|Ethernet]] frame construction.', + "When a host needs to send an [[ip|IP]] packet to a local destination, it first checks its [[arp|ARP]] cache for the destination's {{mac-address|MAC address}}. On a cache miss, it broadcasts an [[arp|ARP]] Request (EtherType 0x0806) to all devices on the [[ethernet|Ethernet]] segment. The target host replies with its {{mac-address|MAC address}}, which is cached for future [[ethernet|Ethernet]] frame construction.", leftRole: '[[arp|ARP]] provides the [[ip|IP]]-to-{{mac-address|MAC}} resolution mechanism that makes [[ethernet|Ethernet]] delivery possible for [[ip|IP]] traffic.', rightRole: @@ -1924,7 +2830,7 @@ const relationshipPairs: ProtocolPair[] = [ howTheyWork: '[[ip|IP]] provides logical addressing for routing packets across networks, but the last hop to the destination requires a physical {{mac-address|MAC address}}. [[arp|ARP]] translates the destination [[ip|IP]] address to the corresponding {{mac-address|MAC address}} on the local segment. Without [[arp|ARP]], [[ip|IP]] packets could be routed to the correct network but never delivered to the correct host.', leftRole: - '[[arp|ARP]] resolves [[ip|IP]]\'s logical addresses to the hardware addresses needed for local delivery.', + "[[arp|ARP]] resolves [[ip|IP]]'s logical addresses to the hardware addresses needed for local delivery.", rightRole: '[[ip|IP]] provides the logical addressing that [[arp|ARP]] resolves β€” every [[arp|ARP]] request asks "who has this [[ip|IP]] address?"' }, @@ -1932,13 +2838,13 @@ const relationshipPairs: ProtocolPair[] = [ ids: ['ip', 'ethernet'], type: 'relationship', summary: - '[[ip|IP]] packets are encapsulated inside [[ethernet|Ethernet]] frames for delivery on local networks β€” [[ethernet|Ethernet]] is [[ip|IP]]\'s Layer 2 carrier on wired LANs.', + "[[ip|IP]] packets are encapsulated inside [[ethernet|Ethernet]] frames for delivery on local networks β€” [[ethernet|Ethernet]] is [[ip|IP]]'s Layer 2 carrier on wired LANs.", howTheyWork: - 'When an [[ip|IP]] packet needs to traverse a local [[ethernet|Ethernet]] segment, it is placed inside an [[ethernet|Ethernet]] frame (EtherType 0x0800 for [[ip|IPv4]]). The [[ethernet|Ethernet]] frame\'s destination {{mac-address|MAC}} is either the final host (if local) or the {{default-gateway|default gateway}} router. At each router hop, the [[ip|IP]] header stays the same but the [[ethernet|Ethernet]] frame is stripped and rebuilt with new {{mac-address|MAC}} addresses.', + "When an [[ip|IP]] packet needs to traverse a local [[ethernet|Ethernet]] segment, it is placed inside an [[ethernet|Ethernet]] frame (EtherType 0x0800 for [[ip|IPv4]]). The [[ethernet|Ethernet]] frame's destination {{mac-address|MAC}} is either the final host (if local) or the {{default-gateway|default gateway}} router. At each router hop, the [[ip|IP]] header stays the same but the [[ethernet|Ethernet]] frame is stripped and rebuilt with new {{mac-address|MAC}} addresses.", leftRole: '[[ip|IP]] provides logical addressing, routing decisions, and {{ttl|TTL}} management for end-to-end packet delivery.', rightRole: - '[[ethernet|Ethernet]] provides the physical framing and {{mac-address|MAC}}-based delivery for each hop of the [[ip|IP]] packet\'s journey.' + "[[ethernet|Ethernet]] provides the physical framing and {{mac-address|MAC}}-based delivery for each hop of the [[ip|IP]] packet's journey." }, { ids: ['ip', 'wifi'], @@ -1956,13 +2862,13 @@ const relationshipPairs: ProtocolPair[] = [ ids: ['ip', 'tcp'], type: 'relationship', summary: - '[[tcp|TCP]] provides reliable, ordered streams on top of [[ip|IP]]\'s best-effort packet delivery β€” together they form [[tcp|TCP]]/[[ip|IP]], the foundation of the internet.', + "[[tcp|TCP]] provides reliable, ordered streams on top of [[ip|IP]]'s best-effort packet delivery β€” together they form [[tcp|TCP]]/[[ip|IP]], the foundation of the internet.", howTheyWork: '[[ip|IP]] handles addressing and routing packets between {{hosts-bare|hosts}}, but provides no guarantees about delivery, ordering, or duplication. [[tcp|TCP]] adds reliability on top: sequence numbers track byte order, acknowledgments confirm delivery, and {{retransmission|retransmission}} recovers lost packets. Every [[tcp|TCP]] segment is encapsulated in an [[ip|IP]] packet (protocol number 6).', leftRole: '[[ip|IP]] provides the addressing and hop-by-hop routing that delivers packets across networks.', rightRole: - '[[tcp|TCP]] provides reliable, ordered, {{connection-oriented|connection-oriented}} byte streams over [[ip|IP]]\'s unreliable datagram service.' + "[[tcp|TCP]] provides reliable, ordered, {{connection-oriented|connection-oriented}} byte streams over [[ip|IP]]'s unreliable datagram service." }, { ids: ['ip', 'udp'], @@ -1980,13 +2886,13 @@ const relationshipPairs: ProtocolPair[] = [ ids: ['ip', 'icmp'], type: 'relationship', summary: - '[[icmp|ICMP]] is [[ip|IP]]\'s diagnostic companion β€” it reports routing errors, measures reachability, and discovers path {{mtu|MTU}}, all encapsulated directly in [[ip|IP]] packets.', + "[[icmp|ICMP]] is [[ip|IP]]'s diagnostic companion β€” it reports routing errors, measures reachability, and discovers path {{mtu|MTU}}, all encapsulated directly in [[ip|IP]] packets.", howTheyWork: - '[[icmp|ICMP]] messages are encapsulated in [[ip|IP]] packets with protocol number 1 (not [[tcp|TCP]] or [[udp|UDP]]). When a router can\'t deliver an [[ip|IP]] packet ({{ttl|TTL}} expired, destination unreachable, {{fragmentation|fragmentation}} needed), it sends an [[icmp|ICMP]] message back to the sender. Ping ({{echo-request|Echo Request}}/Reply) and {{traceroute|traceroute}} ({{ttl|TTL}}-based hop discovery) are the most common [[icmp|ICMP]] operations.', + "[[icmp|ICMP]] messages are encapsulated in [[ip|IP]] packets with protocol number 1 (not [[tcp|TCP]] or [[udp|UDP]]). When a router can't deliver an [[ip|IP]] packet ({{ttl|TTL}} expired, destination unreachable, {{fragmentation|fragmentation}} needed), it sends an [[icmp|ICMP]] message back to the sender. Ping ({{echo-request|Echo Request}}/Reply) and {{traceroute|traceroute}} ({{ttl|TTL}}-based hop discovery) are the most common [[icmp|ICMP]] operations.", leftRole: '[[ip|IP]] provides the packet delivery that [[icmp|ICMP]] both rides on and diagnoses problems within.', rightRole: - '[[icmp|ICMP]] provides error reporting and diagnostics for [[ip|IP]]\'s routing infrastructure.' + "[[icmp|ICMP]] provides error reporting and diagnostics for [[ip|IP]]'s routing infrastructure." }, // ── JSON-RPC relationships ────────────────────────────────── @@ -1998,8 +2904,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[json-rpc|JSON-RPC]] commonly rides over [[http1|HTTP]] POST β€” the {{http-method|HTTP}} layer handles transport while [[json-rpc|JSON-RPC]] defines the structured method-call semantics inside the body.', howTheyWork: 'The client sends a [[json-rpc|JSON-RPC]] request as the body of an [[http1|HTTP]] POST to a single endpoint (e.g., /rpc). The {{content-type|Content-Type}} is application/json. The server processes the [[json-rpc|JSON-RPC]] call and returns the result in the {{http-method|HTTP}} response body. Unlike [[rest|REST]], the {{http-method|HTTP method}} is always POST and the {{url|URL}} is always the same β€” all routing happens via the method field inside the {{json|JSON}}.', - leftRole: '[[http1|HTTP]] provides the {{request-response|request-response}} transport, connection management, and [[tls|TLS]] {{encryption|encryption}} for [[json-rpc|JSON-RPC]] calls.', - rightRole: '[[json-rpc|JSON-RPC]] provides the method dispatch, parameter passing, error handling, and batch semantics inside the {{http-method|HTTP}} body.' + leftRole: + '[[http1|HTTP]] provides the {{request-response|request-response}} transport, connection management, and [[tls|TLS]] {{encryption|encryption}} for [[json-rpc|JSON-RPC]] calls.', + rightRole: + '[[json-rpc|JSON-RPC]] provides the method dispatch, parameter passing, error handling, and batch semantics inside the {{http-method|HTTP}} body.' }, { ids: ['json-rpc', 'websockets'], @@ -2008,18 +2916,22 @@ const relationshipPairs: ProtocolPair[] = [ '[[json-rpc|JSON-RPC]] over [[websockets|WebSockets]] enables bidirectional {{rpc|RPC}} β€” both client and server can initiate method calls and send notifications over the persistent connection.', howTheyWork: 'After the [[websockets|WebSocket]] {{handshake|handshake}} upgrades the {{http-method|HTTP}} connection, both sides can send [[json-rpc|JSON-RPC]] messages at any time. The client sends requests; the server responds. But the server can also send notifications (no id) or even its own requests to the client β€” something impossible over plain {{http-method|HTTP}}. This is how {{lsp|Language Server Protocol}} (LSP) sends diagnostics and how [[mcp|MCP]] servers push progress updates.', - leftRole: '[[json-rpc|JSON-RPC]] provides the structured call semantics β€” method names, parameters, results, errors, and notifications.', - rightRole: '[[websockets|WebSockets]] provides the persistent, {{full-duplex|full-duplex}} transport that enables server-initiated [[json-rpc|JSON-RPC]] messages.' + leftRole: + '[[json-rpc|JSON-RPC]] provides the structured call semantics β€” method names, parameters, results, errors, and notifications.', + rightRole: + '[[websockets|WebSockets]] provides the persistent, {{full-duplex|full-duplex}} transport that enables server-initiated [[json-rpc|JSON-RPC]] messages.' }, { ids: ['json-rpc', 'sse'], type: 'relationship', summary: - '[[json-rpc|JSON-RPC]] can use [[sse|SSE]] for streaming server responses β€” the client sends requests via {{http-method|HTTP}} POST and receives streamed results as server-sent events, as used by [[mcp|MCP]]\'s Streamable {{http-method|HTTP}} transport.', + "[[json-rpc|JSON-RPC]] can use [[sse|SSE]] for streaming server responses β€” the client sends requests via {{http-method|HTTP}} POST and receives streamed results as server-sent events, as used by [[mcp|MCP]]'s Streamable {{http-method|HTTP}} transport.", howTheyWork: - 'In [[mcp|MCP]]\'s Streamable {{http-method|HTTP}} transport, a client sends a [[json-rpc|JSON-RPC]] request as an {{http-method|HTTP}} POST. The server can respond with a normal {{json|JSON}} response or upgrade to an [[sse|SSE]] stream ({{content-type|Content-Type}}: text/event-stream), sending incremental results and notifications as events. This gives [[json-rpc|JSON-RPC]] streaming capabilities without requiring a full [[websockets|WebSocket]] connection.', - leftRole: '[[json-rpc|JSON-RPC]] provides the method-call structure and request/response correlation via the id field.', - rightRole: '[[sse|SSE]] provides the server-push streaming mechanism for delivering incremental [[json-rpc|JSON-RPC]] results and notifications.' + "In [[mcp|MCP]]'s Streamable {{http-method|HTTP}} transport, a client sends a [[json-rpc|JSON-RPC]] request as an {{http-method|HTTP}} POST. The server can respond with a normal {{json|JSON}} response or upgrade to an [[sse|SSE]] stream ({{content-type|Content-Type}}: text/event-stream), sending incremental results and notifications as events. This gives [[json-rpc|JSON-RPC]] streaming capabilities without requiring a full [[websockets|WebSocket]] connection.", + leftRole: + '[[json-rpc|JSON-RPC]] provides the method-call structure and request/response correlation via the id field.', + rightRole: + '[[sse|SSE]] provides the server-push streaming mechanism for delivering incremental [[json-rpc|JSON-RPC]] results and notifications.' }, // ── MCP relationships ────────────────────────────────────── @@ -2030,29 +2942,35 @@ const relationshipPairs: ProtocolPair[] = [ summary: '[[mcp|MCP]] uses [[json-rpc|JSON-RPC]] 2.0 as its wire format β€” every [[mcp|MCP]] message (initialize, tools/call, notifications) is a [[json-rpc|JSON-RPC]] request, response, or {{notification|notification}}.', howTheyWork: - '[[mcp|MCP]] defines the method names (initialize, tools/list, tools/call, resources/read) and their parameter schemas, while [[json-rpc|JSON-RPC]] provides the framing β€” the id field for {{request-response|request-response}} correlation, the error object format, and the {{notification|notification}} pattern (no id = no response). [[mcp|MCP]]\'s three-step {{handshake|handshake}} is three [[json-rpc|JSON-RPC]] messages: a request, a response, and a {{notification|notification}}.', - leftRole: '[[json-rpc|JSON-RPC]] provides the wire format β€” request/response correlation, error codes, notifications, and transport-agnostic framing.', - rightRole: '[[mcp|MCP]] defines the semantic methods (tools, resources, prompts, {{sampling|sampling}}) and their parameter schemas on top of [[json-rpc|JSON-RPC]].' + "[[mcp|MCP]] defines the method names (initialize, tools/list, tools/call, resources/read) and their parameter schemas, while [[json-rpc|JSON-RPC]] provides the framing β€” the id field for {{request-response|request-response}} correlation, the error object format, and the {{notification|notification}} pattern (no id = no response). [[mcp|MCP]]'s three-step {{handshake|handshake}} is three [[json-rpc|JSON-RPC]] messages: a request, a response, and a {{notification|notification}}.", + leftRole: + '[[json-rpc|JSON-RPC]] provides the wire format β€” request/response correlation, error codes, notifications, and transport-agnostic framing.', + rightRole: + '[[mcp|MCP]] defines the semantic methods (tools, resources, prompts, {{sampling|sampling}}) and their parameter schemas on top of [[json-rpc|JSON-RPC]].' }, { ids: ['http1', 'mcp'], type: 'relationship', summary: - '[[mcp|MCP]]\'s Streamable {{http-method|HTTP}} transport uses [[http1|HTTP]] POST for sending [[json-rpc|JSON-RPC]] messages, with optional [[sse|SSE]] upgrade for streaming responses.', + "[[mcp|MCP]]'s Streamable {{http-method|HTTP}} transport uses [[http1|HTTP]] POST for sending [[json-rpc|JSON-RPC]] messages, with optional [[sse|SSE]] upgrade for streaming responses.", howTheyWork: 'In Streamable {{http-method|HTTP}} mode, the [[mcp|MCP]] client sends [[json-rpc|JSON-RPC]] requests as [[http1|HTTP]] POST bodies to a single endpoint (e.g., /mcp). The server can respond with a plain {{json|JSON}} response or upgrade to an [[sse|SSE]] stream for incremental results. The server assigns a session {{id-identifier|ID}} via the Mcp-Session-Id header for {{stateful|stateful}} session management.', - leftRole: '[[http1|HTTP]] provides the {{request-response|request-response}} transport and connection management for remote [[mcp|MCP]] servers.', - rightRole: '[[mcp|MCP]] defines the [[json-rpc|JSON-RPC]] methods and session semantics carried inside {{http-method|HTTP}} requests.' + leftRole: + '[[http1|HTTP]] provides the {{request-response|request-response}} transport and connection management for remote [[mcp|MCP]] servers.', + rightRole: + '[[mcp|MCP]] defines the [[json-rpc|JSON-RPC]] methods and session semantics carried inside {{http-method|HTTP}} requests.' }, { ids: ['mcp', 'sse'], type: 'relationship', summary: - '[[mcp|MCP]]\'s Streamable {{http-method|HTTP}} transport uses [[sse|SSE]] to stream incremental tool results and server notifications back to the client.', + "[[mcp|MCP]]'s Streamable {{http-method|HTTP}} transport uses [[sse|SSE]] to stream incremental tool results and server notifications back to the client.", howTheyWork: - 'When an [[mcp|MCP]] server needs to stream results (e.g., a long-running tool or progress updates), it responds to the client\'s {{http-method|HTTP}} POST with {{content-type|Content-Type}}: text/event-stream instead of application/json. The server then sends [[json-rpc|JSON-RPC]] responses and notifications as [[sse|SSE]] events. This gives [[mcp|MCP]] streaming capabilities without requiring a persistent [[websockets|WebSocket]] connection.', - leftRole: '[[mcp|MCP]] defines the [[json-rpc|JSON-RPC]] messages (progress notifications, partial results) that are streamed as events.', - rightRole: '[[sse|SSE]] provides the {{http-method|HTTP}}-based streaming mechanism that delivers incremental [[mcp|MCP]] results to the client.' + "When an [[mcp|MCP]] server needs to stream results (e.g., a long-running tool or progress updates), it responds to the client's {{http-method|HTTP}} POST with {{content-type|Content-Type}}: text/event-stream instead of application/json. The server then sends [[json-rpc|JSON-RPC]] responses and notifications as [[sse|SSE]] events. This gives [[mcp|MCP]] streaming capabilities without requiring a persistent [[websockets|WebSocket]] connection.", + leftRole: + '[[mcp|MCP]] defines the [[json-rpc|JSON-RPC]] messages (progress notifications, partial results) that are streamed as events.', + rightRole: + '[[sse|SSE]] provides the {{http-method|HTTP}}-based streaming mechanism that delivers incremental [[mcp|MCP]] results to the client.' }, // ── A2A relationships ────────────────────────────────────── @@ -2063,9 +2981,11 @@ const relationshipPairs: ProtocolPair[] = [ summary: '[[a2a|A2A]] uses [[json-rpc|JSON-RPC]] 2.0 as its wire format β€” agent messages (message/send, message/stream) are [[json-rpc|JSON-RPC]] requests, and task results are [[json-rpc|JSON-RPC]] responses.', howTheyWork: - '[[a2a|A2A]] defines the method names (message/send, message/stream) and their parameter schemas, while [[json-rpc|JSON-RPC]] provides the wire framing. The [[a2a|A2A]] client sends a [[json-rpc|JSON-RPC]] request with a user message, and the server responds with a Task object containing status and artifacts. [[json-rpc|JSON-RPC]]\'s id field correlates multi-turn conversations.', - leftRole: '[[a2a|A2A]] defines the agent communication semantics β€” messages, tasks, parts, artifacts, and the task lifecycle state machine.', - rightRole: '[[json-rpc|JSON-RPC]] provides the request/response framing, error handling, and {{notification|notification}} support for [[a2a|A2A]] messages.' + "[[a2a|A2A]] defines the method names (message/send, message/stream) and their parameter schemas, while [[json-rpc|JSON-RPC]] provides the wire framing. The [[a2a|A2A]] client sends a [[json-rpc|JSON-RPC]] request with a user message, and the server responds with a Task object containing status and artifacts. [[json-rpc|JSON-RPC]]'s id field correlates multi-turn conversations.", + leftRole: + '[[a2a|A2A]] defines the agent communication semantics β€” messages, tasks, parts, artifacts, and the task lifecycle state machine.', + rightRole: + '[[json-rpc|JSON-RPC]] provides the request/response framing, error handling, and {{notification|notification}} support for [[a2a|A2A]] messages.' }, { ids: ['a2a', 'http1'], @@ -2074,8 +2994,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[a2a|A2A]] runs entirely over [[http1|HTTP]] β€” agent discovery (GET /.well-known/agent.json), task communication (POST), and push notifications (webhooks) all use standard {{http-method|HTTP}}.', howTheyWork: 'Agent Cards are served as static {{json|JSON}} at the well-known {{http-method|HTTP}} {{url|URL}}. Task messages are sent as [[json-rpc|JSON-RPC]] payloads in {{http-method|HTTP}} POST requests. For streaming, the server responds with {{content-type|Content-Type}}: text/event-stream ([[sse|SSE]]). Push notifications use {{http-method|HTTP}} POST to a client-provided webhook {{url|URL}}. All communication is standard {{http-method|HTTP}} that works through proxies, load balancers, and CDNs.', - leftRole: '[[a2a|A2A]] defines the agent discovery, task management, and collaboration semantics layered on {{http-method|HTTP}}.', - rightRole: '[[http1|HTTP]] provides the universal transport β€” GET for discovery, POST for messages, [[sse|SSE]] for streaming, webhooks for push.' + leftRole: + '[[a2a|A2A]] defines the agent discovery, task management, and collaboration semantics layered on {{http-method|HTTP}}.', + rightRole: + '[[http1|HTTP]] provides the universal transport β€” GET for discovery, POST for messages, [[sse|SSE]] for streaming, webhooks for push.' }, { ids: ['a2a', 'sse'], @@ -2084,8 +3006,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[a2a|A2A]] uses [[sse|SSE]] to stream task status updates and artifact delivery in real-time via the message/stream method.', howTheyWork: 'When a client calls message/stream instead of message/send, the [[a2a|A2A]] server responds with a text/event-stream. As the agent works, it pushes TaskStatusUpdateEvent (state changes like "working" β†’ "completed") and TaskArtifactUpdateEvent (incremental results) as [[sse|SSE]] events. This allows clients to show real-time progress without polling.', - leftRole: '[[a2a|A2A]] defines the event types (TaskStatusUpdate, TaskArtifactUpdate) that are streamed to the client.', - rightRole: '[[sse|SSE]] provides the {{http-method|HTTP}}-based streaming transport for delivering real-time [[a2a|A2A]] task updates.' + leftRole: + '[[a2a|A2A]] defines the event types (TaskStatusUpdate, TaskArtifactUpdate) that are streamed to the client.', + rightRole: + '[[sse|SSE]] provides the {{http-method|HTTP}}-based streaming transport for delivering real-time [[a2a|A2A]] task updates.' }, { ids: ['a2a', 'mcp'], @@ -2094,8 +3018,10 @@ const relationshipPairs: ProtocolPair[] = [ '[[mcp|MCP]] equips individual agents with tool access; [[a2a|A2A]] enables those equipped agents to collaborate. Together they form the two-protocol foundation of agentic {{ai|AI}}.', howTheyWork: 'In a multi-agent system, [[a2a|A2A]] handles high-level coordination β€” Agent A uses message/send to delegate a sub-task to Agent B. Agent B then uses [[mcp|MCP]] internally to call database tools, read file resources, or invoke APIs to fulfill the task. Agent B returns results to Agent A via [[a2a|A2A]] artifacts. [[mcp|MCP]] is vertical (agent-to-tools), [[a2a|A2A]] is horizontal (agent-to-agent).', - leftRole: '[[a2a|A2A]] provides the inter-agent communication layer β€” discovery, delegation, task lifecycle, and result delivery.', - rightRole: '[[mcp|MCP]] provides the tool integration layer β€” each agent uses [[mcp|MCP]] to access the tools and data it needs to fulfill tasks.' + leftRole: + '[[a2a|A2A]] provides the inter-agent communication layer β€” discovery, delegation, task lifecycle, and result delivery.', + rightRole: + '[[mcp|MCP]] provides the tool integration layer β€” each agent uses [[mcp|MCP]] to access the tools and data it needs to fulfill tasks.' }, // ── SOAP relationships ────────────────────────────────────── @@ -2158,7 +3084,7 @@ const relationshipPairs: ProtocolPair[] = [ ids: ['dns', 'ip'], type: 'relationship', summary: - '[[dns|DNS]] is the phone book for [[ip|IP]]\'s address space β€” it translates human-readable names into the 32-bit or 128-bit addresses that [[ip|IP]] needs to route packets.', + "[[dns|DNS]] is the phone book for [[ip|IP]]'s address space β€” it translates human-readable names into the 32-bit or 128-bit addresses that [[ip|IP]] needs to route packets.", howTheyWork: 'When an application needs to {{mqtt-connect|connect}} to a hostname, it queries [[dns|DNS]], which returns one or more [[ip|IP]] addresses. The operating system then uses [[ip|IP]] to construct packets with the resolved destination address. Without [[dns|DNS]], users would need to memorize numerical addresses; without [[ip|IP]], the resolved addresses would have nowhere to route to.', leftRole: @@ -2184,7 +3110,7 @@ const relationshipPairs: ProtocolPair[] = [ summary: 'Production [[soap|SOAP]] services run over HTTPS, with [[tls|TLS]] encrypting the {{xml|XML}} envelopes in {{transit|transit}}. [[soap|SOAP]] also has its own WS-Security layer for message-level {{encryption|encryption}} and signing.', howTheyWork: - '[[tls|TLS]] provides transport-level {{encryption|encryption}} for [[soap|SOAP]] messages sent over HTTPS β€” protecting the entire {{http-method|HTTP}} request including the {{xml|XML}} envelope. For end-to-end security through intermediaries, [[soap|SOAP]]\'s WS-Security standard adds message-level {{encryption|encryption}} and digital signatures within the [[soap|SOAP]] Header, allowing parts of the message to remain encrypted even when [[tls|TLS]] terminates at a load balancer.', + "[[tls|TLS]] provides transport-level {{encryption|encryption}} for [[soap|SOAP]] messages sent over HTTPS β€” protecting the entire {{http-method|HTTP}} request including the {{xml|XML}} envelope. For end-to-end security through intermediaries, [[soap|SOAP]]'s WS-Security standard adds message-level {{encryption|encryption}} and digital signatures within the [[soap|SOAP]] Header, allowing parts of the message to remain encrypted even when [[tls|TLS]] terminates at a load balancer.", leftRole: '[[soap|SOAP]] defines the {{xml|XML}} message format and can add message-level security via WS-Security headers for end-to-end protection.', rightRole: @@ -2235,7 +3161,7 @@ const relationshipPairs: ProtocolPair[] = [ summary: '[[tcp|TCP]] runs identically over [[ipv6|IPv6]] as over [[ip|IPv4]] β€” the same reliable byte-stream delivery, but [[ipv6|IPv6]] mandates that [[tcp|TCP]] perform {{checksum|checksum}} computation ([[ipv6|IPv6]] has no header {{checksum|checksum}}).', howTheyWork: - '[[tcp|TCP]] segments are encapsulated in [[ipv6|IPv6]] packets with Next Header value 6. The key difference from [[ip|IPv4]]: since [[ipv6|IPv6]] has no header {{checksum|checksum}}, the [[tcp|TCP]] {{checksum|checksum}} is mandatory (not optional). [[tcp|TCP]]\'s pseudo-header for {{checksum|checksum}} computation uses 128-bit addresses instead of 32-bit ones. Otherwise the connection setup, {{flow-control|flow control}}, and congestion algorithms are identical.', + "[[tcp|TCP]] segments are encapsulated in [[ipv6|IPv6]] packets with Next Header value 6. The key difference from [[ip|IPv4]]: since [[ipv6|IPv6]] has no header {{checksum|checksum}}, the [[tcp|TCP]] {{checksum|checksum}} is mandatory (not optional). [[tcp|TCP]]'s pseudo-header for {{checksum|checksum}} computation uses 128-bit addresses instead of 32-bit ones. Otherwise the connection setup, {{flow-control|flow control}}, and congestion algorithms are identical.", leftRole: '[[ipv6|IPv6]] provides 128-bit addressing and routing, carrying [[tcp|TCP]] segments in its {{payload|payload}} with Next Header=6.', rightRole: @@ -2247,7 +3173,7 @@ const relationshipPairs: ProtocolPair[] = [ summary: '[[udp|UDP]] datagrams ride over [[ipv6|IPv6]] just as over [[ip|IPv4]], but with one key difference: the [[udp|UDP]] {{checksum|checksum}} is mandatory in [[ipv6|IPv6]] (it was optional in [[ip|IPv4]]).', howTheyWork: - '[[udp|UDP]] datagrams are carried in [[ipv6|IPv6]] packets with Next Header value 17. Because [[ipv6|IPv6]] eliminated the [[ip|IP]]-layer header {{checksum|checksum}}, [[udp|UDP]]\'s {{checksum|checksum}} became mandatory to ensure minimum integrity coverage. The {{checksum|checksum}} pseudo-header uses the full 128-bit source and destination addresses. Applications like [[dns|DNS]], [[dhcp|DHCPv6]], and real-time media use [[udp|UDP]] over [[ipv6|IPv6]].', + "[[udp|UDP]] datagrams are carried in [[ipv6|IPv6]] packets with Next Header value 17. Because [[ipv6|IPv6]] eliminated the [[ip|IP]]-layer header {{checksum|checksum}}, [[udp|UDP]]'s {{checksum|checksum}} became mandatory to ensure minimum integrity coverage. The {{checksum|checksum}} pseudo-header uses the full 128-bit source and destination addresses. Applications like [[dns|DNS]], [[dhcp|DHCPv6]], and real-time media use [[udp|UDP]] over [[ipv6|IPv6]].", leftRole: '[[ipv6|IPv6]] routes [[udp|UDP]] datagrams across networks using 128-bit addresses and Next Header=17.', rightRole: @@ -2307,12 +3233,13 @@ const relationshipPairs: ProtocolPair[] = [ // LOOKUP // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -const allPairs: ProtocolPair[] = [...vsPairs, ...relationshipPairs]; +export const allPairs: ProtocolPair[] = [...vsPairs, ...relationshipPairs]; /** Map for O(1) lookup by canonical key "idA:idB" (alphabetically sorted). */ const pairMap = new Map<string, ProtocolPair>(); for (const pair of allPairs) { - const key = pair.ids[0] < pair.ids[1] ? `${pair.ids[0]}:${pair.ids[1]}` : `${pair.ids[1]}:${pair.ids[0]}`; + const key = + pair.ids[0] < pair.ids[1] ? `${pair.ids[0]}:${pair.ids[1]}` : `${pair.ids[1]}:${pair.ids[0]}`; pairMap.set(key, pair); } @@ -2323,7 +3250,10 @@ export function getPair(idA: string, idB: string): ProtocolPair | null { } /** Get all pairs involving a given protocol, separated by type. */ -export function getPairsForProtocol(id: string): { vs: ProtocolPair[]; relationships: ProtocolPair[] } { +export function getPairsForProtocol(id: string): { + vs: ProtocolPair[]; + relationships: ProtocolPair[]; +} { const vs: ProtocolPair[] = []; const relationships: ProtocolPair[] = []; for (const pair of allPairs) { diff --git a/src/lib/data/concept-foundations.ts b/src/lib/data/concept-foundations.ts index ddc1b92..0ce1f0c 100644 --- a/src/lib/data/concept-foundations.ts +++ b/src/lib/data/concept-foundations.ts @@ -29,7 +29,8 @@ The deeper trick is that protocols are **public**. They are described in plain t A -->|"3. {{ack|ACK}}"| B A -->|"4. Request"| B B -->|"5. Response"| A`, - caption: '[[tcp|TCP]] requires a {{three-way-handshake|three-way handshake}} before any data can flow. The order matters β€” both sides have to confirm the connection in writing before either can speak its mind.' + caption: + '[[tcp|TCP]] requires a {{three-way-handshake|three-way handshake}} before any data can flow. The order matters β€” both sides have to confirm the connection in writing before either can speak its mind.' }, { type: 'image', @@ -74,7 +75,7 @@ The {{ietf|IETF}}'s job is not to invent these protocols. It is to **document th title: 'Co-author of TCP/IP', org: 'Stanford β†’ DARPA β†’ Google', contribution: - "With [[pioneer:bob-kahn|Bob Kahn]], the 1974 paper that coined the word \"internet\" and described a single protocol they would later split into [[tcp|TCP]] + [[ip|IP]]. Stewards of the protocol's growth across the next four decades.", + 'With [[pioneer:bob-kahn|Bob Kahn]], the 1974 paper that coined the word "internet" and described a single protocol they would later split into [[tcp|TCP]] + [[ip|IP]]. Stewards of the protocol\'s growth across the next four decades.', imagePath: 'https://upload.wikimedia.org/wikipedia/commons/thumb/a/ae/Dr_Vint_Cerf_ForMemRS_%28cropped%29.jpg/330px-Dr_Vint_Cerf_ForMemRS_%28cropped%29.jpg' }, @@ -188,7 +189,7 @@ The win was never about elegance β€” {{osi-model|OSI}}'s seven layers are arguab { type: 'callout', title: 'Rough Consensus and Running Code', - text: 'David Clark\'s 1992 {{ietf|IETF}} quote is the closest thing the internet community has to a national anthem. It says: standards are documents about behavior we have already shipped, not theories we hope someone will adopt. It is the reason new protocols appear as Internet Drafts with reference implementations, not as {{iso|ISO}} documents. And it is why β€” even in 2026 β€” every protocol in this lab traces back to a draft someone could install and run.' + text: "David Clark's 1992 {{ietf|IETF}} quote is the closest thing the internet community has to a national anthem. It says: standards are documents about behavior we have already shipped, not theories we hope someone will adopt. It is the reason new protocols appear as Internet Drafts with reference implementations, not as {{iso|ISO}} documents. And it is why β€” even in 2026 β€” every protocol in this lab traces back to a draft someone could install and run." }, { type: 'narrative', @@ -240,7 +241,8 @@ Together: [[dns|DNS]] resolves the hostname β†’ [[ip|IP]] routes the packet to t [[dns|DNS]] -->|"[[dns|DNS]] resolves"| {{ip-address|IP}} {{ip-address|IP}} -->|"[[arp|ARP]] / {{ndp|NDP}} resolves"| {{mac-address|MAC}} {{mac-address|MAC}} -->|"{{os|OS}} demuxes"| Port`, - caption: 'Each address layer answers a different question. [[dns|DNS]]: who. [[ip|IP]]: where. {{mac-address|MAC}}: which port on this switch. Port: which program.' + caption: + 'Each address layer answers a different question. [[dns|DNS]]: who. [[ip|IP]]: where. {{mac-address|MAC}}: which port on this switch. Port: which program.' }, { type: 'narrative', @@ -288,7 +290,7 @@ This division of labour β€” [[ip|IP]] for end-to-end identity, MAC for hop-to-ho { type: 'callout', title: 'Why an IP looks like four numbers', - text: '[[ip|IPv4]] addresses are 32 bits, conventionally written as four decimal numbers separated by dots: \`192.0.2.5\` is just \`11000000.00000010.00000000.00000101\` in dotted-decimal. The notation is for humans. The router only sees the bits. When you write a {{cidr|CIDR}} prefix like \`192.0.2.0/24\`, the \`/24\` says "the first 24 bits are the network; the last 8 are the host" β€” a {{routing-table|routing table}} lookup compares those leading bits against its prefix entries to pick the next {{hop|hop}}.' + text: '[[ip|IPv4]] addresses are 32 bits, conventionally written as four decimal numbers separated by dots: `192.0.2.5` is just `11000000.00000010.00000000.00000101` in dotted-decimal. The notation is for humans. The router only sees the bits. When you write a {{cidr|CIDR}} prefix like `192.0.2.0/24`, the `/24` says "the first 24 bits are the network; the last 8 are the host" β€” a {{routing-table|routing table}} lookup compares those leading bits against its prefix entries to pick the next {{hop|hop}}.' } ] }, @@ -316,7 +318,8 @@ A {{packet|packet}} is a **self-contained unit** with a **header** (control info D -->|"[[tcp|TCP]] wraps"| S S -->|"{{ip-address|IP}} wraps"| P P -->|"[[ethernet|Ethernet]] wraps"| F`, - caption: 'Each layer adds its own header around the {{payload|payload}} from above. At the destination, headers are stripped in reverse order, and the original {{http-method|HTTP}} request is delivered to the application.' + caption: + 'Each layer adds its own header around the {{payload|payload}} from above. At the destination, headers are stripped in reverse order, and the original {{http-method|HTTP}} request is delivered to the application.' }, { type: 'image', @@ -391,7 +394,8 @@ Three conventional ranges. **Well-known ports** (0–1023) are reserved for stan {{os|OS}} -->|":443"| S["HTTPS Server"] {{os|OS}} -->|":22"| [[ssh|SSH]]["[[ssh|SSH]] Daemon"] OS -->|":5432"| DB["Database"]`, - caption: 'The {{os|OS}} uses the destination port to deliver each packet to the right process. Multiple services share one [[ip|IP]] address; the port disambiguates.' + caption: + 'The {{os|OS}} uses the destination port to deliver each packet to the right process. Multiple services share one [[ip|IP]] address; the port disambiguates.' }, { type: 'image', @@ -435,7 +439,7 @@ This is also why [[quic|QUIC]] runs over [[udp|UDP]] port 443 ([[http3|HTTP/3]]) { type: 'callout', title: 'How a load balancer works at the port level', - text: 'A load balancer like nginx or HAProxy binds to port 443, accepts the inbound [[tcp|TCP]]/[[tls|TLS]] connection, then opens a **separate** outbound connection to one of N backend servers. From the client\'s perspective there is one connection; from the backends\' perspective there are many. The two connections are stitched together in user space. This is why the source [[ip|IP]] at the backend is the load balancer\'s, not the original client\'s, unless you explicitly forward it via the **PROXY protocol** or an {{header|HTTP header}} like \`X-Forwarded-For\`.' + text: "A load balancer like nginx or HAProxy binds to port 443, accepts the inbound [[tcp|TCP]]/[[tls|TLS]] connection, then opens a **separate** outbound connection to one of N backend servers. From the client's perspective there is one connection; from the backends' perspective there are many. The two connections are stitched together in user space. This is why the source [[ip|IP]] at the backend is the load balancer's, not the original client's, unless you explicitly forward it via the **PROXY protocol** or an {{header|HTTP header}} like `X-Forwarded-For`." } ] }, @@ -460,7 +464,8 @@ This tradeoff drives the entire protocol ecosystem. Web pages need reliability definition: `graph LR [[udp|UDP]]["<b>[[udp|UDP]]</b><br/>No guarantees<br/>8-byte header"] ---|"+ {{encryption|encryption}} + {{multiplexing|multiplexing}}"| [[quic|QUIC]]["<b>[[quic|QUIC]]</b><br/>Per-stream reliability<br/>0/{{one-rtt|1-RTT}} {{handshake|handshake}}"] [[quic|QUIC]] ---|"+ ordered byte stream"| [[tcp|TCP]]["<b>[[tcp|TCP]]</b><br/>Full reliability<br/>{{one-rtt|1-RTT}} {{handshake|handshake}}"]`, - caption: 'Protocols sit on a {{spectrum|spectrum}} from raw speed ([[udp|UDP]]) to guaranteed delivery ([[tcp|TCP]]). [[quic|QUIC]] sits in between by giving each multiplexed stream its own reliability β€” so a lost packet only blocks one stream.' + caption: + 'Protocols sit on a {{spectrum|spectrum}} from raw speed ([[udp|UDP]]) to guaranteed delivery ([[tcp|TCP]]). [[quic|QUIC]] sits in between by giving each multiplexed stream its own reliability β€” so a lost packet only blocks one stream.' }, { type: 'narrative', @@ -499,7 +504,8 @@ The principle they articulated β€” **conservation of packets** β€” has held up f RC -->|"new {{ack|ACK}}"| CA CA -->|"loss detected"| FR CA -->|"timeout"| S0`, - caption: 'The four-phase loop every [[tcp|TCP]] {{congestion-control|congestion controller}} has used since 1988. Modern algorithms ({{cubic|CUBIC}}, {{bbr|BBR}}) replace the linear growth in {{congestion-avoidance|Congestion Avoidance}} with their own curves, but the overall shape is unchanged.' + caption: + 'The four-phase loop every [[tcp|TCP]] {{congestion-control|congestion controller}} has used since 1988. Modern algorithms ({{cubic|CUBIC}}, {{bbr|BBR}}) replace the linear growth in {{congestion-avoidance|Congestion Avoidance}} with their own curves, but the overall shape is unchanged.' }, { type: 'narrative', @@ -546,7 +552,8 @@ BBRv1 hit ~4% mean throughput improvement on YouTube globally, more than 14% in C2021 --> C2023a["<b>2023</b><br/>{{bbrv3|BBRv3}} default<br/>for {{google|google}}.com / YouTube"] C2021 --> C2023b["<b>Jan 2023</b><br/>{{l4s|L4S}}<br/>[[rfc:9330|RFC 9330]]/9331/9332"] C2023b --> C2025["<b>Jan 2025</b><br/>Comcast {{l4s|L4S}}<br/>in production"]`, - caption: 'Every [[tcp|TCP]] congestion controller is a chapter in the story Jacobson started. Modern transports β€” {{cubic|CUBIC}}, {{bbr|BBR}}, {{l4s|L4S}}, RACK-TLP β€” are each refinements of the same conservation-of-packets principle, adapted to different network realities.' + caption: + 'Every [[tcp|TCP]] congestion controller is a chapter in the story Jacobson started. Modern transports β€” {{cubic|CUBIC}}, {{bbr|BBR}}, {{l4s|L4S}}, RACK-TLP β€” are each refinements of the same conservation-of-packets principle, adapted to different network realities.' }, { type: 'narrative', @@ -592,7 +599,8 @@ Second, **trust is concentrated**. The server can be hardened, audited, monitore P3 <--> P1 end CS ~~~ P2P`, - caption: 'Client-server centralises control through one authority. {{peer-to-peer|P2P}} connects nodes directly β€” more resilient but harder to coordinate.' + caption: + 'Client-server centralises control through one authority. {{peer-to-peer|P2P}} connects nodes directly β€” more resilient but harder to coordinate.' }, { type: 'image', @@ -668,9 +676,9 @@ The combination is what makes the modern web tractable. You use slow asymmetric { type: 'image', src: 'https://upload.wikimedia.org/wikipedia/commons/thumb/f/fb/Asymmetric_Cryptography.svg/500px-Asymmetric_Cryptography.svg.png', - alt: 'Public-key cryptography: sender encrypts with the recipient\'s public key; recipient decrypts with their matching private key.', + alt: "Public-key cryptography: sender encrypts with the recipient's public key; recipient decrypts with their matching private key.", caption: - '{{public-key|Public-key}} cryptography. Anyone can {{encryption|encrypt}} a message using the recipient\'s {{public-key|public key}} (which is shared openly). Only the recipient β€” the holder of the matching {{private-key|private key}} β€” can decrypt it. This solves the key-distribution problem that defeated symmetric ciphers for centuries.', + "{{public-key|Public-key}} cryptography. Anyone can {{encryption|encrypt}} a message using the recipient's {{public-key|public key}} (which is shared openly). Only the recipient β€” the holder of the matching {{private-key|private key}} β€” can decrypt it. This solves the key-distribution problem that defeated symmetric ciphers for centuries.", credit: 'Diagram: Wikimedia Commons / public domain' }, { @@ -685,7 +693,8 @@ The combination is what makes the modern web tractable. You use slow asymmetric C2["Client"] <-->|"{{aes|AES}} / ChaCha20 encrypted"| S2["Server"] end {{handshake|Handshake}} -->|"shared secret"| Data`, - caption: '[[tls|TLS]] uses slow {{asymmetric-encryption|asymmetric crypto}} to safely {{exchange|exchange}} a session key, then switches to fast {{symmetric-encryption|symmetric encryption}} for all data. The {{handshake|handshake}} is a few hundred bytes; the data can be gigabytes.' + caption: + '[[tls|TLS]] uses slow {{asymmetric-encryption|asymmetric crypto}} to safely {{exchange|exchange}} a session key, then switches to fast {{symmetric-encryption|symmetric encryption}} for all data. The {{handshake|handshake}} is a few hundred bytes; the data can be gigabytes.' }, { type: 'image', @@ -751,7 +760,8 @@ In April 2025, {{google|Google}} published **Agent-to-Agent Protocol** β€” [[a2a {{stdio|STDIO}}["{{stdio|stdio}} (local)"] end Wire -.-> Transport`, - caption: '{{ai|AI}} protocols sit at the application layer, using [[json-rpc|JSON-RPC]] 2.0 as their wire format and {{http-method|HTTP}} (or {{stdio|stdio}}) as their transport. [[mcp|MCP]] connects agents to tools; [[a2a|A2A]] connects agents to each other.' + caption: + '{{ai|AI}} protocols sit at the application layer, using [[json-rpc|JSON-RPC]] 2.0 as their wire format and {{http-method|HTTP}} (or {{stdio|stdio}}) as their transport. [[mcp|MCP]] connects agents to tools; [[a2a|A2A]] connects agents to each other.' }, { type: 'narrative', diff --git a/src/lib/data/concepts.ts b/src/lib/data/concepts.ts index f658cbe..77dae1f 100644 --- a/src/lib/data/concepts.ts +++ b/src/lib/data/concepts.ts @@ -41,7 +41,7 @@ export const concepts: Concept[] = [ id: 'imp', term: 'IMP (Interface Message Processor)', definition: - "The refrigerator-sized minicomputers (modified Honeywell DDP-516s) built by {{bbn|BBN}} that served as {{arpanet|ARPANET}}'s first routers. The IMP at UCLA processed the very first ARPANET message on October 29, 1969 β€” the network's \"Hello World.\"", + 'The refrigerator-sized minicomputers (modified Honeywell DDP-516s) built by {{bbn|BBN}} that served as {{arpanet|ARPANET}}\'s first routers. The IMP at UCLA processed the very first ARPANET message on October 29, 1969 β€” the network\'s "Hello World."', analogy: 'The original router, but the size of a wardrobe and humming loud enough to fill a room.', wikiUrl: 'https://en.wikipedia.org/wiki/Interface_Message_Processor', @@ -71,7 +71,7 @@ export const concepts: Concept[] = [ id: 'bbn', term: 'BBN (Bolt, Beranek and Newman)', definition: - "The Cambridge, Mass. consultancy that won the {{arpanet|ARPANET}} hardware contract in 1968 and built the {{imp|IMPs}}. BBN also wrote the first @-sign email program ([[pioneer:ray-tomlinson|Ray Tomlinson]], 1971) and much of the early internet plumbing. Now part of RTX (Raytheon Technologies).", + 'The Cambridge, Mass. consultancy that won the {{arpanet|ARPANET}} hardware contract in 1968 and built the {{imp|IMPs}}. BBN also wrote the first @-sign email program ([[pioneer:ray-tomlinson|Ray Tomlinson]], 1971) and much of the early internet plumbing. Now part of RTX (Raytheon Technologies).', analogy: 'The Skunk Works of early networking β€” small team, contract by contract, no glamour, all of the foundations.', wikiUrl: 'https://en.wikipedia.org/wiki/BBN_Technologies', @@ -82,8 +82,7 @@ export const concepts: Concept[] = [ term: 'IANA (Internet Assigned Numbers Authority)', definition: 'The function (not an organization) responsible for assigning unique numbers used by internet protocols β€” [[ip|IP]] address blocks, AS numbers, well-known port numbers, MIME types, character sets. Run single-handedly by [[pioneer:jon-postel|Jon Postel]] from his ISI office for over a decade; now operated by {{icann|ICANN}}.', - analogy: - 'The phone directory that prevents two countries from claiming the same area code.', + analogy: 'The phone directory that prevents two countries from claiming the same area code.', wikiUrl: 'https://en.wikipedia.org/wiki/Internet_Assigned_Numbers_Authority', category: 'infrastructure' }, @@ -102,8 +101,7 @@ export const concepts: Concept[] = [ term: 'W3C (World Wide Web Consortium)', definition: 'The standards body for the web, founded by [[pioneer:tim-berners-lee|Tim Berners-Lee]] in 1994 and hosted by MIT (and partners). Publishes the specs for HTML, CSS, the DOM, and dozens of related web technologies. Where the {{ietf|IETF}} does wire formats, the W3C does the layers above HTTP.', - analogy: - '{{ietf|IETF}} runs the rails, W3C runs the trains.', + analogy: '{{ietf|IETF}} runs the rails, W3C runs the trains.', wikiUrl: 'https://en.wikipedia.org/wiki/World_Wide_Web_Consortium', category: 'web' }, @@ -112,8 +110,7 @@ export const concepts: Concept[] = [ term: 'ISOC (Internet Society)', definition: 'Non-profit founded in 1992 to provide an organizational home for the {{ietf|IETF}} and to advocate for open internet policy worldwide. Funds the IETF Trust, supports the IRTF research arm, and runs programs on internet access, encryption, and routing security.', - analogy: - 'The fiscal sponsor and policy lobby for the people who actually write the protocols.', + analogy: 'The fiscal sponsor and policy lobby for the people who actually write the protocols.', wikiUrl: 'https://en.wikipedia.org/wiki/Internet_Society', category: 'infrastructure' }, @@ -313,7 +310,8 @@ export const concepts: Concept[] = [ term: 'Connectionless', definition: 'A communication mode where each packet is sent independently with no prior setup or guaranteed delivery (e.g., [[udp|UDP]]). Faster and simpler, but no ordering or reliability guarantees.', - analogy: 'Like sending postcards β€” each one travels independently and might arrive out of order.', + analogy: + 'Like sending postcards β€” each one travels independently and might arrive out of order.', wikiUrl: 'https://en.wikipedia.org/wiki/Connectionless_communication', category: 'networking-basics' }, @@ -468,8 +466,7 @@ export const concepts: Concept[] = [ term: 'Encryption', definition: 'The process of converting readable data (plaintext) into unreadable data (ciphertext) using an algorithm and a key. Only someone with the correct key can decrypt it back.', - analogy: - 'Like writing a message in a secret code that only your friend knows how to decode.', + analogy: 'Like writing a message in a secret code that only your friend knows how to decode.', wikiUrl: 'https://en.wikipedia.org/wiki/Encryption', category: 'security' }, @@ -538,7 +535,7 @@ export const concepts: Concept[] = [ id: 'certificate-authority', term: 'Certificate Authority (CA)', definition: - 'An organisation trusted to issue digital certificates. CAs sign certificates after verifying the requester controls a domain (DV), an organisation (OV), or has been extended-validated (EV). Root CAs are pre-installed in browsers and operating systems; intermediate CAs sign on their behalf so the root key can stay offline. Let\'s Encrypt, DigiCert, Sectigo, GoDaddy, and Google Trust Services issue most public-web certificates.', + "An organisation trusted to issue digital certificates. CAs sign certificates after verifying the requester controls a domain (DV), an organisation (OV), or has been extended-validated (EV). Root CAs are pre-installed in browsers and operating systems; intermediate CAs sign on their behalf so the root key can stay offline. Let's Encrypt, DigiCert, Sectigo, GoDaddy, and Google Trust Services issue most public-web certificates.", analogy: 'Like a notary public β€” a third party that the issuing world has agreed to trust, so a stamp from them means the document is what it claims to be.', wikiUrl: 'https://en.wikipedia.org/wiki/Certificate_authority', @@ -724,7 +721,7 @@ export const concepts: Concept[] = [ id: 'mtu', term: 'MTU (Maximum Transmission Unit)', definition: - 'The largest packet size (in bytes) that a network link can carry. [[ethernet|Ethernet]] defaults to 1500 bytes. Packets larger than the MTU must be fragmented or dropped (if the Don\'t Fragment flag is set). Path MTU Discovery finds the smallest MTU along a route.', + "The largest packet size (in bytes) that a network link can carry. [[ethernet|Ethernet]] defaults to 1500 bytes. Packets larger than the MTU must be fragmented or dropped (if the Don't Fragment flag is set). Path MTU Discovery finds the smallest MTU along a route.", analogy: 'Like the maximum box size a conveyor belt can handle β€” anything bigger must be split into smaller boxes.', wikiUrl: 'https://en.wikipedia.org/wiki/Maximum_transmission_unit', @@ -742,7 +739,7 @@ export const concepts: Concept[] = [ id: 'checksum', term: 'Checksum', definition: - 'A small value computed from a block of data to detect transmission errors. [[tcp|TCP]], [[udp|UDP]], and [[ip|IP]] each include checksums in their headers. The receiver recomputes the checksum and drops the packet if it doesn\'t match.', + "A small value computed from a block of data to detect transmission errors. [[tcp|TCP]], [[udp|UDP]], and [[ip|IP]] each include checksums in their headers. The receiver recomputes the checksum and drops the packet if it doesn't match.", analogy: 'Like a check digit on a credit card number β€” a quick math test that catches accidental typos.', wikiUrl: 'https://en.wikipedia.org/wiki/Checksum', @@ -752,7 +749,7 @@ export const concepts: Concept[] = [ id: 'proxy', term: 'Proxy / Reverse Proxy', definition: - 'A proxy sits between client and server, forwarding requests on the client\'s behalf (hiding the client). A reverse proxy sits in front of servers, distributing incoming requests (hiding the servers). Used for caching, load balancing, and security.', + "A proxy sits between client and server, forwarding requests on the client's behalf (hiding the client). A reverse proxy sits in front of servers, distributing incoming requests (hiding the servers). Used for caching, load balancing, and security.", analogy: 'A forward proxy is like a personal assistant making calls for you. A reverse proxy is like a receptionist directing visitors to the right office.', wikiUrl: 'https://en.wikipedia.org/wiki/Reverse_proxy', @@ -788,9 +785,9 @@ export const concepts: Concept[] = [ id: 'forward-secrecy', term: 'Forward Secrecy', definition: - 'A property of key exchange protocols (like ECDHE) where compromising the server\'s long-term private key does not compromise past session keys. Each session generates unique ephemeral keys that are discarded after use.', + "A property of key exchange protocols (like ECDHE) where compromising the server's long-term private key does not compromise past session keys. Each session generates unique ephemeral keys that are discarded after use.", analogy: - 'Like using a different lock combination for every package β€” even if someone learns today\'s code, they cannot open yesterday\'s packages.', + "Like using a different lock combination for every package β€” even if someone learns today's code, they cannot open yesterday's packages.", wikiUrl: 'https://en.wikipedia.org/wiki/Forward_secrecy', category: 'security' }, @@ -798,7 +795,7 @@ export const concepts: Concept[] = [ id: 'dtls', term: 'DTLS (Datagram TLS)', definition: - 'A variant of [[tls|TLS]] designed for datagram protocols like [[udp|UDP]]. Provides the same encryption, authentication, and integrity guarantees as [[tls|TLS]], but handles packet loss and reordering that [[udp|UDP]] doesn\'t prevent. Used by [[webrtc|WebRTC]] and [[coap|CoAP]].', + "A variant of [[tls|TLS]] designed for datagram protocols like [[udp|UDP]]. Provides the same encryption, authentication, and integrity guarantees as [[tls|TLS]], but handles packet loss and reordering that [[udp|UDP]] doesn't prevent. Used by [[webrtc|WebRTC]] and [[coap|CoAP]].", wikiUrl: 'https://en.wikipedia.org/wiki/Datagram_Transport_Layer_Security', category: 'security' }, @@ -870,8 +867,7 @@ export const concepts: Concept[] = [ term: 'Broadcast', definition: 'A one-to-all transmission sent to every device on a local network segment. [[arp|ARP]] uses broadcast to find MAC addresses. [[ipv6|IPv6]] eliminates broadcast entirely, replacing it with multicast. Excessive broadcast traffic causes "broadcast storms."', - analogy: - 'Like a PA announcement in a building β€” everyone hears it, whether they care or not.', + analogy: 'Like a PA announcement in a building β€” everyone hears it, whether they care or not.', wikiUrl: 'https://en.wikipedia.org/wiki/Broadcasting_(networking)', category: 'networking-basics' }, @@ -925,7 +921,7 @@ export const concepts: Concept[] = [ id: 'opacity', term: 'Opacity (Agent Design)', definition: - 'A design principle where an agent\'s internal reasoning, tool usage, and prompt chains are hidden from external observers. In [[a2a|A2A]], agents are opaque β€” you see their skills and outputs (artifacts), not how they arrive at results. This enables agents from different vendors to interoperate without exposing proprietary logic.', + "A design principle where an agent's internal reasoning, tool usage, and prompt chains are hidden from external observers. In [[a2a|A2A]], agents are opaque β€” you see their skills and outputs (artifacts), not how they arrive at results. This enables agents from different vendors to interoperate without exposing proprietary logic.", wikiUrl: 'https://a2a-protocol.org/latest/topics/key-concepts/', category: 'protocol-mechanics' }, @@ -1111,7 +1107,7 @@ export const concepts: Concept[] = [ id: 'tunnel', term: 'Tunnel / Tunneling', definition: - 'Encapsulating one {{protocol|protocol}} inside another to carry traffic across a network that doesn\'t natively support it. For example, [[ssh|SSH]] tunnels wrap [[tcp|TCP]] traffic inside an encrypted [[ssh|SSH]] connection, and VPNs tunnel all traffic through an encrypted link. The outer protocol handles delivery; the inner protocol rides along as {{payload|payload}}.', + "Encapsulating one {{protocol|protocol}} inside another to carry traffic across a network that doesn't natively support it. For example, [[ssh|SSH]] tunnels wrap [[tcp|TCP]] traffic inside an encrypted [[ssh|SSH]] connection, and VPNs tunnel all traffic through an encrypted link. The outer protocol handles delivery; the inner protocol rides along as {{payload|payload}}.", analogy: 'Like putting a letter inside a letter β€” the outer envelope gets it through the postal system, and the inner envelope carries the real message.', wikiUrl: 'https://en.wikipedia.org/wiki/Tunneling_protocol', @@ -1121,9 +1117,9 @@ export const concepts: Concept[] = [ id: 'vpn', term: 'VPN (Virtual Private Network)', definition: - 'A technology that creates an encrypted {{tunnel|tunnel}} between your device and a VPN server, making all your traffic appear to originate from the server\'s [[ip|IP]] address. Used for privacy (hiding traffic from ISPs), security (protecting data on public [[wifi|Wi-Fi]]), and accessing remote networks (corporate VPNs). Common protocols include WireGuard, OpenVPN, and IPsec.', + "A technology that creates an encrypted {{tunnel|tunnel}} between your device and a VPN server, making all your traffic appear to originate from the server's [[ip|IP]] address. Used for privacy (hiding traffic from ISPs), security (protecting data on public [[wifi|Wi-Fi]]), and accessing remote networks (corporate VPNs). Common protocols include WireGuard, OpenVPN, and IPsec.", analogy: - 'Like a secret underground passage between two buildings β€” outsiders can\'t see what you\'re carrying or where you\'re really going.', + "Like a secret underground passage between two buildings β€” outsiders can't see what you're carrying or where you're really going.", wikiUrl: 'https://en.wikipedia.org/wiki/Virtual_private_network', category: 'security' }, @@ -1179,7 +1175,7 @@ export const concepts: Concept[] = [ id: 'man-in-the-middle', term: 'Man-in-the-Middle Attack (MITM)', definition: - 'An attack where the attacker secretly intercepts and potentially alters communication between two parties who believe they are talking directly to each other. {{spoofing|ARP spoofing}} on a local network is a classic MITM vector. [[tls|TLS]] {{certificate|certificates}} prevent MITM by authenticating the server\'s identity.', + "An attack where the attacker secretly intercepts and potentially alters communication between two parties who believe they are talking directly to each other. {{spoofing|ARP spoofing}} on a local network is a classic MITM vector. [[tls|TLS]] {{certificate|certificates}} prevent MITM by authenticating the server's identity.", analogy: 'Like a postal worker secretly opening, reading, and resealing your letters β€” both you and the recipient think the envelope was never touched.', wikiUrl: 'https://en.wikipedia.org/wiki/Man-in-the-middle_attack', @@ -1339,7 +1335,7 @@ export const concepts: Concept[] = [ id: 'bdp', term: 'BDP (Bandwidth-Delay Product)', definition: - 'The amount of data needed in flight to fully utilise a network path: bandwidth Γ— round-trip time. The natural target size for a sender\'s congestion window. A 100 ms Γ— 1 Gbps path has a 12.5 MB BDP.', + "The amount of data needed in flight to fully utilise a network path: bandwidth Γ— round-trip time. The natural target size for a sender's congestion window. A 100 ms Γ— 1 Gbps path has a 12.5 MB BDP.", analogy: 'Like the volume of water needed to fill a hose end-to-end before flow becomes steady β€” short hose or low pressure means less water; long hose or high pressure means more.', wikiUrl: 'https://en.wikipedia.org/wiki/Bandwidth-delay_product', @@ -1357,7 +1353,7 @@ export const concepts: Concept[] = [ id: 'cubic', term: 'CUBIC', definition: - 'The [[tcp|TCP]] congestion control algorithm that has been the Linux default since 2.6.19 (2006), Windows default since 2017, and is now Standards Track as [[rfc:9438|RFC 9438]] (2023). Replaces AIMD\'s linear ramp with a cubic function of time since the last loss β€” much friendlier to long fat pipes.', + "The [[tcp|TCP]] congestion control algorithm that has been the Linux default since 2.6.19 (2006), Windows default since 2017, and is now Standards Track as [[rfc:9438|RFC 9438]] (2023). Replaces AIMD's linear ramp with a cubic function of time since the last loss β€” much friendlier to long fat pipes.", wikiUrl: 'https://en.wikipedia.org/wiki/CUBIC_TCP', category: 'protocol-mechanics' }, @@ -1365,7 +1361,7 @@ export const concepts: Concept[] = [ id: 'bbr', term: 'BBR (Bottleneck Bandwidth and Round-trip)', definition: - 'Google\'s 2016 model-based congestion control. Instead of treating loss as the only signal, BBR estimates the path\'s bottleneck bandwidth and minimum RTT and paces packets to fully use the bandwidth without filling buffers. BBRv3 has been the default for google.com and YouTube since 2023.', + "Google's 2016 model-based congestion control. Instead of treating loss as the only signal, BBR estimates the path's bottleneck bandwidth and minimum RTT and paces packets to fully use the bandwidth without filling buffers. BBRv3 has been the default for google.com and YouTube since 2023.", wikiUrl: 'https://en.wikipedia.org/wiki/TCP_congestion_control#TCP_BBR', category: 'protocol-mechanics' }, @@ -1389,7 +1385,7 @@ export const concepts: Concept[] = [ id: 'aqm', term: 'AQM (Active Queue Management)', definition: - 'Algorithms that drop or mark packets in a router\'s queue *before* the queue fills up, signaling senders to slow down early instead of buffering data into seconds of latency. CoDel, FQ-CoDel, PIE, and the L4S DualQ Coupled AQM are modern examples; their absence is why bufferbloat exists.', + "Algorithms that drop or mark packets in a router's queue *before* the queue fills up, signaling senders to slow down early instead of buffering data into seconds of latency. CoDel, FQ-CoDel, PIE, and the L4S DualQ Coupled AQM are modern examples; their absence is why bufferbloat exists.", wikiUrl: 'https://en.wikipedia.org/wiki/Active_queue_management', category: 'protocol-mechanics' }, @@ -1430,7 +1426,8 @@ export const concepts: Concept[] = [ term: 'Session Resumption', definition: "A handshake shortcut where a returning client and server skip the full key exchange by reusing parameters from a previous session, identified by a session ID or session ticket. Saves an entire round-trip and the cost of asymmetric crypto. Underpins [[tls|TLS]] 1.3's 1-RTT and 0-RTT resumption.", - wikiUrl: 'https://en.wikipedia.org/wiki/Transport_Layer_Security#Session_IDs_and_session_tickets', + wikiUrl: + 'https://en.wikipedia.org/wiki/Transport_Layer_Security#Session_IDs_and_session_tickets', category: 'protocol-mechanics' }, { @@ -1537,7 +1534,7 @@ export const concepts: Concept[] = [ id: 'syn-flood', term: 'SYN Flood', definition: - 'A denial-of-service attack that sends many [[tcp|TCP]] SYN packets without completing the handshake, exhausting the server\'s half-open-connection table. The attack first hit the public internet at Panix in September 1996 and motivated D. J. Bernstein to invent SYN cookies within days.', + "A denial-of-service attack that sends many [[tcp|TCP]] SYN packets without completing the handshake, exhausting the server's half-open-connection table. The attack first hit the public internet at Panix in September 1996 and motivated D. J. Bernstein to invent SYN cookies within days.", wikiUrl: 'https://en.wikipedia.org/wiki/SYN_flood', category: 'security' }, @@ -1555,7 +1552,7 @@ export const concepts: Concept[] = [ id: 'same-origin-policy', term: 'Same-Origin Policy', definition: - 'The browser\'s foundational security boundary: scripts loaded from one origin (scheme + host + port) cannot read responses from another origin without that origin\'s explicit consent. CORS, document.domain, postMessage, and Cookie SameSite are the carve-outs and escape valves built around it.', + "The browser's foundational security boundary: scripts loaded from one origin (scheme + host + port) cannot read responses from another origin without that origin's explicit consent. CORS, document.domain, postMessage, and Cookie SameSite are the carve-outs and escape valves built around it.", wikiUrl: 'https://en.wikipedia.org/wiki/Same-origin_policy', category: 'web' }, @@ -1647,7 +1644,7 @@ export const concepts: Concept[] = [ definition: 'The property that you can answer arbitrary questions about a running system from the outside β€” typically by combining three signal types: *metrics* (numerical aggregates over time), *logs* (timestamped events), and *traces* (causally-linked spans across services). OpenTelemetry is the standard wire format.', analogy: - 'Like the difference between a car\'s dashboard (metrics: a few numbers you watch) and a black-box flight recorder (traces: a complete record you query after the fact). Observability is having both.', + "Like the difference between a car's dashboard (metrics: a few numbers you watch) and a black-box flight recorder (traces: a complete record you query after the fact). Observability is having both.", wikiUrl: 'https://en.wikipedia.org/wiki/Observability_(software)', category: 'infrastructure' }, @@ -1673,7 +1670,7 @@ export const concepts: Concept[] = [ id: 'peering', term: 'Peering', definition: - 'A bilateral interconnection between two networks where each agrees to exchange traffic destined for the other (and the other\'s customers) at no cost. Distinct from *transit*, where one network pays another for access to the rest of the internet. Public peering happens at IXPs; private peering is direct fibre between two AS edges.', + "A bilateral interconnection between two networks where each agrees to exchange traffic destined for the other (and the other's customers) at no cost. Distinct from *transit*, where one network pays another for access to the rest of the internet. Public peering happens at IXPs; private peering is direct fibre between two AS edges.", wikiUrl: 'https://en.wikipedia.org/wiki/Peering', category: 'networking-basics' }, @@ -1689,7 +1686,7 @@ export const concepts: Concept[] = [ id: 'ixp', term: 'IXP (Internet Exchange Point)', definition: - 'A neutral facility where many autonomous systems meet on a shared layer-2 fabric (typically [[ethernet|Ethernet]]) to exchange traffic via [[bgp|BGP]] without paying transit. AMS-IX, DE-CIX, and LINX move terabits per second. The IXP itself doesn\'t move traffic β€” it provides the meet-me room and the switch.', + "A neutral facility where many autonomous systems meet on a shared layer-2 fabric (typically [[ethernet|Ethernet]]) to exchange traffic via [[bgp|BGP]] without paying transit. AMS-IX, DE-CIX, and LINX move terabits per second. The IXP itself doesn't move traffic β€” it provides the meet-me room and the switch.", wikiUrl: 'https://en.wikipedia.org/wiki/Internet_exchange_point', category: 'networking-basics' }, @@ -1712,7 +1709,7 @@ export const concepts: Concept[] = [ id: 'ndp', term: 'NDP (Neighbor Discovery Protocol)', definition: - "[[ipv6|IPv6]]'s replacement for [[arp|ARP]] plus router discovery, prefix discovery, and Duplicate Address Detection ([[rfc:4861|RFC 4861]]). Runs over ICMPv6 multicast on the local link. Where [[arp|ARP]] broadcasts \"who has 192.0.2.7?\", NDP sends a Neighbor Solicitation to a solicited-node multicast group β€” much more efficient.", + '[[ipv6|IPv6]]\'s replacement for [[arp|ARP]] plus router discovery, prefix discovery, and Duplicate Address Detection ([[rfc:4861|RFC 4861]]). Runs over ICMPv6 multicast on the local link. Where [[arp|ARP]] broadcasts "who has 192.0.2.7?", NDP sends a Neighbor Solicitation to a solicited-node multicast group β€” much more efficient.', wikiUrl: 'https://en.wikipedia.org/wiki/Neighbor_Discovery_Protocol', category: 'networking-basics' }, @@ -1721,7 +1718,8 @@ export const concepts: Concept[] = [ term: 'SLAAC (Stateless Address Autoconfiguration)', definition: "[[ipv6|IPv6]]'s mechanism ([[rfc:4862|RFC 4862]]) for hosts to generate their own globally-unique addresses without a [[dhcp|DHCP]] server. The router advertises a prefix; the host appends an interface identifier (EUI-64 or RFC 7217 stable-private). No server, no lease, no central state.", - wikiUrl: 'https://en.wikipedia.org/wiki/[[ipv6|IPv6]]#Stateless_address_autoconfiguration_(SLAAC)', + wikiUrl: + 'https://en.wikipedia.org/wiki/[[ipv6|IPv6]]#Stateless_address_autoconfiguration_(SLAAC)', category: 'networking-basics' }, { @@ -1736,7 +1734,7 @@ export const concepts: Concept[] = [ id: 'four-six-four-xlat', term: '464XLAT', definition: - "An [[ipv6|IPv6]] transition mechanism ([[rfc:6877|RFC 6877]]) that lets [[ip|IPv4]]-only applications run on [[ipv6|IPv6]]-only access networks. A CLAT on the host translates [[ip|IPv4]] β†’ [[ipv6|IPv6]]; a PLAT (NAT64) at the carrier edge translates [[ipv6|IPv6]] β†’ [[ip|IPv4]]. Modern Android, iOS, macOS, and Windows 11 ship CLAT natively. Why your phone can be [[ipv6|IPv6]]-only without breaking ancient apps.", + 'An [[ipv6|IPv6]] transition mechanism ([[rfc:6877|RFC 6877]]) that lets [[ip|IPv4]]-only applications run on [[ipv6|IPv6]]-only access networks. A CLAT on the host translates [[ip|IPv4]] β†’ [[ipv6|IPv6]]; a PLAT (NAT64) at the carrier edge translates [[ipv6|IPv6]] β†’ [[ip|IPv4]]. Modern Android, iOS, macOS, and Windows 11 ship CLAT natively. Why your phone can be [[ipv6|IPv6]]-only without breaking ancient apps.', wikiUrl: 'https://en.wikipedia.org/wiki/464XLAT', category: 'networking-basics' }, @@ -1754,7 +1752,7 @@ export const concepts: Concept[] = [ id: 'tcp-fin', term: 'TCP FIN', definition: - "A [[tcp|TCP]] packet with the FIN flag set, signalling \"I'm done sending data β€” but I'll keep listening.\" The graceful counterpart to RST. A clean [[tcp|TCP]] close is a four-way exchange: FIN, ACK, FIN, ACK, with both sides able to half-close independently.", + 'A [[tcp|TCP]] packet with the FIN flag set, signalling "I\'m done sending data β€” but I\'ll keep listening." The graceful counterpart to RST. A clean [[tcp|TCP]] close is a four-way exchange: FIN, ACK, FIN, ACK, with both sides able to half-close independently.', wikiUrl: 'https://en.wikipedia.org/wiki/Transmission_Control_Protocol#Connection_termination', category: 'protocol-mechanics' }, @@ -1762,15 +1760,16 @@ export const concepts: Concept[] = [ id: 'sack', term: 'SACK (Selective Acknowledgment)', definition: - "A [[tcp|TCP]] option ([[rfc:2018|RFC 2018]], 1996) that lets the receiver tell the sender exactly which non-contiguous byte ranges have arrived β€” instead of the cumulative ACK only saying \"I have everything up to byte N.\" Lets the sender retransmit only what's missing, dramatically improving recovery on lossy paths. Universally supported.", - wikiUrl: 'https://en.wikipedia.org/wiki/Transmission_Control_Protocol#Selective_acknowledgments', + 'A [[tcp|TCP]] option ([[rfc:2018|RFC 2018]], 1996) that lets the receiver tell the sender exactly which non-contiguous byte ranges have arrived β€” instead of the cumulative ACK only saying "I have everything up to byte N." Lets the sender retransmit only what\'s missing, dramatically improving recovery on lossy paths. Universally supported.', + wikiUrl: + 'https://en.wikipedia.org/wiki/Transmission_Control_Protocol#Selective_acknowledgments', category: 'protocol-mechanics' }, { id: 'window-scale', term: 'Window Scale', definition: - "A [[tcp|TCP]] option ([[rfc:7323|RFC 7323]]) that lets the 16-bit receive window field represent values up to 2³⁰ bytes by left-shifting it during the handshake. Without window scale, a single [[tcp|TCP]] connection caps at 64 KB in flight β€” fine in 1981, far too little for a 10 Gbps Γ— 100 ms BDP. Negotiated only in the SYN handshake, never midstream.", + 'A [[tcp|TCP]] option ([[rfc:7323|RFC 7323]]) that lets the 16-bit receive window field represent values up to 2³⁰ bytes by left-shifting it during the handshake. Without window scale, a single [[tcp|TCP]] connection caps at 64 KB in flight β€” fine in 1981, far too little for a 10 Gbps Γ— 100 ms BDP. Negotiated only in the SYN handshake, never midstream.', wikiUrl: 'https://en.wikipedia.org/wiki/TCP_window_scale_option', category: 'protocol-mechanics' }, @@ -1778,7 +1777,7 @@ export const concepts: Concept[] = [ id: 'nagle', term: "Nagle's Algorithm", definition: - "A 1984 sender-side rule (RFC 896) that holds back small writes until either the previous data is ACKed or a full segment is ready, to avoid flooding the network with tiny packets. Saved early networks; today it interacts pathologically with delayed ACKs and is the reason TCP_NODELAY exists.", + 'A 1984 sender-side rule (RFC 896) that holds back small writes until either the previous data is ACKed or a full segment is ready, to avoid flooding the network with tiny packets. Saved early networks; today it interacts pathologically with delayed ACKs and is the reason TCP_NODELAY exists.', wikiUrl: 'https://en.wikipedia.org/wiki/Nagle%27s_algorithm', category: 'protocol-mechanics' }, @@ -1810,7 +1809,7 @@ export const concepts: Concept[] = [ id: 'pacing', term: 'Pacing', definition: - "Spreading outgoing packets evenly over time instead of sending them in a burst. BBR paces every send to exactly the estimated bottleneck bandwidth, which avoids triggering AQM drops and minimises queue buildup. Linux pacing is implemented in the FQ qdisc β€” BBR depends on it.", + 'Spreading outgoing packets evenly over time instead of sending them in a burst. BBR paces every send to exactly the estimated bottleneck bandwidth, which avoids triggering AQM drops and minimises queue buildup. Linux pacing is implemented in the FQ qdisc β€” BBR depends on it.', category: 'protocol-mechanics' }, { @@ -1826,7 +1825,7 @@ export const concepts: Concept[] = [ id: 'salt', term: 'Salt', definition: - "Random data mixed with a password before hashing so identical passwords produce different stored hashes β€” defeating precomputed rainbow tables. Modern password hashing (argon2, bcrypt, scrypt) salts internally. Distinct from a *nonce*, which prevents key reuse rather than precomputation.", + 'Random data mixed with a password before hashing so identical passwords produce different stored hashes β€” defeating precomputed rainbow tables. Modern password hashing (argon2, bcrypt, scrypt) salts internally. Distinct from a *nonce*, which prevents key reuse rather than precomputation.', wikiUrl: 'https://en.wikipedia.org/wiki/Salt_(cryptography)', category: 'security' }, @@ -1842,7 +1841,7 @@ export const concepts: Concept[] = [ id: 'iv', term: 'IV (Initialization Vector)', definition: - "A non-secret value that randomises the starting state of a block cipher mode so encrypting the same plaintext twice produces different ciphertext. CBC requires an unpredictable IV; GCM uses a 96-bit nonce as IV. Reusing an IV under the same key in GCM is catastrophic (it leaks the authentication key).", + 'A non-secret value that randomises the starting state of a block cipher mode so encrypting the same plaintext twice produces different ciphertext. CBC requires an unpredictable IV; GCM uses a 96-bit nonce as IV. Reusing an IV under the same key in GCM is catastrophic (it leaks the authentication key).', wikiUrl: 'https://en.wikipedia.org/wiki/Initialization_vector', category: 'security' }, @@ -1850,7 +1849,7 @@ export const concepts: Concept[] = [ id: 'ocsp-crl', term: 'OCSP / CRL (Certificate Revocation)', definition: - "Two mechanisms for telling clients a certificate has been revoked before its expiry. CRLs are large signed lists the client downloads periodically; OCSP (RFC 6960) is a per-certificate online query. Both are unreliable in practice β€” clients soft-fail when the responder is unreachable β€” which is why short certificate lifetimes are replacing revocation as the primary defence.", + 'Two mechanisms for telling clients a certificate has been revoked before its expiry. CRLs are large signed lists the client downloads periodically; OCSP (RFC 6960) is a per-certificate online query. Both are unreliable in practice β€” clients soft-fail when the responder is unreachable β€” which is why short certificate lifetimes are replacing revocation as the primary defence.', wikiUrl: 'https://en.wikipedia.org/wiki/Online_Certificate_Status_Protocol', category: 'security' }, @@ -1882,15 +1881,16 @@ export const concepts: Concept[] = [ id: 'rov', term: 'ROV (Route Origin Validation)', definition: - "The runtime check a router performs against RPKI: for each [[bgp|BGP]] UPDATE, verify that the originating AS is authorised to announce the prefix. Result is *Valid*, *Invalid*, or *NotFound*. Most large transit providers drop *Invalid*. Pairs with RPKI as the deployment mechanism that stopped the YouTube-class hijack.", - wikiUrl: 'https://en.wikipedia.org/wiki/Resource_Public_Key_Infrastructure#Route_Origin_Validation', + 'The runtime check a router performs against RPKI: for each [[bgp|BGP]] UPDATE, verify that the originating AS is authorised to announce the prefix. Result is *Valid*, *Invalid*, or *NotFound*. Most large transit providers drop *Invalid*. Pairs with RPKI as the deployment mechanism that stopped the YouTube-class hijack.', + wikiUrl: + 'https://en.wikipedia.org/wiki/Resource_Public_Key_Infrastructure#Route_Origin_Validation', category: 'security' }, { id: 'aspa', term: 'ASPA (Autonomous System Provider Authorization)', definition: - "An emerging RPKI extension (draft-ietf-sidrops-aspa-verification, expected to publish 2026) where each AS publishes a signed list of its upstream providers. Routers can then detect path hijacks and route leaks by checking that each AS_PATH segment matches the customer-provider hierarchy. The pragmatic alternative to BGPsec.", + 'An emerging RPKI extension (draft-ietf-sidrops-aspa-verification, expected to publish 2026) where each AS publishes a signed list of its upstream providers. Routers can then detect path hijacks and route leaks by checking that each AS_PATH segment matches the customer-provider hierarchy. The pragmatic alternative to BGPsec.', wikiUrl: 'https://datatracker.ietf.org/doc/draft-ietf-sidrops-aspa-verification/', category: 'security' }, @@ -1924,7 +1924,7 @@ export const concepts: Concept[] = [ id: 'cookie', term: 'Cookie', definition: - "A small key-value pair the server stores on the client via Set-Cookie and the client returns on every subsequent request to the same origin. Modern attributes: Secure (HTTPS only), HttpOnly (not visible to JavaScript), SameSite (Strict/Lax/None β€” controls cross-site sending), Domain, Path, Max-Age. Cookies underpin sessions, auth, tracking, and most XSS/CSRF concerns.", + 'A small key-value pair the server stores on the client via Set-Cookie and the client returns on every subsequent request to the same origin. Modern attributes: Secure (HTTPS only), HttpOnly (not visible to JavaScript), SameSite (Strict/Lax/None β€” controls cross-site sending), Domain, Path, Max-Age. Cookies underpin sessions, auth, tracking, and most XSS/CSRF concerns.', wikiUrl: 'https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies', category: 'web' }, @@ -1932,7 +1932,7 @@ export const concepts: Concept[] = [ id: 'hsts', term: 'HSTS (HTTP Strict Transport Security)', definition: - "A response header (RFC 6797) that tells the browser \"only ever connect to this domain over HTTPS, for the next N seconds.\" After the first visit, plaintext HTTP requests are upgraded automatically β€” defeating SSL-stripping attacks. Browsers also ship a preload list (hstspreload.org) so the very first visit is protected too.", + 'A response header (RFC 6797) that tells the browser "only ever connect to this domain over HTTPS, for the next N seconds." After the first visit, plaintext HTTP requests are upgraded automatically β€” defeating SSL-stripping attacks. Browsers also ship a preload list (hstspreload.org) so the very first visit is protected too.', wikiUrl: 'https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security', category: 'web' }, @@ -1956,7 +1956,7 @@ export const concepts: Concept[] = [ id: 'webtransport', term: 'WebTransport', definition: - "A modern client-server transport API for browsers (W3C Working Draft, IETF draft-ietf-webtrans-http3) running over [[http3|HTTP/3]]. Provides multiplexed reliable streams plus unreliable datagrams β€” what [[websockets|WebSocket]] would look like if redesigned in 2024. Targeted for completion late 2026 or early 2027.", + 'A modern client-server transport API for browsers (W3C Working Draft, IETF draft-ietf-webtrans-http3) running over [[http3|HTTP/3]]. Provides multiplexed reliable streams plus unreliable datagrams β€” what [[websockets|WebSocket]] would look like if redesigned in 2024. Targeted for completion late 2026 or early 2027.', wikiUrl: 'https://developer.mozilla.org/en-US/docs/Web/API/WebTransport_API', category: 'web' }, @@ -1964,7 +1964,7 @@ export const concepts: Concept[] = [ id: 'masque', term: 'MASQUE', definition: - "An IETF working group standardising proxy protocols on top of [[http3|HTTP/3]] β€” CONNECT-[[ip|IP]] (tunnel any L3 traffic), CONNECT-[[udp|UDP]] (proxy [[udp|UDP]], used by [[http3|HTTP/3]]-over-[[http3|HTTP/3]]), CONNECT-[[ethernet|Ethernet]]. The technology behind iCloud Private Relay and Cloudflare WARP: arbitrary [[ip|IP]] traffic tunnelled inside what looks like normal HTTPS.", + 'An IETF working group standardising proxy protocols on top of [[http3|HTTP/3]] β€” CONNECT-[[ip|IP]] (tunnel any L3 traffic), CONNECT-[[udp|UDP]] (proxy [[udp|UDP]], used by [[http3|HTTP/3]]-over-[[http3|HTTP/3]]), CONNECT-[[ethernet|Ethernet]]. The technology behind iCloud Private Relay and Cloudflare WARP: arbitrary [[ip|IP]] traffic tunnelled inside what looks like normal HTTPS.', wikiUrl: 'https://datatracker.ietf.org/wg/masque/about/', category: 'web' }, @@ -1989,7 +1989,7 @@ export const concepts: Concept[] = [ id: 'last-will', term: 'Last Will (MQTT)', definition: - "A message a client tells the [[mqtt|MQTT]] broker to publish on its behalf if the client disconnects ungracefully. Lets every other subscriber learn immediately when a sensor goes offline β€” without polling β€” even though the failed sensor cannot send anything itself.", + 'A message a client tells the [[mqtt|MQTT]] broker to publish on its behalf if the client disconnects ungracefully. Lets every other subscriber learn immediately when a sensor goes offline β€” without polling β€” even though the failed sensor cannot send anything itself.', wikiUrl: 'https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html', category: 'messaging' }, @@ -1997,7 +1997,7 @@ export const concepts: Concept[] = [ id: 'retained-message', term: 'Retained Message (MQTT)', definition: - "A message the [[mqtt|MQTT]] broker holds onto for a topic and immediately delivers to any new subscriber. Lets a late-joining subscriber learn the current state of the world (e.g., the last reading from a sensor) without waiting for the next publish.", + 'A message the [[mqtt|MQTT]] broker holds onto for a topic and immediately delivers to any new subscriber. Lets a late-joining subscriber learn the current state of the world (e.g., the last reading from a sensor) without waiting for the next publish.', wikiUrl: 'https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html', category: 'messaging' }, @@ -2005,7 +2005,7 @@ export const concepts: Concept[] = [ id: 'log-compaction', term: 'Log Compaction (Kafka)', definition: - "A [[kafka|Kafka]] retention policy that, instead of deleting old records by age, keeps the most recent value for each key. Lets a topic act as an event log that doubles as a snapshot β€” a new consumer can read from offset 0 and end up with the current state of every key, just slowly.", + 'A [[kafka|Kafka]] retention policy that, instead of deleting old records by age, keeps the most recent value for each key. Lets a topic act as an event log that doubles as a snapshot β€” a new consumer can read from offset 0 and end up with the current state of every key, just slowly.', wikiUrl: 'https://kafka.apache.org/documentation/#compaction', category: 'messaging' }, @@ -2039,7 +2039,7 @@ export const concepts: Concept[] = [ id: 'service-discovery', term: 'Service Discovery', definition: - "The mechanism by which a service finds the network address of another service it depends on, when those addresses change frequently. Implementations include [[dns|DNS]] (with short TTLs), Consul/etcd (key-value lookup), Kubernetes Services (a stable [[dns|DNS]] name in front of changing pod IPs), and the service mesh (the sidecar handles it).", + 'The mechanism by which a service finds the network address of another service it depends on, when those addresses change frequently. Implementations include [[dns|DNS]] (with short TTLs), Consul/etcd (key-value lookup), Kubernetes Services (a stable [[dns|DNS]] name in front of changing pod IPs), and the service mesh (the sidecar handles it).', wikiUrl: 'https://en.wikipedia.org/wiki/Service_discovery', category: 'infrastructure' }, @@ -2047,8 +2047,9 @@ export const concepts: Concept[] = [ id: 'circuit-breaker', term: 'Circuit Breaker', definition: - "A resilience pattern where calls to a failing dependency are short-circuited (fail-fast with a fallback) instead of waiting for timeouts. Three states: *closed* (calls flow), *open* (calls fail immediately), *half-open* (a few probe calls test recovery). Prevents one slow dependency from saturating thread pools and cascading the failure.", - analogy: 'Like the breaker in your house β€” it trips when something downstream is in trouble, protecting the rest of the circuit until you fix it.', + 'A resilience pattern where calls to a failing dependency are short-circuited (fail-fast with a fallback) instead of waiting for timeouts. Three states: *closed* (calls flow), *open* (calls fail immediately), *half-open* (a few probe calls test recovery). Prevents one slow dependency from saturating thread pools and cascading the failure.', + analogy: + 'Like the breaker in your house β€” it trips when something downstream is in trouble, protecting the rest of the circuit until you fix it.', wikiUrl: 'https://martinfowler.com/bliki/CircuitBreaker.html', category: 'infrastructure' }, @@ -2056,7 +2057,7 @@ export const concepts: Concept[] = [ id: 'exponential-backoff', term: 'Exponential Backoff', definition: - "A retry strategy where the wait between attempts doubles each time, ideally with random jitter. After a transient failure, attempt 1 waits 100 ms, attempt 2 waits 200 ms, then 400 ms, 800 ms, etc. Without jitter, many clients all retry at the same instant after a shared outage and create a thundering herd.", + 'A retry strategy where the wait between attempts doubles each time, ideally with random jitter. After a transient failure, attempt 1 waits 100 ms, attempt 2 waits 200 ms, then 400 ms, 800 ms, etc. Without jitter, many clients all retry at the same instant after a shared outage and create a thundering herd.', wikiUrl: 'https://en.wikipedia.org/wiki/Exponential_backoff', category: 'infrastructure' }, @@ -2064,7 +2065,7 @@ export const concepts: Concept[] = [ id: 'rate-limiting', term: 'Rate Limiting', definition: - "A server-side mechanism that caps how many requests a client may make in a time window β€” by [[ip|IP]], API key, user, or tenant. Token bucket and leaky bucket are the standard algorithms. The HTTP response is 429 Too Many Requests, ideally with a Retry-After header naming when to try again.", + 'A server-side mechanism that caps how many requests a client may make in a time window β€” by [[ip|IP]], API key, user, or tenant. Token bucket and leaky bucket are the standard algorithms. The HTTP response is 429 Too Many Requests, ideally with a Retry-After header naming when to try again.', wikiUrl: 'https://en.wikipedia.org/wiki/Rate_limiting', category: 'infrastructure' }, @@ -2072,7 +2073,7 @@ export const concepts: Concept[] = [ id: 'slo-sli-sla', term: 'SLO / SLI / SLA', definition: - "Three nested concepts from Google\'s SRE practice. An *SLI* (Service Level Indicator) is a measurement (e.g., 99th-percentile latency). An *SLO* (Objective) is the target you set for it (\"99.9% of requests under 200 ms over 30 days\"). An *SLA* (Agreement) is the externally-promised version with consequences if missed. The gap between an SLO and an SLA is your error budget.", + 'Three nested concepts from Google\'s SRE practice. An *SLI* (Service Level Indicator) is a measurement (e.g., 99th-percentile latency). An *SLO* (Objective) is the target you set for it ("99.9% of requests under 200 ms over 30 days"). An *SLA* (Agreement) is the externally-promised version with consequences if missed. The gap between an SLO and an SLA is your error budget.', wikiUrl: 'https://sre.google/sre-book/service-level-objectives/', category: 'infrastructure' }, @@ -2080,7 +2081,7 @@ export const concepts: Concept[] = [ id: 'tail-latency', term: 'Tail Latency (p99, p999)', definition: - "The high-percentile latencies that dominate user experience but disappear in averages. p99 is \"99% of requests are at least this fast\" β€” and at internet scale every user hits p99+ multiple times per session. Jeff Dean and Luiz Barroso\'s 2013 paper \"The Tail at Scale\" is the canonical text.", + 'The high-percentile latencies that dominate user experience but disappear in averages. p99 is "99% of requests are at least this fast" β€” and at internet scale every user hits p99+ multiple times per session. Jeff Dean and Luiz Barroso\'s 2013 paper "The Tail at Scale" is the canonical text.', wikiUrl: 'https://research.google/pubs/the-tail-at-scale/', category: 'infrastructure' }, @@ -2088,7 +2089,7 @@ export const concepts: Concept[] = [ id: 'trace-span', term: 'Trace / Span', definition: - "The distributed-tracing data model. A *trace* represents one request\'s end-to-end journey. Each unit of work along the way (an HTTP call, a database query, a queue publish) is a *span* with a start time, end time, and a parent span. Spans form a tree across services. OpenTelemetry is the standard wire format; Jaeger, Tempo, and Zipkin are common UIs.", + "The distributed-tracing data model. A *trace* represents one request's end-to-end journey. Each unit of work along the way (an HTTP call, a database query, a queue publish) is a *span* with a start time, end time, and a parent span. Spans form a tree across services. OpenTelemetry is the standard wire format; Jaeger, Tempo, and Zipkin are common UIs.", wikiUrl: 'https://opentelemetry.io/docs/concepts/signals/traces/', category: 'infrastructure' }, @@ -2096,7 +2097,7 @@ export const concepts: Concept[] = [ id: 'availability-zone', term: 'Region / Availability Zone', definition: - "Cloud-provider terminology for failure domains. A *region* is a geographic area (us-east-1, eu-west-2) with its own user-facing endpoints. An *availability zone* is one or more datacenters within a region with independent power, cooling, and networking β€” designed so a single AZ failure does not take down the others. \"Multi-AZ\" is the minimum production resilience bar.", + 'Cloud-provider terminology for failure domains. A *region* is a geographic area (us-east-1, eu-west-2) with its own user-facing endpoints. An *availability zone* is one or more datacenters within a region with independent power, cooling, and networking β€” designed so a single AZ failure does not take down the others. "Multi-AZ" is the minimum production resilience bar.', wikiUrl: 'https://en.wikipedia.org/wiki/Availability_zone', category: 'infrastructure' }, @@ -2106,9 +2107,9 @@ export const concepts: Concept[] = [ id: 'ice', term: 'ICE (Interactive Connectivity Establishment)', definition: - 'The algorithm that orchestrates [[nat-traversal|NAT traversal]] for a single session. Each agent gathers every possible candidate address (host, server-reflexive via STUN, peer-reflexive, relayed via TURN), pairs them with the peer\'s candidates, runs connectivity checks across every pair, and nominates the highest-priority working one. RFC 8445.', + "The algorithm that orchestrates [[nat-traversal|NAT traversal]] for a single session. Each agent gathers every possible candidate address (host, server-reflexive via STUN, peer-reflexive, relayed via TURN), pairs them with the peer's candidates, runs connectivity checks across every pair, and nominates the highest-priority working one. RFC 8445.", analogy: - "Like a meet-up app that tries every route between two friends β€” bike, train, ride-share, walking β€” and picks the one that actually gets them together.", + 'Like a meet-up app that tries every route between two friends β€” bike, train, ride-share, walking β€” and picks the one that actually gets them together.', wikiUrl: 'https://en.wikipedia.org/wiki/Interactive_Connectivity_Establishment', category: 'networking-basics' }, @@ -2142,7 +2143,7 @@ export const concepts: Concept[] = [ id: 'gatt', term: 'GATT (Generic Attribute Profile)', definition: - "The [[bluetooth|BLE]] application protocol. A GATT *server* (peripheral) exposes a tree of services β†’ characteristics β†’ descriptors, each with a 16- or 128-bit UUID and a numeric handle. A GATT *client* (central) discovers them, reads/writes/subscribes-to-notifications. The protocol every BLE sensor and wearable speaks above L2CAP.", + 'The [[bluetooth|BLE]] application protocol. A GATT *server* (peripheral) exposes a tree of services β†’ characteristics β†’ descriptors, each with a 16- or 128-bit UUID and a numeric handle. A GATT *client* (central) discovers them, reads/writes/subscribes-to-notifications. The protocol every BLE sensor and wearable speaks above L2CAP.', analogy: 'Like a tiny REST API embedded in every Bluetooth sensor β€” services are endpoints, characteristics are the actual values.', wikiUrl: 'https://en.wikipedia.org/wiki/Bluetooth_Low_Energy#GATT', @@ -2152,7 +2153,7 @@ export const concepts: Concept[] = [ id: 'ble', term: 'BLE (Bluetooth Low Energy)', definition: - "The 2010 [[bluetooth|Bluetooth]] redesign for microamp power budgets. Different radio than Classic BR/EDR (40 Γ— 2 MHz channels, GFSK-only, hops once per connection event). Different stack: L2CAP β†’ ATT β†’ GATT. The protocol under AirPods, AirTags, hearing aids, and Matter device commissioning.", + 'The 2010 [[bluetooth|Bluetooth]] redesign for microamp power budgets. Different radio than Classic BR/EDR (40 Γ— 2 MHz channels, GFSK-only, hops once per connection event). Different stack: L2CAP β†’ ATT β†’ GATT. The protocol under AirPods, AirTags, hearing aids, and Matter device commissioning.', wikiUrl: 'https://en.wikipedia.org/wiki/Bluetooth_Low_Energy', category: 'protocol-mechanics' }, @@ -2160,7 +2161,7 @@ export const concepts: Concept[] = [ id: 'l2cap', term: 'L2CAP (Logical Link Control and Adaptation Protocol)', definition: - "The [[bluetooth|Bluetooth]] transport layer above the Link Layer. Provides Channel IDs that demultiplex sub-protocols: CID 0x0004 is ATT (GATT data), CID 0x0005 is LE signalling, CID 0x0006 is the Security Manager Protocol (pairing).", + 'The [[bluetooth|Bluetooth]] transport layer above the Link Layer. Provides Channel IDs that demultiplex sub-protocols: CID 0x0004 is ATT (GATT data), CID 0x0005 is LE signalling, CID 0x0006 is the Security Manager Protocol (pairing).', wikiUrl: 'https://en.wikipedia.org/wiki/Bluetooth#L2CAP', category: 'protocol-mechanics' }, @@ -2178,7 +2179,7 @@ export const concepts: Concept[] = [ id: 'lsa', term: 'LSA (Link State Advertisement)', definition: - "The unit of routing information in [[ospf|OSPF]] and IS-IS. Each router floods LSAs describing its own links β€” type, cost, neighbours β€” and every router in the area accumulates them into an identical Link State Database (LSDB). Dijkstra runs on that database to compute shortest paths.", + 'The unit of routing information in [[ospf|OSPF]] and IS-IS. Each router floods LSAs describing its own links β€” type, cost, neighbours β€” and every router in the area accumulates them into an identical Link State Database (LSDB). Dijkstra runs on that database to compute shortest paths.', wikiUrl: 'https://en.wikipedia.org/wiki/Link-state_advertisement', category: 'protocol-mechanics' }, @@ -2203,7 +2204,7 @@ export const concepts: Concept[] = [ id: 'security-association', term: 'SA (Security Association)', definition: - "A one-directional [[ipsec|IPsec]] tunnel, identified by a 32-bit Security Parameters Index (SPI). It carries the cipher, key, sequence-number counter, and anti-replay window for traffic in one direction. A typical site-to-site VPN has two SAs (one each way) per Traffic Selector pair.", + 'A one-directional [[ipsec|IPsec]] tunnel, identified by a 32-bit Security Parameters Index (SPI). It carries the cipher, key, sequence-number counter, and anti-replay window for traffic in one direction. A typical site-to-site VPN has two SAs (one each way) per Traffic Selector pair.', wikiUrl: 'https://en.wikipedia.org/wiki/Security_association', category: 'security' }, @@ -2211,7 +2212,7 @@ export const concepts: Concept[] = [ id: 'esp', term: 'ESP (Encapsulating Security Payload)', definition: - "The [[ipsec|IPsec]] data-plane protocol that encrypts and authenticates [[ip|IP]] payloads with an AEAD cipher like AES-GCM. 8-byte header (SPI + 32-bit sequence number), 8-byte AEAD nonce, encrypted payload, 16-byte authentication tag. The part of IPsec that everyone deploys. RFC 4303.", + 'The [[ipsec|IPsec]] data-plane protocol that encrypts and authenticates [[ip|IP]] payloads with an AEAD cipher like AES-GCM. 8-byte header (SPI + 32-bit sequence number), 8-byte AEAD nonce, encrypted payload, 16-byte authentication tag. The part of IPsec that everyone deploys. RFC 4303.', wikiUrl: 'https://en.wikipedia.org/wiki/IPsec#Encapsulating_Security_Payload', category: 'security' }, @@ -2219,7 +2220,7 @@ export const concepts: Concept[] = [ id: 'ah-authentication-header', term: 'AH (Authentication Header)', definition: - "The [[ipsec|IPsec]] integrity-only protocol. Authenticates the entire [[ip|IP]] header (minus mutable fields) and payload but encrypts nothing. Almost no production deployment uses AH alone in 2026 β€” ESP with AEAD does both jobs in one pass. RFC 4302.", + 'The [[ipsec|IPsec]] integrity-only protocol. Authenticates the entire [[ip|IP]] header (minus mutable fields) and payload but encrypts nothing. Almost no production deployment uses AH alone in 2026 β€” ESP with AEAD does both jobs in one pass. RFC 4302.', wikiUrl: 'https://en.wikipedia.org/wiki/IPsec#Authentication_Header', category: 'security' }, @@ -2227,7 +2228,7 @@ export const concepts: Concept[] = [ id: 'ike', term: 'IKE / IKEv2 (Internet Key Exchange)', definition: - "The [[ipsec|IPsec]] control plane β€” negotiates the cipher suite, exchanges Diffie-Hellman / ECDH / ML-KEM public keys, authenticates the peers (certificate, PSK, or EAP), and establishes the Security Associations the data plane uses. IKEv2 (RFC 7296, STD 79) is the modern Internet Standard.", + 'The [[ipsec|IPsec]] control plane β€” negotiates the cipher suite, exchanges Diffie-Hellman / ECDH / ML-KEM public keys, authenticates the peers (certificate, PSK, or EAP), and establishes the Security Associations the data plane uses. IKEv2 (RFC 7296, STD 79) is the modern Internet Standard.', wikiUrl: 'https://en.wikipedia.org/wiki/Internet_Key_Exchange', category: 'security' }, @@ -2235,14 +2236,14 @@ export const concepts: Concept[] = [ id: 'anti-replay', term: 'Anti-replay window', definition: - "A sliding bitmap of recently-seen sequence numbers maintained by an [[ipsec|ESP]] (or similar) receiver. Packets older than the window or duplicates within it are dropped. RFC 4303 Β§3.4.3 default is **32 entries** β€” a well-documented foot-gun on 10 Gbps+ links where out-of-order delivery routinely overflows it; production gateways tune to 1024+.", + 'A sliding bitmap of recently-seen sequence numbers maintained by an [[ipsec|ESP]] (or similar) receiver. Packets older than the window or duplicates within it are dropped. RFC 4303 Β§3.4.3 default is **32 entries** β€” a well-documented foot-gun on 10 Gbps+ links where out-of-order delivery routinely overflows it; production gateways tune to 1024+.', category: 'security' }, { id: 'pfs', term: 'PFS (Perfect Forward Secrecy)', definition: - "A property of a key-exchange protocol where compromising one session\'s long-term key does **not** compromise past sessions. Achieved by deriving each session key from an ephemeral Diffie-Hellman exchange. [[tls|TLS]] 1.3 enforces it; [[ipsec|IKEv2]] gets it via fresh DH/KEM in CREATE_CHILD_SA rekeys.", + "A property of a key-exchange protocol where compromising one session's long-term key does **not** compromise past sessions. Achieved by deriving each session key from an ephemeral Diffie-Hellman exchange. [[tls|TLS]] 1.3 enforces it; [[ipsec|IKEv2]] gets it via fresh DH/KEM in CREATE_CHILD_SA rekeys.", wikiUrl: 'https://en.wikipedia.org/wiki/Forward_secrecy', category: 'security' }, @@ -2276,7 +2277,7 @@ export const concepts: Concept[] = [ id: 'ndef', term: 'NDEF (NFC Data Exchange Format)', definition: - "The NFC Forum binary record container that lives in tags and rides over LLCP/SNEP. A 1-byte header (MB/ME/CF/SR/IL + 3-bit TNF) + variable type/id/payload-length fields + payload. The TNF picks the namespace: 1=Well-Known (URI, Text, Smart Poster), 2=MIME, 3=Absolute URI, 4=External. A URI record uses a single-byte prefix shorthand (0x03 = `https://`). **Adopted as an IEC standard in March 2026.**", + 'The NFC Forum binary record container that lives in tags and rides over LLCP/SNEP. A 1-byte header (MB/ME/CF/SR/IL + 3-bit TNF) + variable type/id/payload-length fields + payload. The TNF picks the namespace: 1=Well-Known (URI, Text, Smart Poster), 2=MIME, 3=Absolute URI, 4=External. A URI record uses a single-byte prefix shorthand (0x03 = `https://`). **Adopted as an IEC standard in March 2026.**', category: 'protocol-mechanics' }, { @@ -2290,7 +2291,7 @@ export const concepts: Concept[] = [ id: 'aid', term: 'AID (Application Identifier)', definition: - "A 5–16 byte identifier per ISO 7816-5 that selects which on-card application to talk to β€” e.g. `A0000000041010` for Mastercard, `A0000000031010` for Visa, `A0000002471001` for ICAO eMRTDs. {{emv-cryptogram|EMV}} contactless uses a two-stage selection: first SELECT *PPSE* (`2PAY.SYS.DDF01`) to enumerate which AIDs the card supports, then SELECT the chosen AID.", + 'A 5–16 byte identifier per ISO 7816-5 that selects which on-card application to talk to β€” e.g. `A0000000041010` for Mastercard, `A0000000031010` for Visa, `A0000002471001` for ICAO eMRTDs. {{emv-cryptogram|EMV}} contactless uses a two-stage selection: first SELECT *PPSE* (`2PAY.SYS.DDF01`) to enumerate which AIDs the card supports, then SELECT the chosen AID.', category: 'protocol-mechanics' }, { @@ -2340,7 +2341,7 @@ export const concepts: Concept[] = [ id: 'ieee-802-15-4', term: 'IEEE 802.15.4', definition: - "The PHY/MAC standard that underlies [[zigbee|Zigbee]], **Thread**, **WirelessHART**, **Wi-SUN**, and (in its 802.15.4z amendment) [[uwb|UWB]]. Bands: 2.4 GHz O-QPSK at 250 kbit/s (16 channels), 868 MHz BPSK at 20 kbit/s (Europe), 902–928 MHz BPSK at 40 kbit/s (North America). 127-byte PHY payload limit. Two device classes: FFD (Full-Function Device, can route) and RFD (Reduced-Function Device, sleepy end-device).", + 'The PHY/MAC standard that underlies [[zigbee|Zigbee]], **Thread**, **WirelessHART**, **Wi-SUN**, and (in its 802.15.4z amendment) [[uwb|UWB]]. Bands: 2.4 GHz O-QPSK at 250 kbit/s (16 channels), 868 MHz BPSK at 20 kbit/s (Europe), 902–928 MHz BPSK at 40 kbit/s (North America). 127-byte PHY payload limit. Two device classes: FFD (Full-Function Device, can route) and RFD (Reduced-Function Device, sleepy end-device).', category: 'networking-basics' }, { @@ -2354,7 +2355,7 @@ export const concepts: Concept[] = [ id: 'trust-center', term: 'Trust Center', definition: - "The single [[zigbee|Zigbee]] device (almost always the Coordinator) that holds and distributes the **network key** to all joined devices, governs which devices may join, and rekeys the network. New devices authenticate to the TC at commissioning time using a **pre-configured link key** (the universally-known default *ZigBeeAlliance09*, an **install code** derived secret, or β€” in R23 β€” a SPEKE-over-Curve25519 dynamic link key). The TC is the single trust root of a Zigbee mesh.", + 'The single [[zigbee|Zigbee]] device (almost always the Coordinator) that holds and distributes the **network key** to all joined devices, governs which devices may join, and rekeys the network. New devices authenticate to the TC at commissioning time using a **pre-configured link key** (the universally-known default *ZigBeeAlliance09*, an **install code** derived secret, or β€” in R23 β€” a SPEKE-over-Curve25519 dynamic link key). The TC is the single trust root of a Zigbee mesh.', category: 'security' }, { @@ -2375,7 +2376,7 @@ export const concepts: Concept[] = [ id: 'sts', term: 'STS (Scrambled Timestamp Sequence)', definition: - "The cryptographic primitive that makes IEEE 802.15.4z [[uwb|UWB]] ranging secure against distance-decrease attacks. A 32–2048-chip pulse sequence whose positions are generated by **AES-128 in Counter mode** keyed by a per-session STS_KEY and a per-frame nonce β€” a *distance commitment*. An attacker without the key sees noise; they cannot predict the next chip and cannot reliably early-replay. Receiver generates the expected sequence locally and cross-correlates with a sharp autocorrelation peak. Pre-STS UWB (802.15.4a, 2007) was vulnerable; even STS has been attacked (Ghost Peak ~4% success at USENIX Sec 2022), motivating the 802.15.4ab redesign.", + 'The cryptographic primitive that makes IEEE 802.15.4z [[uwb|UWB]] ranging secure against distance-decrease attacks. A 32–2048-chip pulse sequence whose positions are generated by **AES-128 in Counter mode** keyed by a per-session STS_KEY and a per-frame nonce β€” a *distance commitment*. An attacker without the key sees noise; they cannot predict the next chip and cannot reliably early-replay. Receiver generates the expected sequence locally and cross-correlates with a sharp autocorrelation peak. Pre-STS UWB (802.15.4a, 2007) was vulnerable; even STS has been attacked (Ghost Peak ~4% success at USENIX Sec 2022), motivating the 802.15.4ab redesign.', category: 'security' }, { @@ -2389,14 +2390,14 @@ export const concepts: Concept[] = [ id: 'tof-ranging', term: 'Time-of-Flight (ToF) ranging', definition: - "Measuring distance by timing how long a radio pulse takes to traverse the air and multiplying by *c* β‰ˆ 0.299792458 m/ns. A 1 ns timing error = 30 cm of range error. [[uwb|UWB]] chips routinely timestamp pulse arrival to 15–60 ps, yielding cm-class precision β€” and crucially, ToF cannot be *shortened* by a relay (the speed of light is the hard upper bound), so it defeats the BLE-RSSI relay attack class that broke Tesla Model 3 phone-as-a-key in 2022.", + 'Measuring distance by timing how long a radio pulse takes to traverse the air and multiplying by *c* β‰ˆ 0.299792458 m/ns. A 1 ns timing error = 30 cm of range error. [[uwb|UWB]] chips routinely timestamp pulse arrival to 15–60 ps, yielding cm-class precision β€” and crucially, ToF cannot be *shortened* by a relay (the speed of light is the hard upper bound), so it defeats the BLE-RSSI relay attack class that broke Tesla Model 3 phone-as-a-key in 2022.', category: 'protocol-mechanics' }, { id: 'fira', term: 'FiRa Consortium', definition: - "*Fine Ranging.* Founded **1 August 2019** by NXP, Samsung, HID Global, and Bosch to certify [[uwb|UWB]] interoperability on top of IEEE 802.15.4z. Defines the **FiRa MAC profile** for application-layer ranging configuration (session setup, ranging-round structure, multi-node ranging, result reporting via the UWB Command Interface). ~200 members. The UWB-side analogue of what the [[bluetooth|Bluetooth]] SIG does for BLE or the NFC Forum does for NFC.", + '*Fine Ranging.* Founded **1 August 2019** by NXP, Samsung, HID Global, and Bosch to certify [[uwb|UWB]] interoperability on top of IEEE 802.15.4z. Defines the **FiRa MAC profile** for application-layer ranging configuration (session setup, ranging-round structure, multi-node ranging, result reporting via the UWB Command Interface). ~200 members. The UWB-side analogue of what the [[bluetooth|Bluetooth]] SIG does for BLE or the NFC Forum does for NFC.', category: 'infrastructure' }, { @@ -2447,7 +2448,7 @@ export const concepts: Concept[] = [ id: 'spectrum', term: 'Spectrum', definition: - "The frequency range a wireless protocol is allowed to transmit on. Allocated globally by the **ITU-R**, regionally by **CEPT** (Europe) or **APT** (Asia-Pacific), and nationally by regulators like the {{fcc|FCC}} (US) or Ofcom (UK). Licensed spectrum (auctioned to carriers, predictable QoS) carries [[cellular|cellular]]; unlicensed bands ({{ism-band|ISM}}, U-NII) host [[wifi|Wi-Fi]], [[bluetooth|Bluetooth]], [[zigbee|Zigbee]], [[uwb|UWB]]. Spectrum is the most contested resource in wireless β€” every gigahertz freed (or reclaimed) is a multi-billion-dollar policy fight.", + 'The frequency range a wireless protocol is allowed to transmit on. Allocated globally by the **ITU-R**, regionally by **CEPT** (Europe) or **APT** (Asia-Pacific), and nationally by regulators like the {{fcc|FCC}} (US) or Ofcom (UK). Licensed spectrum (auctioned to carriers, predictable QoS) carries [[cellular|cellular]]; unlicensed bands ({{ism-band|ISM}}, U-NII) host [[wifi|Wi-Fi]], [[bluetooth|Bluetooth]], [[zigbee|Zigbee]], [[uwb|UWB]]. Spectrum is the most contested resource in wireless β€” every gigahertz freed (or reclaimed) is a multi-billion-dollar policy fight.', analogy: 'Real estate on an invisible map. Some plots are auctioned for billions to single carriers; some plots are public parks anyone may build on if they obey the noise ordinance.', wikiUrl: 'https://en.wikipedia.org/wiki/Radio_spectrum', @@ -2475,7 +2476,7 @@ export const concepts: Concept[] = [ id: 'multipath', term: 'Multipath', definition: - "A radio signal that arrives at a receiver via two or more paths (one direct, others reflected off walls/floors/cars) interferes with itself β€” the copies add constructively or destructively depending on their relative phase, producing rapid fading as the receiver or environment moves. The same physics that ruined 1990s analog cellular calls is the *foundation* of every modern wireless system: **MIMO** (multiple-input multiple-output) treats each reflected path as a separate spatial stream, and **OFDM** ({{ofdma|/OFDMA}}) spreads each symbol across hundreds of narrow subcarriers so only a handful are nulled by a deep fade. Wireless went from \"multipath is the enemy\" to \"multipath is the bandwidth\" in one generation.", + 'A radio signal that arrives at a receiver via two or more paths (one direct, others reflected off walls/floors/cars) interferes with itself β€” the copies add constructively or destructively depending on their relative phase, producing rapid fading as the receiver or environment moves. The same physics that ruined 1990s analog cellular calls is the *foundation* of every modern wireless system: **MIMO** (multiple-input multiple-output) treats each reflected path as a separate spatial stream, and **OFDM** ({{ofdma|/OFDMA}}) spreads each symbol across hundreds of narrow subcarriers so only a handful are nulled by a deep fade. Wireless went from "multipath is the enemy" to "multipath is the bandwidth" in one generation.', wikiUrl: 'https://en.wikipedia.org/wiki/Multipath_propagation', category: 'networking-basics' }, @@ -2492,7 +2493,7 @@ export const concepts: Concept[] = [ id: 'ofdma', term: 'OFDMA (Orthogonal Frequency-Division Multiple Access)', definition: - "The multi-user upgrade to OFDM. Where plain OFDM splits one transmission across many orthogonal subcarriers, OFDMA lets the {{access-point|AP}} assign **subsets of subcarriers** (called Resource Units) to *different* clients in the same symbol β€” like turning a single highway into multiple narrower lanes. Introduced to [[wifi|Wi-Fi]] in 802.11ax ([[wifi|Wi-Fi]] 6, 2020); the core multiple-access method of [[cellular|4G LTE]] and [[cellular|5G NR]] since 2008. The reason a Wi-Fi 6 {{access-point|AP}} can serve 30 phones in a coffee shop without each one paying the full per-transmission overhead the way Wi-Fi 5 did.", + 'The multi-user upgrade to OFDM. Where plain OFDM splits one transmission across many orthogonal subcarriers, OFDMA lets the {{access-point|AP}} assign **subsets of subcarriers** (called Resource Units) to *different* clients in the same symbol β€” like turning a single highway into multiple narrower lanes. Introduced to [[wifi|Wi-Fi]] in 802.11ax ([[wifi|Wi-Fi]] 6, 2020); the core multiple-access method of [[cellular|4G LTE]] and [[cellular|5G NR]] since 2008. The reason a Wi-Fi 6 {{access-point|AP}} can serve 30 phones in a coffee shop without each one paying the full per-transmission overhead the way Wi-Fi 5 did.', wikiUrl: 'https://en.wikipedia.org/wiki/Orthogonal_frequency-division_multiple_access', category: 'protocol-mechanics' }, @@ -2500,7 +2501,7 @@ export const concepts: Concept[] = [ id: 'mlo', term: 'MLO (Multi-Link Operation)', definition: - "The flagship feature of [[wifi|Wi-Fi]] 7 (802.11be, 2024). A single client connection spans 2.4 + 5 + 6 GHz radios simultaneously β€” frames can be sent on whichever band is least congested, and {{tail-latency|tail latency}} on a busy network drops sharply. The catch in shipping silicon is that most MLO is **eMLSR** (Enhanced Multi-Link Single Radio): one radio time-sliced across bands. True simultaneous transmit-receive (STR) across bands is rare. The win is *latency consistency*, not raw aggregate throughput.", + 'The flagship feature of [[wifi|Wi-Fi]] 7 (802.11be, 2024). A single client connection spans 2.4 + 5 + 6 GHz radios simultaneously β€” frames can be sent on whichever band is least congested, and {{tail-latency|tail latency}} on a busy network drops sharply. The catch in shipping silicon is that most MLO is **eMLSR** (Enhanced Multi-Link Single Radio): one radio time-sliced across bands. True simultaneous transmit-receive (STR) across bands is rare. The win is *latency consistency*, not raw aggregate throughput.', category: 'protocol-mechanics' }, { @@ -2544,7 +2545,7 @@ export const concepts: Concept[] = [ id: 'afc', term: 'AFC (Automated Frequency Coordination)', definition: - "A cloud service that arbitrates [[wifi|Wi-Fi]] use of the 6 GHz Standard-Power band against existing incumbent licensees (fixed microwave links, satellite services). A 6 GHz Wi-Fi {{access-point|AP}} queries an AFC operator with its location and antenna parameters; the AFC returns the channels and EIRP limits it may use without interfering with incumbents. The {{fcc|FCC}} approved seven AFC operators (Qualcomm, Federated Wireless, Sony, Comsearch, [[wifi|Wi-Fi]] Alliance Services, WBA, Broadcom) on 23 February 2024 β€” the regulatory machinery without which 6 GHz Standard Power would not exist.", + 'A cloud service that arbitrates [[wifi|Wi-Fi]] use of the 6 GHz Standard-Power band against existing incumbent licensees (fixed microwave links, satellite services). A 6 GHz Wi-Fi {{access-point|AP}} queries an AFC operator with its location and antenna parameters; the AFC returns the channels and EIRP limits it may use without interfering with incumbents. The {{fcc|FCC}} approved seven AFC operators (Qualcomm, Federated Wireless, Sony, Comsearch, [[wifi|Wi-Fi]] Alliance Services, WBA, Broadcom) on 23 February 2024 β€” the regulatory machinery without which 6 GHz Standard Power would not exist.', category: 'infrastructure' }, @@ -2561,14 +2562,14 @@ export const concepts: Concept[] = [ id: 'le-audio', term: 'LE Audio', definition: - "The 2020+ [[bluetooth|Bluetooth]] audio architecture, defined across Core 5.2+ and a stack of profiles (BAP, PBP, TMAP, HAP). Replaces Classic A2DP/HFP with **Isochronous Channels** β€” Connected Isochronous Streams (CIS) for {{unicast|unicast}} earbuds and hearing aids, Broadcast Isochronous Streams (BIS) for {{auracast|Auracast}} one-to-many. Mandatory {{codec|codec}} is {{lc3|LC3}}. Cuts audio power by roughly half versus A2DP and brings true stereo, multi-stream, and hearing-aid-grade reliability under one umbrella.", + 'The 2020+ [[bluetooth|Bluetooth]] audio architecture, defined across Core 5.2+ and a stack of profiles (BAP, PBP, TMAP, HAP). Replaces Classic A2DP/HFP with **Isochronous Channels** β€” Connected Isochronous Streams (CIS) for {{unicast|unicast}} earbuds and hearing aids, Broadcast Isochronous Streams (BIS) for {{auracast|Auracast}} one-to-many. Mandatory {{codec|codec}} is {{lc3|LC3}}. Cuts audio power by roughly half versus A2DP and brings true stereo, multi-stream, and hearing-aid-grade reliability under one umbrella.', category: 'protocol-mechanics' }, { id: 'lc3', term: 'LC3 (Low Complexity Communications Codec)', definition: - "Mandatory {{codec|codec}} of {{le-audio|LE Audio}}, standardised by the [[bluetooth|Bluetooth]] SIG in January 2020 (Ericsson + Fraunhofer IIS). Replaces 1990s SBC. Roughly 2Γ— more battery-efficient than SBC at equivalent quality, 8–48 kHz sample rates, 16–320 kbit/s. The codec underneath every modern earbud and hearing aid shipping {{le-audio|LE Audio}}.", + 'Mandatory {{codec|codec}} of {{le-audio|LE Audio}}, standardised by the [[bluetooth|Bluetooth]] SIG in January 2020 (Ericsson + Fraunhofer IIS). Replaces 1990s SBC. Roughly 2Γ— more battery-efficient than SBC at equivalent quality, 8–48 kHz sample rates, 16–320 kbit/s. The codec underneath every modern earbud and hearing aid shipping {{le-audio|LE Audio}}.', category: 'protocol-mechanics' }, { @@ -2582,21 +2583,21 @@ export const concepts: Concept[] = [ id: 'channel-sounding', term: 'Channel Sounding', definition: - "Centimetre-class distance measurement added to [[bluetooth|Bluetooth]] 6.0 (adopted 3 September 2024). Two devices in a normal LL connection schedule Channel Sounding events on a new LE 2M 2BT PHY and measure both signal **phase** across many frequencies (Phase-Based Ranging) and **round-trip time** of timestamped packets; the combination yields cm-accurate distance up to ~150 m. The protocol-level reply to [[uwb|UWB]] for digital car keys, anti-stalking tags, and proximity-aware locks.", + 'Centimetre-class distance measurement added to [[bluetooth|Bluetooth]] 6.0 (adopted 3 September 2024). Two devices in a normal LL connection schedule Channel Sounding events on a new LE 2M 2BT PHY and measure both signal **phase** across many frequencies (Phase-Based Ranging) and **round-trip time** of timestamped packets; the combination yields cm-accurate distance up to ~150 m. The protocol-level reply to [[uwb|UWB]] for digital car keys, anti-stalking tags, and proximity-aware locks.', category: 'protocol-mechanics' }, { id: 'rpa', term: 'RPA (Resolvable Private Address)', definition: - "A 48-bit Bluetooth LE address that *looks* random but is derivable from a long-lived Identity Resolving Key (IRK) the two paired devices share. Rotated every ~15 minutes by default. A bonded peer recomputes the expected RPA from the IRK and recognises its partner; a stranger sees only noise. The mechanism that prevents long-term tracking of {{ble|BLE}} devices by sniffers β€” important for AirTags, AirPods, fitness wearables, and any device a person carries on their body all day.", + 'A 48-bit Bluetooth LE address that *looks* random but is derivable from a long-lived Identity Resolving Key (IRK) the two paired devices share. Rotated every ~15 minutes by default. A bonded peer recomputes the expected RPA from the IRK and recognises its partner; a stranger sees only noise. The mechanism that prevents long-term tracking of {{ble|BLE}} devices by sniffers β€” important for AirTags, AirPods, fitness wearables, and any device a person carries on their body all day.', category: 'security' }, { id: 'knob-attack', term: 'KNOB / BIAS / BLUFFS', definition: - "Three [[bluetooth|Bluetooth]] BR/EDR session-security breaks by the same author (Daniele Antonioli) in five years. **KNOB** (CVE-2019-9506) downgrades the entropy of the negotiated session key to 1 byte β€” brute-forceable. **BIAS** (CVE-2020-10135) impersonates a previously-bonded peer by abusing role-switch in Legacy Secure Connections. **BLUFFS** (CVE-2023-24023) breaks forward secrecy by forcing reuse of a session-key derivation across reconnections. Every BR/EDR device shipped before mid-2024 is affected; the Core 5.4 / 6.0 patches add explicit minimum-entropy and key-diversification checks.", + 'Three [[bluetooth|Bluetooth]] BR/EDR session-security breaks by the same author (Daniele Antonioli) in five years. **KNOB** (CVE-2019-9506) downgrades the entropy of the negotiated session key to 1 byte β€” brute-forceable. **BIAS** (CVE-2020-10135) impersonates a previously-bonded peer by abusing role-switch in Legacy Secure Connections. **BLUFFS** (CVE-2023-24023) breaks forward secrecy by forcing reuse of a session-key derivation across reconnections. Every BR/EDR device shipped before mid-2024 is affected; the Core 5.4 / 6.0 patches add explicit minimum-entropy and key-diversification checks.', wikiUrl: 'https://en.wikipedia.org/wiki/KNOB_attack', category: 'security' }, @@ -2606,7 +2607,7 @@ export const concepts: Concept[] = [ id: '3gpp', term: '3GPP (3rd Generation Partnership Project)', definition: - "The umbrella standards body that owns the [[cellular|cellular]] family from GSM through 5G NR and (soon) 6G. Founded December 1998 as a partnership of regional SDOs (ETSI/Europe, ATIS/USA, TTA/Korea, ARIB+TTC/Japan, CCSA/China, TSDSI/India). Specifications are organised by *Release*: Release 8 (LTE, 2008), Release 15 (5G NR, 2018), Release 18 (5G-Advanced, frozen June 2024), Release 19/20 in flight. Every spec is free to download from 3gpp.org β€” the largest free technical library in telecommunications.", + 'The umbrella standards body that owns the [[cellular|cellular]] family from GSM through 5G NR and (soon) 6G. Founded December 1998 as a partnership of regional SDOs (ETSI/Europe, ATIS/USA, TTA/Korea, ARIB+TTC/Japan, CCSA/China, TSDSI/India). Specifications are organised by *Release*: Release 8 (LTE, 2008), Release 15 (5G NR, 2018), Release 18 (5G-Advanced, frozen June 2024), Release 19/20 in flight. Every spec is free to download from 3gpp.org β€” the largest free technical library in telecommunications.', wikiUrl: 'https://en.wikipedia.org/wiki/3GPP', category: 'infrastructure' }, @@ -2614,7 +2615,7 @@ export const concepts: Concept[] = [ id: 'gsma', term: 'GSMA (GSM Association)', definition: - "The trade association of mobile network operators β€” ~750 carriers plus ~400 ecosystem members. Distinct from {{3gpp|3GPP}}, which writes the technical specs; the GSMA owns the *commercial* layer: IR.21 roaming agreements, BA.51 RCS, FS.36 SS7/Diameter security, the eSIM Architecture, and Mobile World Congress every February in Barcelona. The body operators belong to; 3GPP is the body engineers contribute specs to.", + 'The trade association of mobile network operators β€” ~750 carriers plus ~400 ecosystem members. Distinct from {{3gpp|3GPP}}, which writes the technical specs; the GSMA owns the *commercial* layer: IR.21 roaming agreements, BA.51 RCS, FS.36 SS7/Diameter security, the eSIM Architecture, and Mobile World Congress every February in Barcelona. The body operators belong to; 3GPP is the body engineers contribute specs to.', wikiUrl: 'https://en.wikipedia.org/wiki/GSMA', category: 'infrastructure' }, @@ -2630,7 +2631,7 @@ export const concepts: Concept[] = [ id: '5g-nr', term: '5G NR (New Radio)', definition: - "{{3gpp|3GPP}} Release 15, frozen June 2018. The 5G air interface: scalable {{ofdma|OFDMA}} numerology (15/30/60/120/240 kHz subcarrier spacing) addressing sub-6 GHz (FR1) and {{mmwave|mmWave}} (FR2), service-based 5G Core, network slicing, ultra-reliable low-latency (URLLC), and mMTC for massive IoT. **5G Standalone** (no LTE anchor) deployments arrived 2020–2021; **5G-Advanced** is Release 18 (June 2024).", + '{{3gpp|3GPP}} Release 15, frozen June 2018. The 5G air interface: scalable {{ofdma|OFDMA}} numerology (15/30/60/120/240 kHz subcarrier spacing) addressing sub-6 GHz (FR1) and {{mmwave|mmWave}} (FR2), service-based 5G Core, network slicing, ultra-reliable low-latency (URLLC), and mMTC for massive IoT. **5G Standalone** (no LTE anchor) deployments arrived 2020–2021; **5G-Advanced** is Release 18 (June 2024).', wikiUrl: 'https://en.wikipedia.org/wiki/5G_NR', category: 'protocol-mechanics' }, @@ -2638,14 +2639,14 @@ export const concepts: Concept[] = [ id: 'mmwave', term: 'mmWave', definition: - "Millimetre-wave radio bands β€” typically 24–52 GHz for 5G NR FR2, plus 60 GHz for WiGig and 28/39 GHz for fixed wireless. Enormous bandwidth (hundreds of MHz of contiguous spectrum), gigabit speeds, line-of-sight only, ~20 dB attenuation through a wet leaf. Deployed mostly in stadiums, dense urban hotspots, and fixed-wireless backhaul rather than wide-area mobile.", + 'Millimetre-wave radio bands β€” typically 24–52 GHz for 5G NR FR2, plus 60 GHz for WiGig and 28/39 GHz for fixed wireless. Enormous bandwidth (hundreds of MHz of contiguous spectrum), gigabit speeds, line-of-sight only, ~20 dB attenuation through a wet leaf. Deployed mostly in stadiums, dense urban hotspots, and fixed-wireless backhaul rather than wide-area mobile.', category: 'networking-basics' }, { id: 'ran', term: 'RAN (Radio Access Network)', definition: - "The set of base stations and the protocol stack between them and the carrier core β€” the *radio side* of a [[cellular|cellular]] network. In 5G the base station is the **gNB** (gNodeB), in 4G it was the **eNB** (eNodeB). The RAN handles the PHY/MAC/RLC/PDCP/RRC stack on the air interface and tunnels user traffic into the core over **GTP-U** on the N3 interface. **Open RAN** is the disaggregated alternative where vendor-neutral hardware and software replace vertically-integrated boxes (Vodafone UK, Rakuten Symphony, DISH on AWS Wavelength).", + 'The set of base stations and the protocol stack between them and the carrier core β€” the *radio side* of a [[cellular|cellular]] network. In 5G the base station is the **gNB** (gNodeB), in 4G it was the **eNB** (eNodeB). The RAN handles the PHY/MAC/RLC/PDCP/RRC stack on the air interface and tunnels user traffic into the core over **GTP-U** on the N3 interface. **Open RAN** is the disaggregated alternative where vendor-neutral hardware and software replace vertically-integrated boxes (Vodafone UK, Rakuten Symphony, DISH on AWS Wavelength).', wikiUrl: 'https://en.wikipedia.org/wiki/Radio_access_network', category: 'infrastructure' }, @@ -2668,7 +2669,7 @@ export const concepts: Concept[] = [ id: 'volte', term: 'VoLTE / VoNR', definition: - "**Voice over LTE** and **Voice over New Radio** β€” packetised carrier voice over the LTE or 5G data bearer, signalled by {{ims|IMS}} [[sip|SIP]] and carried over [[rtp|RTP]] using the AMR-WB or EVS {{codec|codec}}. Replaces the legacy 2G/3G circuit-switched voice fallback. GSMA reports 310+ commercial VoLTE operators in 140+ countries and 45+ commercial VoNR networks by 2025. **Wi-Fi Calling** is the same IMS stack tunneled to the carrier over [[ipsec|IPsec]] from any IP network.", + '**Voice over LTE** and **Voice over New Radio** β€” packetised carrier voice over the LTE or 5G data bearer, signalled by {{ims|IMS}} [[sip|SIP]] and carried over [[rtp|RTP]] using the AMR-WB or EVS {{codec|codec}}. Replaces the legacy 2G/3G circuit-switched voice fallback. GSMA reports 310+ commercial VoLTE operators in 140+ countries and 45+ commercial VoNR networks by 2025. **Wi-Fi Calling** is the same IMS stack tunneled to the carrier over [[ipsec|IPsec]] from any IP network.', category: 'protocol-mechanics' }, { @@ -2704,7 +2705,7 @@ export const concepts: Concept[] = [ id: 'aaa', term: 'AAA (Authentication, Authorisation, Accounting)', definition: - "The three-question framework every access network asks: who are you, what may you do, what did you do? RADIUS (RFC 2865, 1997) was the original; {{diameter|Diameter}} replaced it for [[cellular|cellular]]; modern OIDC/[[oauth2|OAuth]] flows generalise it for web applications. The protocol-shaped hole every enterprise authentication system fills.", + 'The three-question framework every access network asks: who are you, what may you do, what did you do? RADIUS (RFC 2865, 1997) was the original; {{diameter|Diameter}} replaced it for [[cellular|cellular]]; modern OIDC/[[oauth2|OAuth]] flows generalise it for web applications. The protocol-shaped hole every enterprise authentication system fills.', category: 'security' }, { @@ -2721,7 +2722,7 @@ export const concepts: Concept[] = [ id: 'thread', term: 'Thread', definition: - "An [[ipv6|IPv6]]-native low-power mesh protocol on {{ieee-802-15-4|IEEE 802.15.4}} radios, governed by the Thread Group (Nest/Google, Apple, Samsung, ARM, Silicon Labs, NXP, +). Where [[zigbee|Zigbee]] grew its own application layer ({{zcl|ZCL}}), Thread carries native IPv6 over **6LoWPAN** {{header|header compression}} and **MLE** (Mesh Link Establishment) routing β€” so a Thread device gets an IPv6 address and is reachable like any other host. Thread 1.4 (December 2024) introduced **Thread Border Routers** as multi-vendor commodity hardware. The radio layer of {{matter|Matter}} that is not Wi-Fi.", + 'An [[ipv6|IPv6]]-native low-power mesh protocol on {{ieee-802-15-4|IEEE 802.15.4}} radios, governed by the Thread Group (Nest/Google, Apple, Samsung, ARM, Silicon Labs, NXP, +). Where [[zigbee|Zigbee]] grew its own application layer ({{zcl|ZCL}}), Thread carries native IPv6 over **6LoWPAN** {{header|header compression}} and **MLE** (Mesh Link Establishment) routing β€” so a Thread device gets an IPv6 address and is reachable like any other host. Thread 1.4 (December 2024) introduced **Thread Border Routers** as multi-vendor commodity hardware. The radio layer of {{matter|Matter}} that is not Wi-Fi.', wikiUrl: 'https://en.wikipedia.org/wiki/Thread_(network_protocol)', category: 'networking-basics' }, @@ -2743,7 +2744,7 @@ export const concepts: Concept[] = [ id: 'mdns', term: 'mDNS / DNS-SD', definition: - "Multicast DNS (RFC 6762) and DNS Service Discovery (RFC 6763). Lets a device on a local link discover services without any configured resolver β€” the device queries `_googlecast._tcp.local`, `_airplay._tcp.local`, `_matter._tcp.local`, etc., over multicast UDP/5353, and any host providing the service answers. Designed by [[pioneer:stuart-cheshire|Stuart Cheshire]] at Apple. Underneath Bonjour, AirPlay, Matter device discovery, and {{thread|Thread}} Border Router service advertisement.", + 'Multicast DNS (RFC 6762) and DNS Service Discovery (RFC 6763). Lets a device on a local link discover services without any configured resolver β€” the device queries `_googlecast._tcp.local`, `_airplay._tcp.local`, `_matter._tcp.local`, etc., over multicast UDP/5353, and any host providing the service answers. Designed by [[pioneer:stuart-cheshire|Stuart Cheshire]] at Apple. Underneath Bonjour, AirPlay, Matter device discovery, and {{thread|Thread}} Border Router service advertisement.', wikiUrl: 'https://en.wikipedia.org/wiki/Multicast_DNS', category: 'protocol-mechanics' }, @@ -2767,7 +2768,7 @@ export const concepts: Concept[] = [ id: 'direct-to-cell', term: 'Direct-to-Cell', definition: - "Satellite-to-standard-phone connectivity using ordinary [[cellular|cellular]] terrestrial bands (typically n25/n26) rather than handheld satellite-terminal hardware. T-Mobile + SpaceX Starlink launched commercial Direct-to-Cell in **January 2025** for SMS and emergency, with voice and data on a roadmap. AT&T's AST SpaceMobile and Apple's Globalstar Emergency SOS partnership follow similar patterns. Reshapes \"coverage\" as a concept: \"no signal\" no longer means *no signal*.", + 'Satellite-to-standard-phone connectivity using ordinary [[cellular|cellular]] terrestrial bands (typically n25/n26) rather than handheld satellite-terminal hardware. T-Mobile + SpaceX Starlink launched commercial Direct-to-Cell in **January 2025** for SMS and emergency, with voice and data on a roadmap. AT&T\'s AST SpaceMobile and Apple\'s Globalstar Emergency SOS partnership follow similar patterns. Reshapes "coverage" as a concept: "no signal" no longer means *no signal*.', category: 'infrastructure' }, { @@ -2781,7 +2782,7 @@ export const concepts: Concept[] = [ id: 'lpwan', term: 'LPWAN (Low-Power Wide-Area Network)', definition: - "The family of long-range, low-data-rate, multi-year-battery wireless protocols that sit between [[wifi|Wi-Fi]] and [[cellular|cellular]]. **LoRaWAN** (sub-GHz, ALOHA-style, 125M+ devices deployed by end-2025), **Sigfox** (slow-modulation 100 bit/s ultra-narrowband, France-originated), **NB-IoT** and **LTE-M** ([[cellular|cellular]]-licensed alternatives inside [[cellular|LTE]] spectrum). All trade throughput for kilometres of range and years of battery life.", + 'The family of long-range, low-data-rate, multi-year-battery wireless protocols that sit between [[wifi|Wi-Fi]] and [[cellular|cellular]]. **LoRaWAN** (sub-GHz, ALOHA-style, 125M+ devices deployed by end-2025), **Sigfox** (slow-modulation 100 bit/s ultra-narrowband, France-originated), **NB-IoT** and **LTE-M** ([[cellular|cellular]]-licensed alternatives inside [[cellular|LTE]] spectrum). All trade throughput for kilometres of range and years of battery life.', wikiUrl: 'https://en.wikipedia.org/wiki/LPWAN', category: 'networking-basics' }, @@ -2796,7 +2797,7 @@ export const concepts: Concept[] = [ id: 'wifi-sensing', term: 'Wi-Fi sensing (802.11bf)', definition: - "Using the Channel State Information (CSI) that [[wifi|Wi-Fi]] radios already compute for {{multipath|multipath}} equalisation to *detect* people, motion, and breathing β€” radio waves as occupancy sensors. Standardised in **IEEE 802.11bf-2025** (published 26 September 2025), covering 1–7.125 GHz and >45 GHz bands. Lets a home Wi-Fi mesh do presence detection without a camera or PIR sensor.", + 'Using the Channel State Information (CSI) that [[wifi|Wi-Fi]] radios already compute for {{multipath|multipath}} equalisation to *detect* people, motion, and breathing β€” radio waves as occupancy sensors. Standardised in **IEEE 802.11bf-2025** (published 26 September 2025), covering 1–7.125 GHz and >45 GHz bands. Lets a home Wi-Fi mesh do presence detection without a camera or PIR sensor.', category: 'protocol-mechanics' }, { @@ -2820,7 +2821,7 @@ export const concepts: Concept[] = [ id: 'cloudflare', term: 'Cloudflare', definition: - "Major CDN, DDoS-mitigation, and reverse-proxy operator founded 2009. Runs ~330 PoPs, serves ~20% of all websites by some measures, and authored or co-authored several internet standards ([[quic|QUIC]] adoption, {{ech|ECH}}, {{rpki|RPKI}} measurement at radar.cloudflare.com). Runs the **1.1.1.1** public DNS resolver. Their post-mortems are a major source of public outage learning.", + 'Major CDN, DDoS-mitigation, and reverse-proxy operator founded 2009. Runs ~330 PoPs, serves ~20% of all websites by some measures, and authored or co-authored several internet standards ([[quic|QUIC]] adoption, {{ech|ECH}}, {{rpki|RPKI}} measurement at radar.cloudflare.com). Runs the **1.1.1.1** public DNS resolver. Their post-mortems are a major source of public outage learning.', wikiUrl: 'https://en.wikipedia.org/wiki/Cloudflare', category: 'infrastructure' }, @@ -2828,7 +2829,7 @@ export const concepts: Concept[] = [ id: 'google', term: 'Google', definition: - "Search, YouTube, and Android operator that has driven a disproportionate share of post-2008 internet protocol design. Authored {{spdy|SPDY}} (became [[http2|HTTP/2]]), [[quic|QUIC]] (became [[http3|HTTP/3]]), {{bbr|BBR}}, [[webrtc|WebRTC]] adoption, the public **8.8.8.8** DNS resolver, and runs **Jupiter** β€” one of the largest internal datacenter fabrics on earth.", + 'Search, YouTube, and Android operator that has driven a disproportionate share of post-2008 internet protocol design. Authored {{spdy|SPDY}} (became [[http2|HTTP/2]]), [[quic|QUIC]] (became [[http3|HTTP/3]]), {{bbr|BBR}}, [[webrtc|WebRTC]] adoption, the public **8.8.8.8** DNS resolver, and runs **Jupiter** β€” one of the largest internal datacenter fabrics on earth.', wikiUrl: 'https://en.wikipedia.org/wiki/Google', category: 'infrastructure' }, @@ -2836,7 +2837,7 @@ export const concepts: Concept[] = [ id: 'apple', term: 'Apple', definition: - "Largest single force shaping client-side wireless and codec choices: [[hls|HLS]] (2009), {{airdrop|AirDrop}}, AirPlay, the **U1 / U2 ultra-wideband** chips (2019/2024) that drove {{ccc-digital-key|CCC Digital Key}} and AirTag, the iCloud Private Relay [[quic|QUIC]] deployment, and the first {{matter|Matter}} thread-border-router shipments. Their device share gives any default they pick (X25519MLKEM768, post-quantum [[tls|TLS]], etc.) immediate global reach.", + 'Largest single force shaping client-side wireless and codec choices: [[hls|HLS]] (2009), {{airdrop|AirDrop}}, AirPlay, the **U1 / U2 ultra-wideband** chips (2019/2024) that drove {{ccc-digital-key|CCC Digital Key}} and AirTag, the iCloud Private Relay [[quic|QUIC]] deployment, and the first {{matter|Matter}} thread-border-router shipments. Their device share gives any default they pick (X25519MLKEM768, post-quantum [[tls|TLS]], etc.) immediate global reach.', wikiUrl: 'https://en.wikipedia.org/wiki/Apple_Inc.', category: 'infrastructure' }, @@ -2844,7 +2845,7 @@ export const concepts: Concept[] = [ id: 'microsoft', term: 'Microsoft', definition: - "Operator of Azure, GitHub, and the Windows networking stack. Co-author of [[websockets|WebSockets]] adoption, [[mptcp|MPTCP]] early experiments, the Azure Service Bus [[amqp|AMQP]] deployment, and the SMB/SMB-Direct file-sharing protocols. Owns LinkedIn (the largest documented [[kafka|Kafka]] deployment on earth, >7 trillion messages/day).", + 'Operator of Azure, GitHub, and the Windows networking stack. Co-author of [[websockets|WebSockets]] adoption, [[mptcp|MPTCP]] early experiments, the Azure Service Bus [[amqp|AMQP]] deployment, and the SMB/SMB-Direct file-sharing protocols. Owns LinkedIn (the largest documented [[kafka|Kafka]] deployment on earth, >7 trillion messages/day).', wikiUrl: 'https://en.wikipedia.org/wiki/Microsoft', category: 'infrastructure' }, @@ -2852,7 +2853,7 @@ export const concepts: Concept[] = [ id: 'meta', term: 'Meta', definition: - "Operator of Facebook, Instagram, WhatsApp, and Messenger (the largest [[mqtt|MQTT]] deployment in the world). Major contributor to **mvfst** (open-source [[quic|QUIC]]), {{zstd|zstd}} compression, RDMA-over-Ethernet at scale, and several {{ietf|IETF}} working groups around Media-over-QUIC and {{l4s|L4S}}.", + 'Operator of Facebook, Instagram, WhatsApp, and Messenger (the largest [[mqtt|MQTT]] deployment in the world). Major contributor to **mvfst** (open-source [[quic|QUIC]]), {{zstd|zstd}} compression, RDMA-over-Ethernet at scale, and several {{ietf|IETF}} working groups around Media-over-QUIC and {{l4s|L4S}}.', wikiUrl: 'https://en.wikipedia.org/wiki/Meta_Platforms', category: 'infrastructure' }, @@ -2868,7 +2869,7 @@ export const concepts: Concept[] = [ id: 'nvidia', term: 'NVIDIA', definition: - "GPU and networking-silicon vendor (acquired Mellanox 2020) that drives modern AI-fabric design. Ships InfiniBand and **Spectrum-X** [[ethernet|Ethernet]] switches, Quantum-X / Spectrum-X co-packaged-optics chips, and BlueField DPUs. Joined the {{uec|Ultra Ethernet Consortium}} after long InfiniBand allegiance β€” a turning point for AI datacenter networking.", + 'GPU and networking-silicon vendor (acquired Mellanox 2020) that drives modern AI-fabric design. Ships InfiniBand and **Spectrum-X** [[ethernet|Ethernet]] switches, Quantum-X / Spectrum-X co-packaged-optics chips, and BlueField DPUs. Joined the {{uec|Ultra Ethernet Consortium}} after long InfiniBand allegiance β€” a turning point for AI datacenter networking.', wikiUrl: 'https://en.wikipedia.org/wiki/Nvidia', category: 'infrastructure' }, @@ -2876,7 +2877,7 @@ export const concepts: Concept[] = [ id: 'cisco', term: 'Cisco', definition: - "The dominant enterprise router and switch vendor since the 1990s. Built **IOS**, the canonical CLI networking-equipment shell, ran some of the most influential [[bgp|BGP]] reference implementations, and authored or co-authored major early {{ietf|IETF}} routing-protocol work. Acquired Webex (2007) and Meraki (2012); 2023–2025 spent rebuilding its security stack around Splunk and Robust Intelligence.", + 'The dominant enterprise router and switch vendor since the 1990s. Built **IOS**, the canonical CLI networking-equipment shell, ran some of the most influential [[bgp|BGP]] reference implementations, and authored or co-authored major early {{ietf|IETF}} routing-protocol work. Acquired Webex (2007) and Meraki (2012); 2023–2025 spent rebuilding its security stack around Splunk and Robust Intelligence.', wikiUrl: 'https://en.wikipedia.org/wiki/Cisco', category: 'infrastructure' }, @@ -2884,7 +2885,7 @@ export const concepts: Concept[] = [ id: 'juniper', term: 'Juniper Networks', definition: - "Carrier-grade router vendor founded 1996, the second pillar of internet backbone routing alongside [[cisco|Cisco]]. **Junos OS** is the canonical FreeBSD-derived router OS. Acquired by HPE in **1 July 2025** for $14 billion.", + 'Carrier-grade router vendor founded 1996, the second pillar of internet backbone routing alongside [[cisco|Cisco]]. **Junos OS** is the canonical FreeBSD-derived router OS. Acquired by HPE in **1 July 2025** for $14 billion.', wikiUrl: 'https://en.wikipedia.org/wiki/Juniper_Networks', category: 'infrastructure' }, @@ -2892,7 +2893,7 @@ export const concepts: Concept[] = [ id: 'broadcom', term: 'Broadcom', definition: - "Switch-silicon and connectivity-chip vendor that ships **Tomahawk**, **Trident**, and **Jericho** Ethernet ASICs β€” the building blocks under most hyperscale datacenter switches. Acquired VMware in 2023. Tomahawk 6 (June 2025) was the first 102.4 Tbps single-chip Ethernet switch.", + 'Switch-silicon and connectivity-chip vendor that ships **Tomahawk**, **Trident**, and **Jericho** Ethernet ASICs β€” the building blocks under most hyperscale datacenter switches. Acquired VMware in 2023. Tomahawk 6 (June 2025) was the first 102.4 Tbps single-chip Ethernet switch.', wikiUrl: 'https://en.wikipedia.org/wiki/Broadcom', category: 'infrastructure' }, @@ -2918,7 +2919,7 @@ export const concepts: Concept[] = [ id: 'linux', term: 'Linux', definition: - "The dominant server, router, and embedded operating system, started by Linus Torvalds in 1991. Owns the canonical implementations of [[tcp|TCP]] {{cubic|CUBIC}} (2.6.19+), {{bbr|BBR}} (4.9+), [[wireguard|WireGuard]] (5.6+), eBPF, XDP, and {{l4s|L4S}}. The reference platform every other OS measures itself against on the network stack.", + 'The dominant server, router, and embedded operating system, started by Linus Torvalds in 1991. Owns the canonical implementations of [[tcp|TCP]] {{cubic|CUBIC}} (2.6.19+), {{bbr|BBR}} (4.9+), [[wireguard|WireGuard]] (5.6+), eBPF, XDP, and {{l4s|L4S}}. The reference platform every other OS measures itself against on the network stack.', wikiUrl: 'https://en.wikipedia.org/wiki/Linux', category: 'infrastructure' }, @@ -2934,7 +2935,7 @@ export const concepts: Concept[] = [ id: 'wireshark', term: 'Wireshark', definition: - "The de-facto open-source packet analyser, originally **Ethereal** (1998). Reads pcap/pcapng files, decodes hundreds of protocols (TCP, TLS, QUIC, BGP, SIP, MQTT, CoAP, EMV β€” almost everything in this catalogue), and is the universal tool when a protocol does not do what its spec says. Recent releases (4.4, late 2024) added decryption for [[tls|TLS]] 1.3 with key-log files and pcap-over-[[quic|QUIC]] capture.", + 'The de-facto open-source packet analyser, originally **Ethereal** (1998). Reads pcap/pcapng files, decodes hundreds of protocols (TCP, TLS, QUIC, BGP, SIP, MQTT, CoAP, EMV β€” almost everything in this catalogue), and is the universal tool when a protocol does not do what its spec says. Recent releases (4.4, late 2024) added decryption for [[tls|TLS]] 1.3 with key-log files and pcap-over-[[quic|QUIC]] capture.', wikiUrl: 'https://en.wikipedia.org/wiki/Wireshark', category: 'infrastructure' }, @@ -2944,7 +2945,7 @@ export const concepts: Concept[] = [ id: 'iot', term: 'IoT (Internet of Things)', definition: - "The umbrella term for networked physical objects β€” sensors, actuators, smart-home devices, industrial controllers β€” that talk over [[mqtt|MQTT]], [[coap|CoAP]], {{thread|Thread}}, [[zigbee|Zigbee]], {{matter|Matter}}, or constrained [[cellular|cellular]] radios (NB-IoT, LTE-M). The defining constraints are *small RAM, small power budgets, intermittent connectivity, and a 10+ year deployment lifetime* β€” which is why every IoT protocol obsesses about byte counts and battery-friendly handshakes.", + 'The umbrella term for networked physical objects β€” sensors, actuators, smart-home devices, industrial controllers β€” that talk over [[mqtt|MQTT]], [[coap|CoAP]], {{thread|Thread}}, [[zigbee|Zigbee]], {{matter|Matter}}, or constrained [[cellular|cellular]] radios (NB-IoT, LTE-M). The defining constraints are *small RAM, small power budgets, intermittent connectivity, and a 10+ year deployment lifetime* β€” which is why every IoT protocol obsesses about byte counts and battery-friendly handshakes.', wikiUrl: 'https://en.wikipedia.org/wiki/Internet_of_things', category: 'networking-basics' }, @@ -2960,7 +2961,7 @@ export const concepts: Concept[] = [ id: 'wan', term: 'WAN (Wide Area Network)', definition: - "Any network spanning multiple physical locations or administrative domains β€” the public internet, an MPLS-VPN backbone, an SD-WAN overlay. WANs are where [[bgp|BGP]] routes, {{nat|NAT}} translates, [[tls|TLS]] protects, and the latency budget jumps from microseconds to tens or hundreds of milliseconds.", + 'Any network spanning multiple physical locations or administrative domains β€” the public internet, an MPLS-VPN backbone, an SD-WAN overlay. WANs are where [[bgp|BGP]] routes, {{nat|NAT}} translates, [[tls|TLS]] protects, and the latency budget jumps from microseconds to tens or hundreds of milliseconds.', wikiUrl: 'https://en.wikipedia.org/wiki/Wide_area_network', category: 'networking-basics' }, @@ -2970,7 +2971,7 @@ export const concepts: Concept[] = [ id: 'tcp-tahoe', term: 'TCP Tahoe', definition: - "The original [[tcp|TCP]] congestion-control algorithm, introduced by [[pioneer:van-jacobson|Van Jacobson]] in 1988. Adds **slow start**, **congestion avoidance**, **fast retransmit**, and full window reset on loss. Named for the 4.3BSD-Tahoe release. Superseded by {{tcp-reno|Reno}} (which keeps the window on duplicate {{ack|ACKs}}) within two years.", + 'The original [[tcp|TCP]] congestion-control algorithm, introduced by [[pioneer:van-jacobson|Van Jacobson]] in 1988. Adds **slow start**, **congestion avoidance**, **fast retransmit**, and full window reset on loss. Named for the 4.3BSD-Tahoe release. Superseded by {{tcp-reno|Reno}} (which keeps the window on duplicate {{ack|ACKs}}) within two years.', wikiUrl: 'https://en.wikipedia.org/wiki/TCP_congestion_control#TCP_Tahoe_and_Reno', category: 'protocol-mechanics' }, @@ -2978,7 +2979,7 @@ export const concepts: Concept[] = [ id: 'tcp-reno', term: 'TCP Reno', definition: - "The 1990 evolution of [[tcp|TCP]] {{tcp-tahoe|Tahoe}} that added **fast recovery** β€” on triple-duplicate {{ack|ACKs}}, halve the window and continue rather than dropping to one segment. The textbook congestion-control algorithm and the reference every later variant compares against.", + 'The 1990 evolution of [[tcp|TCP]] {{tcp-tahoe|Tahoe}} that added **fast recovery** β€” on triple-duplicate {{ack|ACKs}}, halve the window and continue rather than dropping to one segment. The textbook congestion-control algorithm and the reference every later variant compares against.', wikiUrl: 'https://en.wikipedia.org/wiki/TCP_congestion_control', category: 'protocol-mechanics' }, @@ -2986,7 +2987,7 @@ export const concepts: Concept[] = [ id: 'tcp-newreno', term: 'TCP NewReno', definition: - "An incremental refinement of {{tcp-reno|Reno}} that handles **multiple packet losses in one window** by staying in fast-recovery until *all* losses in the window have been acknowledged. Specified in [[rfc:6582|RFC 6582]] (2012, obsoleting RFC 3782). The default on Windows pre-2008 and on many BSD stacks for two decades.", + 'An incremental refinement of {{tcp-reno|Reno}} that handles **multiple packet losses in one window** by staying in fast-recovery until *all* losses in the window have been acknowledged. Specified in [[rfc:6582|RFC 6582]] (2012, obsoleting RFC 3782). The default on Windows pre-2008 and on many BSD stacks for two decades.', wikiUrl: 'https://en.wikipedia.org/wiki/TCP_congestion_control#TCP_NewReno', category: 'protocol-mechanics' }, @@ -2994,7 +2995,7 @@ export const concepts: Concept[] = [ id: 'bbrv3', term: 'BBRv3', definition: - "The 2023+ revision of {{bbr|BBR}} that addresses the v1 fairness problems with {{cubic|CUBIC}} and packet-conservation gaps. Now \`draft-ietf-ccwg-bbr\` (-04 / -05, 2025–2026); Google has run it as the default on google.com and YouTube traffic since 2023. Available in Linux via \`sysctl net.ipv4.tcp_congestion_control=bbr\` paired with FQ qdisc.", + 'The 2023+ revision of {{bbr|BBR}} that addresses the v1 fairness problems with {{cubic|CUBIC}} and packet-conservation gaps. Now `draft-ietf-ccwg-bbr` (-04 / -05, 2025–2026); Google has run it as the default on google.com and YouTube traffic since 2023. Available in Linux via `sysctl net.ipv4.tcp_congestion_control=bbr` paired with FQ qdisc.', category: 'protocol-mechanics' }, @@ -3011,7 +3012,7 @@ export const concepts: Concept[] = [ id: 'moq', term: 'MoQ (Media over QUIC)', definition: - "The {{ietf|IETF}} working group and protocol family designing the next-generation sub-second live streaming transport on top of [[quic|QUIC]]. \`draft-ietf-moq-transport\` (-17 in March 2026) is the core protocol β€” co-edited by Suhas Nandakumar (Cisco), Victor Vasiliev (Google), Ian Swett (Google), and Alan Frindell (Meta). Designed to replace the [[rtmp|RTMP]]β†’[[hls|HLS]] pipeline. Cloudflare runs production MoQ relays across 330+ cities.", + 'The {{ietf|IETF}} working group and protocol family designing the next-generation sub-second live streaming transport on top of [[quic|QUIC]]. `draft-ietf-moq-transport` (-17 in March 2026) is the core protocol β€” co-edited by Suhas Nandakumar (Cisco), Victor Vasiliev (Google), Ian Swett (Google), and Alan Frindell (Meta). Designed to replace the [[rtmp|RTMP]]β†’[[hls|HLS]] pipeline. Cloudflare runs production MoQ relays across 330+ cities.', category: 'protocol-mechanics' }, @@ -3020,7 +3021,7 @@ export const concepts: Concept[] = [ id: 'wpa2', term: 'WPA2', definition: - "The 2004 IEEE 802.11i amendment that made AES-CCMP and the **4-way handshake** mandatory for [[wifi|Wi-Fi]] security, ending WEP and TKIP. WPA2-Personal (PSK) is the universal home-router default 2004–2018; WPA2-Enterprise pairs it with {{eap|EAP}}-TLS / PEAP. Replaced by {{wpa3|WPA3}} starting 2018 after KRACK (2017) exposed protocol-level flaws in the 4-way handshake.", + 'The 2004 IEEE 802.11i amendment that made AES-CCMP and the **4-way handshake** mandatory for [[wifi|Wi-Fi]] security, ending WEP and TKIP. WPA2-Personal (PSK) is the universal home-router default 2004–2018; WPA2-Enterprise pairs it with {{eap|EAP}}-TLS / PEAP. Replaced by {{wpa3|WPA3}} starting 2018 after KRACK (2017) exposed protocol-level flaws in the 4-way handshake.', wikiUrl: 'https://en.wikipedia.org/wiki/Wi-Fi_Protected_Access#WPA2', category: 'security' }, @@ -3028,7 +3029,7 @@ export const concepts: Concept[] = [ id: 'mesh-network', term: 'Mesh network', definition: - "A multi-hop wireless topology where every node forwards frames for its neighbours β€” no central access point owns the airtime. {{thread|Thread}} (802.15.4 + IPv6), [[zigbee|Zigbee]] (802.15.4 + ZCL), Bluetooth Mesh (BR/EDR + GATT proxy), and Wi-Fi 802.11s are the four common families. The trade-off versus star topologies: longer reach and better resilience, but harder commissioning and worse battery life on relay nodes.", + 'A multi-hop wireless topology where every node forwards frames for its neighbours β€” no central access point owns the airtime. {{thread|Thread}} (802.15.4 + IPv6), [[zigbee|Zigbee]] (802.15.4 + ZCL), Bluetooth Mesh (BR/EDR + GATT proxy), and Wi-Fi 802.11s are the four common families. The trade-off versus star topologies: longer reach and better resilience, but harder commissioning and worse battery life on relay nodes.', wikiUrl: 'https://en.wikipedia.org/wiki/Mesh_networking', category: 'networking-basics' }, @@ -3036,7 +3037,7 @@ export const concepts: Concept[] = [ id: 'beacon-frame', term: 'Beacon frame', definition: - "In [[wifi|Wi-Fi]] (and {{ble|BLE}}, in a different sense), the periodic management frame an {{access-point|access point}} broadcasts to announce its presence β€” SSID, supported rates, capabilities, and timing. Default beacon interval is **100 ms** in Wi-Fi; this is one of the bigger sources of idle airtime in dense environments and is what Target Wake Time (TWT) tries to eliminate.", + 'In [[wifi|Wi-Fi]] (and {{ble|BLE}}, in a different sense), the periodic management frame an {{access-point|access point}} broadcasts to announce its presence β€” SSID, supported rates, capabilities, and timing. Default beacon interval is **100 ms** in Wi-Fi; this is one of the bigger sources of idle airtime in dense environments and is what Target Wake Time (TWT) tries to eliminate.', wikiUrl: 'https://en.wikipedia.org/wiki/Beacon_frame', category: 'protocol-mechanics' }, @@ -3062,7 +3063,7 @@ export const concepts: Concept[] = [ id: 'zstd', term: 'Zstandard (zstd)', definition: - "A lossless data compression algorithm developed by Yann Collet at {{meta|Meta}} (open-sourced 2016). Trades a tiny throughput cost vs. zlib for a sizeable ratio improvement, and is now an {{ietf|IETF}} standard ([[rfc:8478|RFC 8478]]) and the default codec for several [[kafka|Kafka]] producers, container image registries, and Linux kernel modules.", + 'A lossless data compression algorithm developed by Yann Collet at {{meta|Meta}} (open-sourced 2016). Trades a tiny throughput cost vs. zlib for a sizeable ratio improvement, and is now an {{ietf|IETF}} standard ([[rfc:8478|RFC 8478]]) and the default codec for several [[kafka|Kafka]] producers, container image registries, and Linux kernel modules.', wikiUrl: 'https://en.wikipedia.org/wiki/Zstd', category: 'protocol-mechanics' }, @@ -3070,14 +3071,14 @@ export const concepts: Concept[] = [ id: 'uec', term: 'UEC (Ultra Ethernet Consortium)', definition: - "Linux Foundation hosted consortium founded **19 July 2023** by AMD, Arista, Broadcom, Cisco, Eviden, HPE, Intel, Meta, and Microsoft (NVIDIA joined later) to redesign [[ethernet|Ethernet]] for AI fabrics. **UEC Specification 1.0** was published 11 June 2025 β€” defines **Ultra Ethernet Transport (UET)** with packet spraying, selective {{retransmission|retransmission}}, in-network telemetry, and ephemeral/{{connectionless|connectionless}} state for millions of endpoints.", + 'Linux Foundation hosted consortium founded **19 July 2023** by AMD, Arista, Broadcom, Cisco, Eviden, HPE, Intel, Meta, and Microsoft (NVIDIA joined later) to redesign [[ethernet|Ethernet]] for AI fabrics. **UEC Specification 1.0** was published 11 June 2025 β€” defines **Ultra Ethernet Transport (UET)** with packet spraying, selective {{retransmission|retransmission}}, in-network telemetry, and ephemeral/{{connectionless|connectionless}} state for millions of endpoints.', category: 'infrastructure' }, { id: 'ssdp', term: 'SSDP (Simple Service Discovery Protocol)', definition: - "The UPnP discovery protocol β€” multicast HTTP-over-[[udp|UDP]] to **239.255.255.250:1900** for finding devices on the {{lan|LAN}}. Routers, smart TVs, printers, game consoles, and media-server software (Plex, DLNA) all speak it. A long-standing security headache: open SSDP reflectors have been used in DDoS amplification attacks since 2014.", + 'The UPnP discovery protocol β€” multicast HTTP-over-[[udp|UDP]] to **239.255.255.250:1900** for finding devices on the {{lan|LAN}}. Routers, smart TVs, printers, game consoles, and media-server software (Plex, DLNA) all speak it. A long-standing security headache: open SSDP reflectors have been used in DDoS amplification attacks since 2014.', wikiUrl: 'https://en.wikipedia.org/wiki/Simple_Service_Discovery_Protocol', category: 'protocol-mechanics' }, @@ -3119,7 +3120,7 @@ export const concepts: Concept[] = [ id: 'tls-finished', term: 'Finished message', definition: - "The handshake-completion message in [[tls|TLS]]. A keyed MAC over the entire {{handshake|handshake}} transcript so far β€” both sides send one to prove they computed the same keys and saw the same messages. Detects downgrade attacks: anyone who tampered with the cipher-suite list, the key shares, or the {{certificate|certificate}} chain would fail the Finished check.", + 'The handshake-completion message in [[tls|TLS]]. A keyed MAC over the entire {{handshake|handshake}} transcript so far β€” both sides send one to prove they computed the same keys and saw the same messages. Detects downgrade attacks: anyone who tampered with the cipher-suite list, the key shares, or the {{certificate|certificate}} chain would fail the Finished check.', wikiUrl: 'https://en.wikipedia.org/wiki/Transport_Layer_Security', category: 'security' }, @@ -3129,7 +3130,7 @@ export const concepts: Concept[] = [ id: 'aes-gcm', term: 'AES-GCM', definition: - "The dominant {{aead|AEAD}} construction in the post-2010 internet: AES in counter mode for {{encryption|encryption}}, GHASH (Galois MAC) for authentication, all under one key. Used by [[tls|TLS]] 1.2/1.3, [[ipsec|IPsec ESP]], [[ssh|SSH]], [[wireguard|WireGuard]] (in AES variants), {{srtp|SRTP}}. Hardware AES-NI / VAES support makes it the fastest mainstream cipher on x86 and ARMv8.", + 'The dominant {{aead|AEAD}} construction in the post-2010 internet: AES in counter mode for {{encryption|encryption}}, GHASH (Galois MAC) for authentication, all under one key. Used by [[tls|TLS]] 1.2/1.3, [[ipsec|IPsec ESP]], [[ssh|SSH]], [[wireguard|WireGuard]] (in AES variants), {{srtp|SRTP}}. Hardware AES-NI / VAES support makes it the fastest mainstream cipher on x86 and ARMv8.', wikiUrl: 'https://en.wikipedia.org/wiki/Galois/Counter_Mode', category: 'security' }, @@ -3155,7 +3156,7 @@ export const concepts: Concept[] = [ id: 'pmk', term: 'PMK (Pairwise Master Key)', definition: - "The long-lived secret shared between a [[wifi|Wi-Fi]] station and the {{access-point|AP}}. In WPA2-Personal it is derived from the passphrase via PBKDF2(SSID, passphrase, 4096); in WPA2-Enterprise it falls out of the {{eap|EAP}} method. Both endpoints know the PMK *before* the {{four-way-handshake|4-way handshake}}; the handshake then mixes it with nonces to derive the per-session {{ptk|PTK}}.", + 'The long-lived secret shared between a [[wifi|Wi-Fi]] station and the {{access-point|AP}}. In WPA2-Personal it is derived from the passphrase via PBKDF2(SSID, passphrase, 4096); in WPA2-Enterprise it falls out of the {{eap|EAP}} method. Both endpoints know the PMK *before* the {{four-way-handshake|4-way handshake}}; the handshake then mixes it with nonces to derive the per-session {{ptk|PTK}}.', wikiUrl: 'https://en.wikipedia.org/wiki/IEEE_802.11i-2004', category: 'security' }, @@ -3163,7 +3164,7 @@ export const concepts: Concept[] = [ id: 'ptk', term: 'PTK (Pairwise Transient Key)', definition: - "The per-session session key in [[wifi|Wi-Fi]] WPA2/WPA3, derived during the {{four-way-handshake|4-way handshake}} from PMK + ANonce + SNonce + both MAC addresses. The PTK is split into KCK (key-confirmation), KEK (key-encryption), and TK (the temporal key that actually encrypts data frames with AES-CCMP or GCMP). Rotated whenever the station re-associates.", + 'The per-session session key in [[wifi|Wi-Fi]] WPA2/WPA3, derived during the {{four-way-handshake|4-way handshake}} from PMK + ANonce + SNonce + both MAC addresses. The PTK is split into KCK (key-confirmation), KEK (key-encryption), and TK (the temporal key that actually encrypts data frames with AES-CCMP or GCMP). Rotated whenever the station re-associates.', wikiUrl: 'https://en.wikipedia.org/wiki/IEEE_802.11i-2004', category: 'security' }, @@ -3179,7 +3180,7 @@ export const concepts: Concept[] = [ id: 'mic', term: 'MIC (Message Integrity Code)', definition: - "A short authenticator appended to encrypted frames in [[wifi|Wi-Fi]] (and [[bluetooth|Bluetooth LE]]) to prove integrity. In WPA2 CCMP it is 8 bytes; in GCMP it is 16. Different from a CRC: a CRC catches transmission errors; a MIC catches *adversarial* tampering because it depends on a secret key.", + 'A short authenticator appended to encrypted frames in [[wifi|Wi-Fi]] (and [[bluetooth|Bluetooth LE]]) to prove integrity. In WPA2 CCMP it is 8 bytes; in GCMP it is 16. Different from a CRC: a CRC catches transmission errors; a MIC catches *adversarial* tampering because it depends on a secret key.', wikiUrl: 'https://en.wikipedia.org/wiki/Message_authentication_code', category: 'security' }, @@ -3189,7 +3190,7 @@ export const concepts: Concept[] = [ id: 'spi', term: 'SPI (Security Parameters Index)', definition: - "A 32-bit identifier in the [[ipsec|IPsec]] ESP header that names *which Security Association* to use to decrypt this packet. The receiver looks up the SPI in its SAD (Security Association Database) to find the key, cipher, replay window, and counters. Each direction of an IPsec tunnel has its own SPI; they are negotiated in the {{ike-sa|IKE_SA_INIT}} exchange.", + 'A 32-bit identifier in the [[ipsec|IPsec]] ESP header that names *which Security Association* to use to decrypt this packet. The receiver looks up the SPI in its SAD (Security Association Database) to find the key, cipher, replay window, and counters. Each direction of an IPsec tunnel has its own SPI; they are negotiated in the {{ike-sa|IKE_SA_INIT}} exchange.', wikiUrl: 'https://en.wikipedia.org/wiki/Security_Parameter_Index', category: 'security' }, @@ -3197,7 +3198,7 @@ export const concepts: Concept[] = [ id: 'ike-sa', term: 'IKE SA', definition: - "The control-plane Security Association in [[ipsec|IKEv2]] β€” the encrypted, authenticated channel that the two peers use to *negotiate* the data-plane Child SAs. Established by the **IKE_SA_INIT** + **IKE_AUTH** exchanges (two round trips) and lives for hours; rekeyed before lifetime expiry with **CREATE_CHILD_SA**.", + 'The control-plane Security Association in [[ipsec|IKEv2]] β€” the encrypted, authenticated channel that the two peers use to *negotiate* the data-plane Child SAs. Established by the **IKE_SA_INIT** + **IKE_AUTH** exchanges (two round trips) and lives for hours; rekeyed before lifetime expiry with **CREATE_CHILD_SA**.', wikiUrl: 'https://en.wikipedia.org/wiki/Internet_Key_Exchange', category: 'security' }, @@ -3205,7 +3206,7 @@ export const concepts: Concept[] = [ id: 'child-sa', term: 'Child SA', definition: - "A unidirectional data-plane Security Association in [[ipsec|IKEv2]]. Carries the ESP key, cipher choice, sequence-number window, and traffic selectors for one direction of a tunnel. Two Child SAs (one each way) are negotiated inside the {{ike-sa|IKE SA}} during IKE_AUTH and rekeyed via **CREATE_CHILD_SA** before their byte/time limits.", + 'A unidirectional data-plane Security Association in [[ipsec|IKEv2]]. Carries the ESP key, cipher choice, sequence-number window, and traffic selectors for one direction of a tunnel. Two Child SAs (one each way) are negotiated inside the {{ike-sa|IKE SA}} during IKE_AUTH and rekeyed via **CREATE_CHILD_SA** before their byte/time limits.', wikiUrl: 'https://en.wikipedia.org/wiki/Internet_Key_Exchange', category: 'security' }, @@ -3215,7 +3216,7 @@ export const concepts: Concept[] = [ id: 'manifest', term: 'Manifest', definition: - "The top-level playlist file in adaptive-bitrate streaming. In [[hls|HLS]] this is an **`.m3u8`** text file; in [[dash|DASH]] it is an XML **MPD** (Media Presentation Description). Lists the available bitrate ladders, codec profiles, audio/subtitle tracks, and the URLs (or URL templates) for each segment. The player downloads the manifest first, then fetches segments per its {{adaptive-bitrate|adaptive-bitrate}} logic.", + 'The top-level playlist file in adaptive-bitrate streaming. In [[hls|HLS]] this is an **`.m3u8`** text file; in [[dash|DASH]] it is an XML **MPD** (Media Presentation Description). Lists the available bitrate ladders, codec profiles, audio/subtitle tracks, and the URLs (or URL templates) for each segment. The player downloads the manifest first, then fetches segments per its {{adaptive-bitrate|adaptive-bitrate}} logic.', wikiUrl: 'https://en.wikipedia.org/wiki/HTTP_Live_Streaming', category: 'protocol-mechanics' }, @@ -3233,7 +3234,7 @@ export const concepts: Concept[] = [ id: 'jitter-buffer', term: 'Jitter buffer', definition: - "A small (10–200 ms) playout queue at the receiver in [[rtp|RTP]] / {{voip|VoIP}} systems that absorbs network {{jitter|jitter}}. Buffers a few packets before starting playback so out-of-order arrivals can be re-ordered by [[rtp|RTP]] {{sequence-number|sequence number}}, and late packets can be dropped without an audible gap. Trades a tiny added {{latency|latency}} for smooth audio/video.", + 'A small (10–200 ms) playout queue at the receiver in [[rtp|RTP]] / {{voip|VoIP}} systems that absorbs network {{jitter|jitter}}. Buffers a few packets before starting playback so out-of-order arrivals can be re-ordered by [[rtp|RTP]] {{sequence-number|sequence number}}, and late packets can be dropped without an audible gap. Trades a tiny added {{latency|latency}} for smooth audio/video.', wikiUrl: 'https://en.wikipedia.org/wiki/Jitter#Jitter_buffer', category: 'protocol-mechanics' }, @@ -3241,7 +3242,7 @@ export const concepts: Concept[] = [ id: 'forward-error-correction', term: 'FEC (Forward Error Correction)', definition: - "Add redundancy on the *sender* side so the receiver can reconstruct lost packets without asking for a {{retransmission|retransmission}}. Common in real-time media where round-trip {{retransmission|retransmissions}} are too slow. Schemes range from simple parity (send 4 packets + 1 parity packet, survive 1 loss) to Reed-Solomon and Raptor codes. [[rtp|RTP]] payload format defined in [[rfc:5109|RFC 5109]] / [[rfc:8627|RFC 8627]].", + 'Add redundancy on the *sender* side so the receiver can reconstruct lost packets without asking for a {{retransmission|retransmission}}. Common in real-time media where round-trip {{retransmission|retransmissions}} are too slow. Schemes range from simple parity (send 4 packets + 1 parity packet, survive 1 loss) to Reed-Solomon and Raptor codes. [[rtp|RTP]] payload format defined in [[rfc:5109|RFC 5109]] / [[rfc:8627|RFC 8627]].', wikiUrl: 'https://en.wikipedia.org/wiki/Forward_error_correction', category: 'protocol-mechanics' }, @@ -3251,7 +3252,7 @@ export const concepts: Concept[] = [ id: 'ehlo', term: 'EHLO', definition: - "The opening command of an Extended [[smtp|SMTP]] session ([[rfc:5321|RFC 5321]]). Replaces the legacy `HELO` and lets the server advertise capabilities it supports β€” {{starttls|STARTTLS}}, SIZE limits, PIPELINING, AUTH mechanisms, DSN, 8BITMIME, SMTPUTF8. Every modern mail exchange starts with `EHLO <client hostname>`.", + 'The opening command of an Extended [[smtp|SMTP]] session ([[rfc:5321|RFC 5321]]). Replaces the legacy `HELO` and lets the server advertise capabilities it supports β€” {{starttls|STARTTLS}}, SIZE limits, PIPELINING, AUTH mechanisms, DSN, 8BITMIME, SMTPUTF8. Every modern mail exchange starts with `EHLO <client hostname>`.', wikiUrl: 'https://en.wikipedia.org/wiki/Extended_SMTP', category: 'protocol-mechanics' }, @@ -3259,7 +3260,7 @@ export const concepts: Concept[] = [ id: 'starttls', term: 'STARTTLS', definition: - "The opportunistic-{{encryption|encryption}} upgrade verb in [[smtp|SMTP]], [[imap|IMAP]], POP3, [[xmpp|XMPP]], and LDAP. Client sends `STARTTLS` over the plaintext session; server replies `220 Ready`; both sides perform a [[tls|TLS]] {{handshake|handshake}} on the same TCP connection. Vulnerable to **stripping attacks** where an active attacker removes the capability advertisement β€” closed by **MTA-STS** ([[rfc:8461|RFC 8461]]) and DANE.", + 'The opportunistic-{{encryption|encryption}} upgrade verb in [[smtp|SMTP]], [[imap|IMAP]], POP3, [[xmpp|XMPP]], and LDAP. Client sends `STARTTLS` over the plaintext session; server replies `220 Ready`; both sides perform a [[tls|TLS]] {{handshake|handshake}} on the same TCP connection. Vulnerable to **stripping attacks** where an active attacker removes the capability advertisement β€” closed by **MTA-STS** ([[rfc:8461|RFC 8461]]) and DANE.', wikiUrl: 'https://en.wikipedia.org/wiki/Opportunistic_TLS', category: 'security' }, @@ -3269,7 +3270,7 @@ export const concepts: Concept[] = [ id: 'dns-record-types', term: 'DNS record types', definition: - "The kinds of resource records [[dns|DNS]] serves. The common set: **A** ([[ip|IPv4]] address), **AAAA** ([[ipv6|IPv6]] address), **CNAME** (alias), **MX** (mail exchange), **NS** (authoritative name servers), **SOA** (zone authority), **TXT** (free-form text, used for SPF/DKIM/DMARC), **SRV** (service location, used by [[mdns-dns-sd|DNS-SD]] and Active Directory), **PTR** (reverse lookup), **CAA** (which {{certificate-authority|CAs}} may issue for a zone), and the {{dnssec|DNSSEC}} chain (DS, DNSKEY, RRSIG, NSEC).", + 'The kinds of resource records [[dns|DNS]] serves. The common set: **A** ([[ip|IPv4]] address), **AAAA** ([[ipv6|IPv6]] address), **CNAME** (alias), **MX** (mail exchange), **NS** (authoritative name servers), **SOA** (zone authority), **TXT** (free-form text, used for SPF/DKIM/DMARC), **SRV** (service location, used by [[mdns-dns-sd|DNS-SD]] and Active Directory), **PTR** (reverse lookup), **CAA** (which {{certificate-authority|CAs}} may issue for a zone), and the {{dnssec|DNSSEC}} chain (DS, DNSKEY, RRSIG, NSEC).', wikiUrl: 'https://en.wikipedia.org/wiki/List_of_DNS_record_types', category: 'protocol-mechanics' }, @@ -3277,7 +3278,7 @@ export const concepts: Concept[] = [ id: 'as-path', term: 'AS_PATH', definition: - "A [[bgp|BGP]] path attribute listing every {{autonomous-system|AS}} a route has passed through, in reverse-chronological order. Used both for *loop prevention* (a router rejects routes whose AS_PATH contains its own AS) and as the primary tie-breaker in best-path selection β€” shorter paths win. The path-vector mechanism is what makes [[bgp|BGP]] **policy-routable** in a way that pure link-state protocols are not.", + 'A [[bgp|BGP]] path attribute listing every {{autonomous-system|AS}} a route has passed through, in reverse-chronological order. Used both for *loop prevention* (a router rejects routes whose AS_PATH contains its own AS) and as the primary tie-breaker in best-path selection β€” shorter paths win. The path-vector mechanism is what makes [[bgp|BGP]] **policy-routable** in a way that pure link-state protocols are not.', wikiUrl: 'https://en.wikipedia.org/wiki/Border_Gateway_Protocol#Routes', category: 'protocol-mechanics' }, @@ -3295,7 +3296,7 @@ export const concepts: Concept[] = [ id: 'multi-homing', term: 'Multi-homing', definition: - "A host (or autonomous system) reachable through *multiple* network paths or {{ip-address|IP addresses}} simultaneously. [[sctp|SCTP]] negotiates multiple address pairs per association so a path failure switches transparently; [[mptcp|MPTCP]] does the same for TCP via subflows; [[bgp|BGP]]-speaking networks multi-home by announcing the same prefix from multiple upstream providers for redundancy.", + 'A host (or autonomous system) reachable through *multiple* network paths or {{ip-address|IP addresses}} simultaneously. [[sctp|SCTP]] negotiates multiple address pairs per association so a path failure switches transparently; [[mptcp|MPTCP]] does the same for TCP via subflows; [[bgp|BGP]]-speaking networks multi-home by announcing the same prefix from multiple upstream providers for redundancy.', wikiUrl: 'https://en.wikipedia.org/wiki/Multihoming', category: 'networking-basics' }, @@ -3303,7 +3304,7 @@ export const concepts: Concept[] = [ id: 'pipelining', term: 'Pipelining', definition: - "Sending the next request before the previous response arrives, so multiple {{request-response|request-response}} pairs are in flight at once. Standardised in [[http1|HTTP/1.1]] ([[rfc:9112|RFC 9112]]) but never reliably deployed because most servers responded *in order* β€” one slow response stalled everything behind it ({{head-of-line-blocking|head-of-line blocking}}). [[http2|HTTP/2]] solved this with binary {{multiplexing|multiplexing}}; [[smtp|SMTP]] PIPELINING is one place it works well.", + 'Sending the next request before the previous response arrives, so multiple {{request-response|request-response}} pairs are in flight at once. Standardised in [[http1|HTTP/1.1]] ([[rfc:9112|RFC 9112]]) but never reliably deployed because most servers responded *in order* β€” one slow response stalled everything behind it ({{head-of-line-blocking|head-of-line blocking}}). [[http2|HTTP/2]] solved this with binary {{multiplexing|multiplexing}}; [[smtp|SMTP]] PIPELINING is one place it works well.', wikiUrl: 'https://en.wikipedia.org/wiki/HTTP_pipelining', category: 'protocol-mechanics' }, @@ -3311,7 +3312,7 @@ export const concepts: Concept[] = [ id: 'doh', term: 'DoH (DNS over HTTPS)', definition: - "[[dns|DNS]] queries tunneled over [[http2|HTTP/2]] / [[http3|HTTP/3]] to a resolver (RFC 8484, 2018). Encrypts and authenticates DNS lookups against on-path eavesdroppers and tampering β€” closes the metadata leak that {{dnssec|DNSSEC}} alone could not. Default in Firefox since 2020 (Cloudflare 1.1.1.1, NextDNS); enterprises sometimes block DoH to retain DNS-based filtering.", + '[[dns|DNS]] queries tunneled over [[http2|HTTP/2]] / [[http3|HTTP/3]] to a resolver (RFC 8484, 2018). Encrypts and authenticates DNS lookups against on-path eavesdroppers and tampering β€” closes the metadata leak that {{dnssec|DNSSEC}} alone could not. Default in Firefox since 2020 (Cloudflare 1.1.1.1, NextDNS); enterprises sometimes block DoH to retain DNS-based filtering.', wikiUrl: 'https://en.wikipedia.org/wiki/DNS_over_HTTPS', category: 'security' }, @@ -3319,7 +3320,7 @@ export const concepts: Concept[] = [ id: 'dot', term: 'DoT (DNS over TLS)', definition: - "[[dns|DNS]] queries over a dedicated [[tls|TLS]] connection on port 853 (RFC 7858, 2016). Same goal as {{doh|DoH}} β€” encrypt and authenticate the resolver path β€” but uses its own port so middleboxes can distinguish DNS from web traffic. {{android|Android}} 9+ ships Private DNS that speaks DoT; the Knot, Unbound, and CoreDNS resolvers expose it server-side.", + '[[dns|DNS]] queries over a dedicated [[tls|TLS]] connection on port 853 (RFC 7858, 2016). Same goal as {{doh|DoH}} β€” encrypt and authenticate the resolver path β€” but uses its own port so middleboxes can distinguish DNS from web traffic. {{android|Android}} 9+ ships Private DNS that speaks DoT; the Knot, Unbound, and CoreDNS resolvers expose it server-side.', wikiUrl: 'https://en.wikipedia.org/wiki/DNS_over_TLS', category: 'security' }, @@ -3327,7 +3328,7 @@ export const concepts: Concept[] = [ id: 'stream-processing', term: 'Stream processing', definition: - "Compute over an unbounded data stream as records arrive β€” window, aggregate, join, alert β€” rather than batching a finite dataset. Built on top of distributed log brokers like [[kafka|Kafka]], [[amqp|AMQP]], or Pulsar. Frameworks: Flink, [[kafka|Kafka]] Streams, Spark Structured Streaming, ksqlDB. The processing model behind real-time fraud detection, telemetry, and CDC pipelines.", + 'Compute over an unbounded data stream as records arrive β€” window, aggregate, join, alert β€” rather than batching a finite dataset. Built on top of distributed log brokers like [[kafka|Kafka]], [[amqp|AMQP]], or Pulsar. Frameworks: Flink, [[kafka|Kafka]] Streams, Spark Structured Streaming, ksqlDB. The processing model behind real-time fraud detection, telemetry, and CDC pipelines.', wikiUrl: 'https://en.wikipedia.org/wiki/Stream_processing', category: 'messaging' }, @@ -3335,7 +3336,7 @@ export const concepts: Concept[] = [ id: 'anthropic', term: 'Anthropic', definition: - "AI safety company (founded 2021) and operator of the **Claude** family of large language models. Authored the Model Context Protocol ([[mcp|MCP]], November 2024), the open standard that lets LLM applications connect to outside tools and resources over [[json-rpc|JSON-RPC]] 2.0.", + 'AI safety company (founded 2021) and operator of the **Claude** family of large language models. Authored the Model Context Protocol ([[mcp|MCP]], November 2024), the open standard that lets LLM applications connect to outside tools and resources over [[json-rpc|JSON-RPC]] 2.0.', wikiUrl: 'https://en.wikipedia.org/wiki/Anthropic', category: 'infrastructure' }, @@ -3343,7 +3344,7 @@ export const concepts: Concept[] = [ id: 'linkedin', term: 'LinkedIn', definition: - "Professional-network site acquired by [[microsoft|Microsoft]] in 2016. Originator of Apache [[kafka|Kafka]] (open-sourced 2011); the company runs the largest publicly documented Kafka deployment on earth β€” **>7 trillion messages/day** as of the 2020s β€” and was the reference architecture every other Kafka deployment scaled against.", + 'Professional-network site acquired by [[microsoft|Microsoft]] in 2016. Originator of Apache [[kafka|Kafka]] (open-sourced 2011); the company runs the largest publicly documented Kafka deployment on earth β€” **>7 trillion messages/day** as of the 2020s β€” and was the reference architecture every other Kafka deployment scaled against.', wikiUrl: 'https://en.wikipedia.org/wiki/LinkedIn', category: 'infrastructure' }, @@ -3351,2669 +3352,2669 @@ export const concepts: Concept[] = [ id: 'android', term: 'Android', definition: - "[[google|Google]]'s mobile operating system (acquired from Android Inc. in 2005, first release 2008). Drives ~70% of global smartphone share. The reference platform that adopted [[quic|QUIC]], {{doh|DoH}}/{{dot|DoT}} (\"Private DNS\"), [[mptcp|MPTCP]], post-quantum [[tls|TLS]], and {{matter|Matter}} for the consumer device fleet.", + '[[google|Google]]\'s mobile operating system (acquired from Android Inc. in 2005, first release 2008). Drives ~70% of global smartphone share. The reference platform that adopted [[quic|QUIC]], {{doh|DoH}}/{{dot|DoT}} ("Private DNS"), [[mptcp|MPTCP]], post-quantum [[tls|TLS]], and {{matter|Matter}} for the consumer device fleet.', wikiUrl: 'https://en.wikipedia.org/wiki/Android_(operating_system)', category: 'infrastructure' }, // ── Sequence-diagram densification (agent-merged) ───────────────── { - id: 'syn', - term: 'SYN (Synchronize)', - definition: - "TCP control flag that opens a connection. The first packet of the {{three-way-handshake|three-way handshake}} carries SYN plus the sender's initial {{sequence-number|sequence number}}. A flood of SYNs without ACKs is the basis of a {{syn-flood|SYN-flood attack}}.", - wikiUrl: 'https://en.wikipedia.org/wiki/Transmission_Control_Protocol#Connection_establishment', - category: 'protocol-mechanics' + id: 'syn', + term: 'SYN (Synchronize)', + definition: + "TCP control flag that opens a connection. The first packet of the {{three-way-handshake|three-way handshake}} carries SYN plus the sender's initial {{sequence-number|sequence number}}. A flood of SYNs without ACKs is the basis of a {{syn-flood|SYN-flood attack}}.", + wikiUrl: 'https://en.wikipedia.org/wiki/Transmission_Control_Protocol#Connection_establishment', + category: 'protocol-mechanics' }, { - id: 'syn-ack', - term: 'SYN-ACK', - definition: - "Second message of the [[tcp|TCP]] {{three-way-handshake|three-way handshake}}: the server's reply that combines its own {{syn|SYN}} (with a fresh {{sequence-number|sequence number}}) and an {{ack|ACK}} of the client's SYN.", - category: 'protocol-mechanics' + id: 'syn-ack', + term: 'SYN-ACK', + definition: + "Second message of the [[tcp|TCP]] {{three-way-handshake|three-way handshake}}: the server's reply that combines its own {{syn|SYN}} (with a fresh {{sequence-number|sequence number}}) and an {{ack|ACK}} of the client's SYN.", + category: 'protocol-mechanics' }, { - id: 'initial-sequence-number', - term: 'Initial Sequence Number (ISN)', - definition: - "The randomly chosen {{sequence-number|sequence number}} each [[tcp|TCP]] endpoint picks at connection setup. Randomness defends against blind injection attacks ([[rfc:1948|RFC 1948]]).", - category: 'protocol-mechanics' + id: 'initial-sequence-number', + term: 'Initial Sequence Number (ISN)', + definition: + 'The randomly chosen {{sequence-number|sequence number}} each [[tcp|TCP]] endpoint picks at connection setup. Randomness defends against blind injection attacks ([[rfc:1948|RFC 1948]]).', + category: 'protocol-mechanics' }, { - id: 'piggyback-ack', - term: 'Piggyback ACK', - definition: - "Combining an {{ack|ACK}} into an outgoing data segment in the opposite direction, saving a round trip. Common in [[tcp|TCP]] bidirectional traffic.", - category: 'protocol-mechanics' + id: 'piggyback-ack', + term: 'Piggyback ACK', + definition: + 'Combining an {{ack|ACK}} into an outgoing data segment in the opposite direction, saving a round trip. Common in [[tcp|TCP]] bidirectional traffic.', + category: 'protocol-mechanics' }, { - id: 'init-chunk', - term: 'INIT chunk', - definition: - "First chunk of an [[sctp|SCTP]] {{four-way-handshake|4-way handshake}}. Carries the initiator's address list (for {{multi-homing|multi-homing}}) and verification tag.", - category: 'protocol-mechanics' + id: 'init-chunk', + term: 'INIT chunk', + definition: + "First chunk of an [[sctp|SCTP]] {{four-way-handshake|4-way handshake}}. Carries the initiator's address list (for {{multi-homing|multi-homing}}) and verification tag.", + category: 'protocol-mechanics' }, { - id: 'init-ack-chunk', - term: 'INIT-ACK chunk', - definition: - "[[sctp|SCTP]]'s reply to an {{init-chunk|INIT}}. Carries a stateless {{cookie|cookie}} so the responder commits no resources until the {{cookie-echo|COOKIE-ECHO}} returns β€” defeats {{syn-flood|SYN-flood}}-style attacks.", - category: 'protocol-mechanics' + id: 'init-ack-chunk', + term: 'INIT-ACK chunk', + definition: + "[[sctp|SCTP]]'s reply to an {{init-chunk|INIT}}. Carries a stateless {{cookie|cookie}} so the responder commits no resources until the {{cookie-echo|COOKIE-ECHO}} returns β€” defeats {{syn-flood|SYN-flood}}-style attacks.", + category: 'protocol-mechanics' }, { - id: 'cookie-echo', - term: 'COOKIE-ECHO chunk', - definition: - "Third chunk of the [[sctp|SCTP]] {{four-way-handshake|4-way handshake}}. The client echoes back the signed {{cookie|cookie}} it received in the {{init-ack-chunk|INIT-ACK}}; only at this point does the server allocate association state.", - category: 'protocol-mechanics' + id: 'cookie-echo', + term: 'COOKIE-ECHO chunk', + definition: + 'Third chunk of the [[sctp|SCTP]] {{four-way-handshake|4-way handshake}}. The client echoes back the signed {{cookie|cookie}} it received in the {{init-ack-chunk|INIT-ACK}}; only at this point does the server allocate association state.', + category: 'protocol-mechanics' }, { - id: 'cookie-ack', - term: 'COOKIE-ACK chunk', - definition: - "Final chunk of the [[sctp|SCTP]] {{four-way-handshake|4-way handshake}}, confirming the association is established and immune to {{syn-flood|SYN-flood}} DoS.", - category: 'protocol-mechanics' + id: 'cookie-ack', + term: 'COOKIE-ACK chunk', + definition: + 'Final chunk of the [[sctp|SCTP]] {{four-way-handshake|4-way handshake}}, confirming the association is established and immune to {{syn-flood|SYN-flood}} DoS.', + category: 'protocol-mechanics' }, { - id: 'sctp-association', - term: 'SCTP Association', - definition: - "[[sctp|SCTP]]'s connection-equivalent: a single logical session between two endpoints that may use multiple {{multi-homing|IP addresses}} and carries any number of independent {{stream|streams}}.", - category: 'protocol-mechanics' + id: 'sctp-association', + term: 'SCTP Association', + definition: + "[[sctp|SCTP]]'s connection-equivalent: a single logical session between two endpoints that may use multiple {{multi-homing|IP addresses}} and carries any number of independent {{stream|streams}}.", + category: 'protocol-mechanics' }, { - id: 'verification-tag', - term: 'Verification Tag', - definition: - "A random 32-bit value carried in every [[sctp|SCTP]] packet, chosen at association setup. Packets bearing the wrong tag are dropped, blocking blind injection.", - category: 'protocol-mechanics' + id: 'verification-tag', + term: 'Verification Tag', + definition: + 'A random 32-bit value carried in every [[sctp|SCTP]] packet, chosen at association setup. Packets bearing the wrong tag are dropped, blocking blind injection.', + category: 'protocol-mechanics' }, { - id: 'mp-capable', - term: 'MP_CAPABLE', - definition: - "[[mptcp|MPTCP]] [[tcp|TCP]] option exchanged during the initial {{three-way-handshake|handshake}} that signals *I can do multipath* and carries each side's per-host key β€” used later to authenticate additional {{subflow|subflows}}.", - category: 'protocol-mechanics' + id: 'mp-capable', + term: 'MP_CAPABLE', + definition: + "[[mptcp|MPTCP]] [[tcp|TCP]] option exchanged during the initial {{three-way-handshake|handshake}} that signals *I can do multipath* and carries each side's per-host key β€” used later to authenticate additional {{subflow|subflows}}.", + category: 'protocol-mechanics' }, { - id: 'mp-join', - term: 'MP_JOIN', - definition: - "[[mptcp|MPTCP]] [[tcp|TCP]] option that attaches a new {{subflow|subflow}} to an existing connection. Uses a token + {{nonce|nonce}} + {{hmac|HMAC}} to prove the new path belongs to the original session.", - category: 'protocol-mechanics' + id: 'mp-join', + term: 'MP_JOIN', + definition: + '[[mptcp|MPTCP]] [[tcp|TCP]] option that attaches a new {{subflow|subflow}} to an existing connection. Uses a token + {{nonce|nonce}} + {{hmac|HMAC}} to prove the new path belongs to the original session.', + category: 'protocol-mechanics' }, { - id: 'subflow', - term: 'Subflow (MPTCP)', - definition: - "An individual [[tcp|TCP]] connection carried over one network path that belongs to a larger [[mptcp|MPTCP]] session. A single MPTCP connection can have many subflows running in parallel over WiFi, cellular, ethernet, etc.", - category: 'protocol-mechanics' + id: 'subflow', + term: 'Subflow (MPTCP)', + definition: + 'An individual [[tcp|TCP]] connection carried over one network path that belongs to a larger [[mptcp|MPTCP]] session. A single MPTCP connection can have many subflows running in parallel over WiFi, cellular, ethernet, etc.', + category: 'protocol-mechanics' }, { - id: 'add-addr', - term: 'ADD_ADDR', - definition: - "[[mptcp|MPTCP]] option that advertises a newly available [[ip|IP]] address to the peer, inviting it to open a new {{subflow|subflow}} over that path.", - category: 'protocol-mechanics' + id: 'add-addr', + term: 'ADD_ADDR', + definition: + '[[mptcp|MPTCP]] option that advertises a newly available [[ip|IP]] address to the peer, inviting it to open a new {{subflow|subflow}} over that path.', + category: 'protocol-mechanics' }, { - id: 'failover', - term: 'Failover', - definition: - "Automatic re-routing of traffic onto a healthy path when the active one dies. Built into [[mptcp|MPTCP]] (subflow switching) and [[sctp|SCTP]] ({{multi-homing|multi-homing}}); often invisible to the application.", - category: 'protocol-mechanics' + id: 'failover', + term: 'Failover', + definition: + 'Automatic re-routing of traffic onto a healthy path when the active one dies. Built into [[mptcp|MPTCP]] (subflow switching) and [[sctp|SCTP]] ({{multi-homing|multi-homing}}); often invisible to the application.', + category: 'protocol-mechanics' }, { - id: 'unreliable-delivery', - term: 'Unreliable Delivery', - definition: - "Best-effort delivery with no retransmission, ordering, or acknowledgment. [[udp|UDP]]'s default β€” packets may be lost, duplicated, or reordered, and the application must handle it.", - category: 'protocol-mechanics' + id: 'unreliable-delivery', + term: 'Unreliable Delivery', + definition: + "Best-effort delivery with no retransmission, ordering, or acknowledgment. [[udp|UDP]]'s default β€” packets may be lost, duplicated, or reordered, and the application must handle it.", + category: 'protocol-mechanics' }, { - id: 'fire-and-forget', - term: 'Fire-and-Forget', - definition: - "Send a message and don't wait for confirmation. Characterizes [[udp|UDP]] datagrams and many event-driven systems β€” fast, but the sender never knows if it arrived.", - category: 'protocol-mechanics' + id: 'fire-and-forget', + term: 'Fire-and-Forget', + definition: + "Send a message and don't wait for confirmation. Characterizes [[udp|UDP]] datagrams and many event-driven systems β€” fast, but the sender never knows if it arrived.", + category: 'protocol-mechanics' }, { - id: 'key-share', - term: 'Key Share', - definition: - "{{tls-handshake|TLS}} extension where each side sends an ephemeral {{diffie-hellman|Diffie-Hellman}} public key in its first flight, enabling shared-secret derivation in 1-RTT and {{pfs|forward secrecy}}.", - category: 'security' + id: 'key-share', + term: 'Key Share', + definition: + '{{tls-handshake|TLS}} extension where each side sends an ephemeral {{diffie-hellman|Diffie-Hellman}} public key in its first flight, enabling shared-secret derivation in 1-RTT and {{pfs|forward secrecy}}.', + category: 'security' }, { - id: 'stream-independence', - term: 'Stream Independence', - definition: - "Property of [[quic|QUIC]] and [[sctp|SCTP]] where each {{stream|stream}} has its own ordering and loss-recovery, so a missing packet on one stream doesn't pause delivery on the others β€” avoids {{head-of-line-blocking|head-of-line blocking}}.", - category: 'protocol-mechanics' + id: 'stream-independence', + term: 'Stream Independence', + definition: + "Property of [[quic|QUIC]] and [[sctp|SCTP]] where each {{stream|stream}} has its own ordering and loss-recovery, so a missing packet on one stream doesn't pause delivery on the others β€” avoids {{head-of-line-blocking|head-of-line blocking}}.", + category: 'protocol-mechanics' }, { - id: 'initial-packet', - term: 'Initial Packet (QUIC)', - definition: - "First packet type in a [[quic|QUIC]] handshake. Carries the [[tls|TLS]] {{client-hello|ClientHello}} or {{server-hello|ServerHello}} plus QUIC transport parameters, protected with derived initial keys ([[rfc:9000|RFC 9000]]).", - category: 'protocol-mechanics' + id: 'initial-packet', + term: 'Initial Packet (QUIC)', + definition: + 'First packet type in a [[quic|QUIC]] handshake. Carries the [[tls|TLS]] {{client-hello|ClientHello}} or {{server-hello|ServerHello}} plus QUIC transport parameters, protected with derived initial keys ([[rfc:9000|RFC 9000]]).', + category: 'protocol-mechanics' }, { - id: 'n-plus-one', - term: 'N+1 Query Problem', - definition: - "Anti-pattern where fetching one parent resource then N children needs N+1 round trips (1 list + N detail calls). Common in {{request-response|request-response}} APIs over [[rest|REST]]; [[graphql|GraphQL]] mitigates it by letting clients request nested fields in a single query.", - wikiUrl: 'https://en.wikipedia.org/wiki/N%2B1_query_problem', - category: 'web' + id: 'n-plus-one', + term: 'N+1 Query Problem', + definition: + 'Anti-pattern where fetching one parent resource then N children needs N+1 round trips (1 list + N detail calls). Common in {{request-response|request-response}} APIs over [[rest|REST]]; [[graphql|GraphQL]] mitigates it by letting clients request nested fields in a single query.', + wikiUrl: 'https://en.wikipedia.org/wiki/N%2B1_query_problem', + category: 'web' }, { - id: 'over-fetching', - term: 'Over-fetching', - definition: - "When an API response includes more fields than the client needs β€” wasting bandwidth and CPU. The flip side is *under-fetching*, when one call doesn't return enough and forces another round trip. [[graphql|GraphQL]] was designed to eliminate both by letting clients specify exactly the shape they want.", - category: 'web' + id: 'over-fetching', + term: 'Over-fetching', + definition: + "When an API response includes more fields than the client needs β€” wasting bandwidth and CPU. The flip side is *under-fetching*, when one call doesn't return enough and forces another round trip. [[graphql|GraphQL]] was designed to eliminate both by letting clients specify exactly the shape they want.", + category: 'web' }, { - id: 'domain-sharding', - term: 'Domain Sharding', - definition: - "A 2010s-era [[http1|HTTP/1.1]] workaround: serve assets from multiple subdomains (`static1.example.com`, `static2.example.com`...) so the browser's 6-connections-per-origin limit multiplies. Made obsolete by [[http2|HTTP/2]] {{multiplexing|multiplexing}}, which actually hurts when you shard.", - wikiUrl: 'https://en.wikipedia.org/wiki/Domain_sharding', - category: 'web' + id: 'domain-sharding', + term: 'Domain Sharding', + definition: + "A 2010s-era [[http1|HTTP/1.1]] workaround: serve assets from multiple subdomains (`static1.example.com`, `static2.example.com`...) so the browser's 6-connections-per-origin limit multiplies. Made obsolete by [[http2|HTTP/2]] {{multiplexing|multiplexing}}, which actually hurts when you shard.", + wikiUrl: 'https://en.wikipedia.org/wiki/Domain_sharding', + category: 'web' }, { - id: 'content-encoding', - term: 'Content-Encoding', - definition: - "[[http1|HTTP]] response header naming the compression applied to the body β€” usually `gzip`, `br` (Brotli), or `zstd` ({{zstd|Zstandard}}). The client advertises support via `Accept-Encoding` and the server picks one. Shrinks payloads 60-90% for text.", - wikiUrl: 'https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding', - category: 'web' + id: 'content-encoding', + term: 'Content-Encoding', + definition: + '[[http1|HTTP]] response header naming the compression applied to the body β€” usually `gzip`, `br` (Brotli), or `zstd` ({{zstd|Zstandard}}). The client advertises support via `Accept-Encoding` and the server picks one. Shrinks payloads 60-90% for text.', + wikiUrl: 'https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding', + category: 'web' }, { - id: 'content-type', - term: 'Content-Type', - definition: - "[[http1|HTTP]] header naming the {{mime|MIME}} type of the message body (e.g., `text/html`, `application/json`, `text/event-stream`). Tells the receiver how to parse the bytes that follow.", - wikiUrl: 'https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type', - category: 'web' + id: 'content-type', + term: 'Content-Type', + definition: + '[[http1|HTTP]] header naming the {{mime|MIME}} type of the message body (e.g., `text/html`, `application/json`, `text/event-stream`). Tells the receiver how to parse the bytes that follow.', + wikiUrl: 'https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type', + category: 'web' }, { - id: 'mime', - term: 'MIME Type', - definition: - "Multipurpose Internet Mail Extensions β€” the `type/subtype` labelling system ({{content-type|Content-Type}}) used by [[http1|HTTP]], [[smtp|SMTP]], and other protocols to declare what's in a message body. Examples: `text/html`, `application/json`, `image/png`.", - wikiUrl: 'https://en.wikipedia.org/wiki/Media_type', - category: 'web' + id: 'mime', + term: 'MIME Type', + definition: + "Multipurpose Internet Mail Extensions β€” the `type/subtype` labelling system ({{content-type|Content-Type}}) used by [[http1|HTTP]], [[smtp|SMTP]], and other protocols to declare what's in a message body. Examples: `text/html`, `application/json`, `image/png`.", + wikiUrl: 'https://en.wikipedia.org/wiki/Media_type', + category: 'web' }, { - id: 'protocol-upgrade', - term: 'Protocol Upgrade', - definition: - "[[http1|HTTP]]'s mechanism for switching the same [[tcp|TCP]] connection to a different protocol mid-stream. Client sends `Upgrade: <name>` and `Connection: Upgrade`; the server replies **`101 Switching Protocols`** and both sides start speaking the new wire format. Used by [[websockets|WebSockets]] and HTTP/2 over cleartext (h2c).", - wikiUrl: 'https://developer.mozilla.org/en-US/docs/Web/HTTP/Protocol_upgrade_mechanism', - category: 'web' + id: 'protocol-upgrade', + term: 'Protocol Upgrade', + definition: + "[[http1|HTTP]]'s mechanism for switching the same [[tcp|TCP]] connection to a different protocol mid-stream. Client sends `Upgrade: <name>` and `Connection: Upgrade`; the server replies **`101 Switching Protocols`** and both sides start speaking the new wire format. Used by [[websockets|WebSockets]] and HTTP/2 over cleartext (h2c).", + wikiUrl: 'https://developer.mozilla.org/en-US/docs/Web/HTTP/Protocol_upgrade_mechanism', + category: 'web' }, { - id: 'websocket-frame', - term: 'WebSocket Frame', - definition: - "The minimal unit of a [[websockets|WebSocket]] message. A small header (opcode = text/binary/close/ping/pong, masking flag, length) followed by payload bytes. Replaces [[http1|HTTP]]'s request/response framing once the {{protocol-upgrade|Upgrade}} completes.", - category: 'web' + id: 'websocket-frame', + term: 'WebSocket Frame', + definition: + "The minimal unit of a [[websockets|WebSocket]] message. A small header (opcode = text/binary/close/ping/pong, masking flag, length) followed by payload bytes. Replaces [[http1|HTTP]]'s request/response framing once the {{protocol-upgrade|Upgrade}} completes.", + category: 'web' }, { - id: 'eventsource', - term: 'EventSource API', - definition: - "The browser JavaScript interface for [[sse|Server-Sent Events]]. `new EventSource(url)` opens a streaming [[http1|HTTP]] connection, auto-reconnects on drop, and fires `message`/named events. Sends the `Last-Event-ID` header on reconnect so the server can resume.", - wikiUrl: 'https://developer.mozilla.org/en-US/docs/Web/API/EventSource', - category: 'web' + id: 'eventsource', + term: 'EventSource API', + definition: + 'The browser JavaScript interface for [[sse|Server-Sent Events]]. `new EventSource(url)` opens a streaming [[http1|HTTP]] connection, auto-reconnects on drop, and fires `message`/named events. Sends the `Last-Event-ID` header on reconnect so the server can resume.', + wikiUrl: 'https://developer.mozilla.org/en-US/docs/Web/API/EventSource', + category: 'web' }, { - id: 'last-event-id', - term: 'Last-Event-ID', - definition: - "[[http1|HTTP]] header the browser sends when reconnecting an [[sse|SSE]] stream, carrying the `id:` of the last event it received. Lets the server resume the stream from where it left off β€” built into the {{eventsource|EventSource API}}.", - category: 'web' + id: 'last-event-id', + term: 'Last-Event-ID', + definition: + '[[http1|HTTP]] header the browser sends when reconnecting an [[sse|SSE]] stream, carrying the `id:` of the last event it received. Lets the server resume the stream from where it left off β€” built into the {{eventsource|EventSource API}}.', + category: 'web' }, { - id: 'graphql-query', - term: 'GraphQL Query', - definition: - "A read operation in [[graphql|GraphQL]] β€” the client describes a nested field selection and the server returns exactly that shape. Counterpart to **mutations** (writes) and **subscriptions** (push streams, often over [[websockets|WebSockets]]).", - wikiUrl: 'https://graphql.org/learn/queries/', - category: 'web' + id: 'graphql-query', + term: 'GraphQL Query', + definition: + 'A read operation in [[graphql|GraphQL]] β€” the client describes a nested field selection and the server returns exactly that shape. Counterpart to **mutations** (writes) and **subscriptions** (push streams, often over [[websockets|WebSockets]]).', + wikiUrl: 'https://graphql.org/learn/queries/', + category: 'web' }, { - id: 'graphql-mutation', - term: 'GraphQL Mutation', - definition: - "A write operation in [[graphql|GraphQL]] β€” creates, updates, or deletes data. Same syntax as a {{graphql-query|query}} but the server treats fields as side-effecting and runs them sequentially.", - category: 'web' + id: 'graphql-mutation', + term: 'GraphQL Mutation', + definition: + 'A write operation in [[graphql|GraphQL]] β€” creates, updates, or deletes data. Same syntax as a {{graphql-query|query}} but the server treats fields as side-effecting and runs them sequentially.', + category: 'web' }, { - id: 'graphql-subscription', - term: 'GraphQL Subscription', - definition: - "A long-lived push channel in [[graphql|GraphQL]] β€” the client subscribes to events and the server streams matching payloads. Usually delivered over [[websockets|WebSockets]] (graphql-ws) or [[sse|SSE]].", - category: 'web' + id: 'graphql-subscription', + term: 'GraphQL Subscription', + definition: + 'A long-lived push channel in [[graphql|GraphQL]] β€” the client subscribes to events and the server streams matching payloads. Usually delivered over [[websockets|WebSockets]] (graphql-ws) or [[sse|SSE]].', + category: 'web' }, { - id: 'graphql-schema', - term: 'GraphQL Schema', - definition: - "The typed contract of a [[graphql|GraphQL]] API β€” defines every object type, field, argument, query/mutation/subscription root, and how they connect. Both client and server share it; tooling generates types from it.", - category: 'web' + id: 'graphql-schema', + term: 'GraphQL Schema', + definition: + 'The typed contract of a [[graphql|GraphQL]] API β€” defines every object type, field, argument, query/mutation/subscription root, and how they connect. Both client and server share it; tooling generates types from it.', + category: 'web' }, { - id: 'graphql-resolver', - term: 'GraphQL Resolver', - definition: - "A server-side function that produces the value for a single {{graphql-schema|schema}} field. [[graphql|GraphQL]] walks the query, calling one resolver per field β€” the runtime that turns a query into a response.", - category: 'web' + id: 'graphql-resolver', + term: 'GraphQL Resolver', + definition: + 'A server-side function that produces the value for a single {{graphql-schema|schema}} field. [[graphql|GraphQL]] walks the query, calling one resolver per field β€” the runtime that turns a query into a response.', + category: 'web' }, { - id: 'rpc', - term: 'RPC (Remote Procedure Call)', - definition: - "An API style where the client calls a *named function* on the server with arguments and gets a result β€” as if it were local. Contrast with [[rest|REST]] (resources + verbs) and [[graphql|GraphQL]] (typed field selection). Modern examples: [[grpc|gRPC]], [[json-rpc|JSON-RPC]], [[mcp|MCP]].", - wikiUrl: 'https://en.wikipedia.org/wiki/Remote_procedure_call', - category: 'protocol-mechanics' + id: 'rpc', + term: 'RPC (Remote Procedure Call)', + definition: + 'An API style where the client calls a *named function* on the server with arguments and gets a result β€” as if it were local. Contrast with [[rest|REST]] (resources + verbs) and [[graphql|GraphQL]] (typed field selection). Modern examples: [[grpc|gRPC]], [[json-rpc|JSON-RPC]], [[mcp|MCP]].', + wikiUrl: 'https://en.wikipedia.org/wiki/Remote_procedure_call', + category: 'protocol-mechanics' }, { - id: 'protoc', - term: 'protoc', - definition: - "The {{protocol-buffers|Protocol Buffers}} compiler. Reads `.proto` schema files and generates type-safe client + server stubs in C++, Go, Java, Python, Rust, and a dozen other languages β€” the build step behind [[grpc|gRPC]].", - wikiUrl: 'https://protobuf.dev/reference/protoc/', - category: 'protocol-mechanics' + id: 'protoc', + term: 'protoc', + definition: + 'The {{protocol-buffers|Protocol Buffers}} compiler. Reads `.proto` schema files and generates type-safe client + server stubs in C++, Go, Java, Python, Rust, and a dozen other languages β€” the build step behind [[grpc|gRPC]].', + wikiUrl: 'https://protobuf.dev/reference/protoc/', + category: 'protocol-mechanics' }, { - id: 'json-schema', - term: 'JSON Schema', - definition: - "A vocabulary for describing the shape and constraints of {{json|JSON}} documents β€” types, required fields, enums, patterns. Used by [[mcp|MCP]] to declare tool input shapes and by [[a2a|A2A]] Agent Cards to declare skill inputs, so an LLM can call the tool correctly.", - wikiUrl: 'https://json-schema.org/', - category: 'web' + id: 'json-schema', + term: 'JSON Schema', + definition: + 'A vocabulary for describing the shape and constraints of {{json|JSON}} documents β€” types, required fields, enums, patterns. Used by [[mcp|MCP]] to declare tool input shapes and by [[a2a|A2A]] Agent Cards to declare skill inputs, so an LLM can call the tool correctly.', + wikiUrl: 'https://json-schema.org/', + category: 'web' }, { - id: 'lsp', - term: 'Language Server Protocol (LSP)', - definition: - "Microsoft's [[json-rpc|JSON-RPC]] standard letting code editors talk to language servers for autocomplete, jump-to-definition, diagnostics, etc. The transport pattern (JSON-RPC over stdio) directly inspired [[mcp|MCP]].", - wikiUrl: 'https://microsoft.github.io/language-server-protocol/', - category: 'web' + id: 'lsp', + term: 'Language Server Protocol (LSP)', + definition: + "Microsoft's [[json-rpc|JSON-RPC]] standard letting code editors talk to language servers for autocomplete, jump-to-definition, diagnostics, etc. The transport pattern (JSON-RPC over stdio) directly inspired [[mcp|MCP]].", + wikiUrl: 'https://microsoft.github.io/language-server-protocol/', + category: 'web' }, { - id: 'stdio', - term: 'stdio (Standard I/O)', - definition: - "The standard input/output streams of a process. Used as a transport by [[mcp|MCP]] and the {{lsp|Language Server Protocol}}: parent launches a child process and exchanges [[json-rpc|JSON-RPC]] messages over its stdin/stdout β€” zero network setup, fully local.", - wikiUrl: 'https://en.wikipedia.org/wiki/Standard_streams', - category: 'infrastructure' + id: 'stdio', + term: 'stdio (Standard I/O)', + definition: + 'The standard input/output streams of a process. Used as a transport by [[mcp|MCP]] and the {{lsp|Language Server Protocol}}: parent launches a child process and exchanges [[json-rpc|JSON-RPC]] messages over its stdin/stdout β€” zero network setup, fully local.', + wikiUrl: 'https://en.wikipedia.org/wiki/Standard_streams', + category: 'infrastructure' }, { - id: 'well-known-uri', - term: 'Well-Known URI', - definition: - "A standardized URL path under `/.well-known/` that hosts machine-readable metadata about a server. Examples: `/.well-known/openid-configuration` ([[oauth2|OAuth]]), `/.well-known/agent.json` ([[a2a|A2A]] Agent Card). Specified in [[rfc:8615|RFC 8615]].", - wikiUrl: 'https://en.wikipedia.org/wiki/Well-known_URI', - category: 'web' + id: 'well-known-uri', + term: 'Well-Known URI', + definition: + 'A standardized URL path under `/.well-known/` that hosts machine-readable metadata about a server. Examples: `/.well-known/openid-configuration` ([[oauth2|OAuth]]), `/.well-known/agent.json` ([[a2a|A2A]] Agent Card). Specified in [[rfc:8615|RFC 8615]].', + wikiUrl: 'https://en.wikipedia.org/wiki/Well-known_URI', + category: 'web' }, { - id: 'agent-card', - term: 'Agent Card', - definition: - "An [[a2a|A2A]] agent's public profile document, served at `/.well-known/agent.json` ({{well-known-uri|well-known URI}}). Lists the agent's name, skills, input/output schemas ({{json-schema|JSON Schema}}), authentication, and API endpoint β€” the file other agents fetch to learn how to delegate to it.", - category: 'web' + id: 'agent-card', + term: 'Agent Card', + definition: + "An [[a2a|A2A]] agent's public profile document, served at `/.well-known/agent.json` ({{well-known-uri|well-known URI}}). Lists the agent's name, skills, input/output schemas ({{json-schema|JSON Schema}}), authentication, and API endpoint β€” the file other agents fetch to learn how to delegate to it.", + category: 'web' }, { - id: 'mcp-tool', - term: 'MCP Tool', - definition: - "An executable function an [[mcp|MCP]] server exposes to a host. Each tool advertises a name, description, and {{json-schema|JSON Schema}} for its arguments. The host calls `tools/call` and the server runs the underlying code.", - category: 'web' + id: 'mcp-tool', + term: 'MCP Tool', + definition: + 'An executable function an [[mcp|MCP]] server exposes to a host. Each tool advertises a name, description, and {{json-schema|JSON Schema}} for its arguments. The host calls `tools/call` and the server runs the underlying code.', + category: 'web' }, { - id: 'mcp-resource', - term: 'MCP Resource', - definition: - "A readable data source an [[mcp|MCP]] server exposes β€” addressed by URI (files, database rows, API endpoints). The host calls `resources/read` to fetch contents and may subscribe to change notifications.", - category: 'web' + id: 'mcp-resource', + term: 'MCP Resource', + definition: + 'A readable data source an [[mcp|MCP]] server exposes β€” addressed by URI (files, database rows, API endpoints). The host calls `resources/read` to fetch contents and may subscribe to change notifications.', + category: 'web' }, { - id: 'mcp-host', - term: 'MCP Host', - definition: - "The AI application (e.g., Claude Desktop, an IDE assistant) on the user's side of an [[mcp|MCP]] connection. It launches or connects to MCP servers, runs the LLM, and orchestrates {{mcp-tool|tool}} calls and {{mcp-resource|resource}} reads.", - category: 'web' + id: 'mcp-host', + term: 'MCP Host', + definition: + "The AI application (e.g., Claude Desktop, an IDE assistant) on the user's side of an [[mcp|MCP]] connection. It launches or connects to MCP servers, runs the LLM, and orchestrates {{mcp-tool|tool}} calls and {{mcp-resource|resource}} reads.", + category: 'web' }, { - id: 'soap-envelope', - term: 'SOAP Envelope', - definition: - "The outer [[xml|XML]] element wrapping every [[soap|SOAP]] message: `<Envelope>` containing an optional `<Header>` (auth, routing, transaction info) and a required `<Body>` (the actual call or response payload, or a {{soap-fault|Fault}}).", - category: 'web' + id: 'soap-envelope', + term: 'SOAP Envelope', + definition: + 'The outer [[xml|XML]] element wrapping every [[soap|SOAP]] message: `<Envelope>` containing an optional `<Header>` (auth, routing, transaction info) and a required `<Body>` (the actual call or response payload, or a {{soap-fault|Fault}}).', + category: 'web' }, { - id: 'soap-fault', - term: 'SOAP Fault', - definition: - "A structured error inside a [[soap|SOAP]] response `<Body>` β€” carries a fault code (`Client`/`Server`/`VersionMismatch`/`MustUnderstand`), a human-readable string, and optional details. Returned with HTTP 500 but parsed as protocol-level error info regardless of transport.", - category: 'web' + id: 'soap-fault', + term: 'SOAP Fault', + definition: + 'A structured error inside a [[soap|SOAP]] response `<Body>` β€” carries a fault code (`Client`/`Server`/`VersionMismatch`/`MustUnderstand`), a human-readable string, and optional details. Returned with HTTP 500 but parsed as protocol-level error info regardless of transport.', + category: 'web' }, { - id: 'soapaction', - term: 'SOAPAction Header', - definition: - "[[http1|HTTP]] header on a [[soap|SOAP]] request naming the operation being invoked. Pre-{{wsdl|WSDL}} servers used it for fast dispatch without parsing the XML body; modern SOAP 1.2 puts the action in `Content-Type` instead.", - category: 'web' + id: 'soapaction', + term: 'SOAPAction Header', + definition: + '[[http1|HTTP]] header on a [[soap|SOAP]] request naming the operation being invoked. Pre-{{wsdl|WSDL}} servers used it for fast dispatch without parsing the XML body; modern SOAP 1.2 puts the action in `Content-Type` instead.', + category: 'web' }, { - id: 'task-lifecycle-a2a', - term: 'A2A Task Lifecycle', - definition: - "The state machine an [[a2a|A2A]] task moves through: `submitted` β†’ `working` β†’ (`input-required` β†’ `working` ...) β†’ `completed` / `failed` / `canceled`. Lets a client agent track long-running work and stream intermediate progress.", - category: 'web' + id: 'task-lifecycle-a2a', + term: 'A2A Task Lifecycle', + definition: + 'The state machine an [[a2a|A2A]] task moves through: `submitted` β†’ `working` β†’ (`input-required` β†’ `working` ...) β†’ `completed` / `failed` / `canceled`. Lets a client agent track long-running work and stream intermediate progress.', + category: 'web' }, { - id: 'http2-frame', - term: 'HTTP/2 Frame', - definition: - "The smallest unit of [[http2|HTTP/2]] communication. A 9-byte header (length, type, flags, stream ID) plus payload. Frame types include **HEADERS** (request/response headers, {{hpack|HPACK}}-encoded), **DATA** (body), **SETTINGS** (connection params), **WINDOW_UPDATE** ({{flow-control|flow control}}), **PING**, **RST_STREAM** (cancel a stream), **GOAWAY** (close connection), and **PUSH_PROMISE** ({{server-push|server push}}).", - category: 'web' + id: 'http2-frame', + term: 'HTTP/2 Frame', + definition: + 'The smallest unit of [[http2|HTTP/2]] communication. A 9-byte header (length, type, flags, stream ID) plus payload. Frame types include **HEADERS** (request/response headers, {{hpack|HPACK}}-encoded), **DATA** (body), **SETTINGS** (connection params), **WINDOW_UPDATE** ({{flow-control|flow control}}), **PING**, **RST_STREAM** (cancel a stream), **GOAWAY** (close connection), and **PUSH_PROMISE** ({{server-push|server push}}).', + category: 'web' }, { - id: 'qpack', - term: 'QPACK', - definition: - "[[http3|HTTP/3]]'s header-compression scheme β€” the [[quic|QUIC]] equivalent of {{hpack|HPACK}}. Redesigned so header decoding doesn't stall when streams arrive out of order, which is essential since QUIC streams are independent ([[rfc:9204|RFC 9204]]).", - wikiUrl: 'https://datatracker.ietf.org/doc/html/rfc9204', - category: 'web' + id: 'qpack', + term: 'QPACK', + definition: + "[[http3|HTTP/3]]'s header-compression scheme β€” the [[quic|QUIC]] equivalent of {{hpack|HPACK}}. Redesigned so header decoding doesn't stall when streams arrive out of order, which is essential since QUIC streams are independent ([[rfc:9204|RFC 9204]]).", + wikiUrl: 'https://datatracker.ietf.org/doc/html/rfc9204', + category: 'web' }, { - id: 'mqtt-connect', - term: 'CONNECT / CONNACK (MQTT)', - definition: - "First two messages of every [[mqtt|MQTT]] session. The client sends `CONNECT` with its client ID, optional credentials, keepalive interval, and last-will message; the {{broker|broker}} replies `CONNACK` with a return code (0 = accepted). Until CONNACK arrives, no PUBLISH or SUBSCRIBE is allowed.", - category: 'messaging' + id: 'mqtt-connect', + term: 'CONNECT / CONNACK (MQTT)', + definition: + 'First two messages of every [[mqtt|MQTT]] session. The client sends `CONNECT` with its client ID, optional credentials, keepalive interval, and last-will message; the {{broker|broker}} replies `CONNACK` with a return code (0 = accepted). Until CONNACK arrives, no PUBLISH or SUBSCRIBE is allowed.', + category: 'messaging' }, { - id: 'mqtt-subscribe', - term: 'SUBSCRIBE / SUBACK (MQTT)', - definition: - "Client registers interest in one or more {{topic|topic}} filters with a `SUBSCRIBE` packet; the {{broker|broker}} responds `SUBACK` listing the granted {{qos|QoS}} level per filter. Topic filters may use the `+` (one-level) and `#` (multi-level) wildcards.", - category: 'messaging' + id: 'mqtt-subscribe', + term: 'SUBSCRIBE / SUBACK (MQTT)', + definition: + 'Client registers interest in one or more {{topic|topic}} filters with a `SUBSCRIBE` packet; the {{broker|broker}} responds `SUBACK` listing the granted {{qos|QoS}} level per filter. Topic filters may use the `+` (one-level) and `#` (multi-level) wildcards.', + category: 'messaging' }, { - id: 'mqtt-publish', - term: 'PUBLISH (MQTT)', - definition: - "Packet carrying an application message from publisher to {{broker|broker}}, or {{broker|broker}} to subscriber. Contains the {{topic|topic}} name, {{qos|QoS}} level, retain flag, and payload. At QoS > 0 a PUBLISH is matched by `PUBACK` (QoS 1) or `PUBREC`/`PUBREL`/`PUBCOMP` (QoS 2).", - category: 'messaging' + id: 'mqtt-publish', + term: 'PUBLISH (MQTT)', + definition: + 'Packet carrying an application message from publisher to {{broker|broker}}, or {{broker|broker}} to subscriber. Contains the {{topic|topic}} name, {{qos|QoS}} level, retain flag, and payload. At QoS > 0 a PUBLISH is matched by `PUBACK` (QoS 1) or `PUBREC`/`PUBREL`/`PUBCOMP` (QoS 2).', + category: 'messaging' }, { - id: 'topic-wildcard', - term: 'Topic wildcard (+, #)', - definition: - "Pattern syntax in [[mqtt|MQTT]] {{topic|topic}} filters. `+` matches exactly one level (`sensor/+/temp` covers `sensor/kitchen/temp` but not `sensor/kitchen/inner/temp`); `#` matches zero or more remaining levels and must be the final character (`sensor/#`).", - category: 'messaging' + id: 'topic-wildcard', + term: 'Topic wildcard (+, #)', + definition: + 'Pattern syntax in [[mqtt|MQTT]] {{topic|topic}} filters. `+` matches exactly one level (`sensor/+/temp` covers `sensor/kitchen/temp` but not `sensor/kitchen/inner/temp`); `#` matches zero or more remaining levels and must be the final character (`sensor/#`).', + category: 'messaging' }, { - id: 'fanout-exchange', - term: 'Fanout exchange', - definition: - "[[amqp|AMQP]] {{exchange|exchange}} type that ignores the {{routing-key|routing key}} and delivers every published message to every queue bound to it. Use it for broadcast notifications where each consumer needs its own copy.", - category: 'messaging' + id: 'fanout-exchange', + term: 'Fanout exchange', + definition: + '[[amqp|AMQP]] {{exchange|exchange}} type that ignores the {{routing-key|routing key}} and delivers every published message to every queue bound to it. Use it for broadcast notifications where each consumer needs its own copy.', + category: 'messaging' }, { - id: 'direct-exchange', - term: 'Direct exchange', - definition: - "[[amqp|AMQP]] {{exchange|exchange}} type that delivers a message to queues whose binding key exactly matches the message's {{routing-key|routing key}}. Default routing for point-to-point work queues.", - category: 'messaging' + id: 'direct-exchange', + term: 'Direct exchange', + definition: + "[[amqp|AMQP]] {{exchange|exchange}} type that delivers a message to queues whose binding key exactly matches the message's {{routing-key|routing key}}. Default routing for point-to-point work queues.", + category: 'messaging' }, { - id: 'topic-exchange', - term: 'Topic exchange', - definition: - "[[amqp|AMQP]] {{exchange|exchange}} type that matches dotted {{routing-key|routing keys}} against patterns with `*` (one word) and `#` (zero or more words). Lets consumers subscribe to slices of a hierarchical event stream.", - category: 'messaging' + id: 'topic-exchange', + term: 'Topic exchange', + definition: + '[[amqp|AMQP]] {{exchange|exchange}} type that matches dotted {{routing-key|routing keys}} against patterns with `*` (one word) and `#` (zero or more words). Lets consumers subscribe to slices of a hierarchical event stream.', + category: 'messaging' }, { - id: 'headers-exchange', - term: 'Headers exchange', - definition: - "[[amqp|AMQP]] {{exchange|exchange}} type that routes on a dictionary of message headers instead of the {{routing-key|routing key}}. Bindings specify `x-match=all` (every header must match) or `x-match=any`.", - category: 'messaging' + id: 'headers-exchange', + term: 'Headers exchange', + definition: + '[[amqp|AMQP]] {{exchange|exchange}} type that routes on a dictionary of message headers instead of the {{routing-key|routing key}}. Bindings specify `x-match=all` (every header must match) or `x-match=any`.', + category: 'messaging' }, { - id: 'durable-queue', - term: 'Durable queue', - definition: - "A queue whose definition survives a {{broker|broker}} restart. Paired with persistent messages (written to disk), it provides at-least-once delivery across crashes β€” at the cost of disk I/O on every publish.", - category: 'messaging' + id: 'durable-queue', + term: 'Durable queue', + definition: + 'A queue whose definition survives a {{broker|broker}} restart. Paired with persistent messages (written to disk), it provides at-least-once delivery across crashes β€” at the cost of disk I/O on every publish.', + category: 'messaging' }, { - id: 'nack', - term: 'NACK (Negative Acknowledgement)', - definition: - "Signal that a consumer could not process a message. In [[amqp|AMQP]] (`basic.nack`) the {{broker|broker}} may requeue the message or route it to a {{dead-letter-queue|dead-letter queue}}; in [[mqtt|MQTT]] 5 a PUBACK can carry a non-success reason code. Opposite of {{ack|ACK}}.", - category: 'messaging' + id: 'nack', + term: 'NACK (Negative Acknowledgement)', + definition: + 'Signal that a consumer could not process a message. In [[amqp|AMQP]] (`basic.nack`) the {{broker|broker}} may requeue the message or route it to a {{dead-letter-queue|dead-letter queue}}; in [[mqtt|MQTT]] 5 a PUBACK can carry a non-success reason code. Opposite of {{ack|ACK}}.', + category: 'messaging' }, { - id: 'stomp-frame', - term: 'STOMP frame', - definition: - "Wire unit of [[stomp|STOMP]]: a command word (`CONNECT`, `SEND`, `SUBSCRIBE`, ...), zero or more `Header: value` lines, a blank line, an optional body, and a terminating `\\0` (null) byte. Plain text β€” debuggable with `telnet`.", - category: 'messaging' + id: 'stomp-frame', + term: 'STOMP frame', + definition: + 'Wire unit of [[stomp|STOMP]]: a command word (`CONNECT`, `SEND`, `SUBSCRIBE`, ...), zero or more `Header: value` lines, a blank line, an optional body, and a terminating `\\0` (null) byte. Plain text β€” debuggable with `telnet`.', + category: 'messaging' }, { - id: 'sasl', - term: 'SASL (Simple Authentication and Security Layer)', - definition: - "Framework defining a family of authentication mechanisms (PLAIN, SCRAM, GSSAPI, OAUTHBEARER, ...) that protocols like [[xmpp|XMPP]], [[smtp|SMTP]], [[imap|IMAP]] and LDAP can negotiate. Separates *how to prove identity* from the application protocol.", - category: 'security' + id: 'sasl', + term: 'SASL (Simple Authentication and Security Layer)', + definition: + 'Framework defining a family of authentication mechanisms (PLAIN, SCRAM, GSSAPI, OAUTHBEARER, ...) that protocols like [[xmpp|XMPP]], [[smtp|SMTP]], [[imap|IMAP]] and LDAP can negotiate. Separates *how to prove identity* from the application protocol.', + category: 'security' }, { - id: 'scram', - term: 'SCRAM (Salted Challenge Response Auth)', - definition: - "{{sasl|SASL}} mechanism in which the server stores a salted hash of the password and proves knowledge via a challenge-response exchange. The plaintext password never crosses the wire and the server never learns it. Default for modern [[xmpp|XMPP]], MongoDB, and PostgreSQL.", - category: 'security' + id: 'scram', + term: 'SCRAM (Salted Challenge Response Auth)', + definition: + '{{sasl|SASL}} mechanism in which the server stores a salted hash of the password and proves knowledge via a challenge-response exchange. The plaintext password never crosses the wire and the server never learns it. Default for modern [[xmpp|XMPP]], MongoDB, and PostgreSQL.', + category: 'security' }, { - id: 'xmpp-stream', - term: 'XML stream (XMPP)', - definition: - "An [[xmpp|XMPP]] session is a single long-lived XML document. Each side opens with `<stream:stream>` and appends `<message>`, `<presence>`, and `<iq>` stanzas until shutdown. The document is closed with `</stream:stream>`.", - category: 'messaging' + id: 'xmpp-stream', + term: 'XML stream (XMPP)', + definition: + 'An [[xmpp|XMPP]] session is a single long-lived XML document. Each side opens with `<stream:stream>` and appends `<message>`, `<presence>`, and `<iq>` stanzas until shutdown. The document is closed with `</stream:stream>`.', + category: 'messaging' }, { - id: 'xmpp-presence', - term: 'Presence stanza (XMPP)', - definition: - "An [[xmpp|XMPP]] `<presence/>` stanza broadcasts a user's availability (online, away, do-not-disturb) to subscribed contacts. The mechanism behind buddy-list status indicators.", - category: 'messaging' + id: 'xmpp-presence', + term: 'Presence stanza (XMPP)', + definition: + "An [[xmpp|XMPP]] `<presence/>` stanza broadcasts a user's availability (online, away, do-not-disturb) to subscribed contacts. The mechanism behind buddy-list status indicators.", + category: 'messaging' }, { - id: 'xmpp-resource', - term: 'JID resource binding', - definition: - "After [[xmpp|XMPP]] authentication the server assigns a per-connection *resource* suffix to the bare JID (`alice@example.com` β†’ `alice@example.com/phone`). Lets one account stay connected from multiple devices and routes stanzas to the right one.", - category: 'messaging' + id: 'xmpp-resource', + term: 'JID resource binding', + definition: + 'After [[xmpp|XMPP]] authentication the server assigns a per-connection *resource* suffix to the bare JID (`alice@example.com` β†’ `alice@example.com/phone`). Lets one account stay connected from multiple devices and routes stanzas to the right one.', + category: 'messaging' }, { - id: 'federation', - term: 'Federation', - definition: - "Architecture where independent servers in different domains interoperate by relaying messages directly to each other β€” no central hub. Used by [[smtp|SMTP]] email, [[xmpp|XMPP]], Matrix, and ActivityPub.", - category: 'messaging' + id: 'federation', + term: 'Federation', + definition: + 'Architecture where independent servers in different domains interoperate by relaying messages directly to each other β€” no central hub. Used by [[smtp|SMTP]] email, [[xmpp|XMPP]], Matrix, and ActivityPub.', + category: 'messaging' }, { - id: 'omemo', - term: 'OMEMO', - definition: - "End-to-end encryption extension for [[xmpp|XMPP]] based on the Signal Double Ratchet. Provides forward secrecy and multi-device support layered on top of the normal {{starttls|TLS}}-protected stream.", - category: 'security' + id: 'omemo', + term: 'OMEMO', + definition: + 'End-to-end encryption extension for [[xmpp|XMPP]] based on the Signal Double Ratchet. Provides forward secrecy and multi-device support layered on top of the normal {{starttls|TLS}}-protected stream.', + category: 'security' }, { - id: 'coap-confirmable', - term: 'Confirmable / Non-confirmable (CoAP)', - definition: - "[[coap|CoAP]] message types. `CON` requires an explicit {{ack|ACK}} from the peer β€” reliable like [[tcp|TCP]] but per-message. `NON` is fire-and-forget, used for repeating sensor readings where a single drop is harmless.", - category: 'messaging' + id: 'coap-confirmable', + term: 'Confirmable / Non-confirmable (CoAP)', + definition: + '[[coap|CoAP]] message types. `CON` requires an explicit {{ack|ACK}} from the peer β€” reliable like [[tcp|TCP]] but per-message. `NON` is fire-and-forget, used for repeating sensor readings where a single drop is harmless.', + category: 'messaging' }, { - id: 'coap-observe', - term: 'Observe (CoAP)', - definition: - "[[coap|CoAP]] extension where a client registers interest in a resource and the server pushes a new representation each time the value changes, with a monotonically-increasing sequence number. Lets battery-powered devices sleep instead of polling.", - category: 'messaging' + id: 'coap-observe', + term: 'Observe (CoAP)', + definition: + '[[coap|CoAP]] extension where a client registers interest in a resource and the server pushes a new representation each time the value changes, with a monotonically-increasing sequence number. Lets battery-powered devices sleep instead of polling.', + category: 'messaging' }, { - id: 'kafka-partition-leader', - term: 'Partition leader (Kafka)', - definition: - "One broker per {{partition|partition}} that serves all reads and writes for that partition; the others are followers that replicate it. Failure of the leader triggers an election so a replica takes over. Producers and consumers are routed to leaders via the cluster metadata.", - category: 'messaging' + id: 'kafka-partition-leader', + term: 'Partition leader (Kafka)', + definition: + 'One broker per {{partition|partition}} that serves all reads and writes for that partition; the others are followers that replicate it. Failure of the leader triggers an election so a replica takes over. Producers and consumers are routed to leaders via the cluster metadata.', + category: 'messaging' }, { - id: 'kafka-acks', - term: 'acks=0/1/all (Kafka)', - definition: - "Kafka producer durability setting. `acks=0` β€” fire-and-forget, no acknowledgement; `acks=1` β€” leader has written; `acks=all` β€” every in-sync replica has written. Pick the durability vs latency trade-off explicitly.", - category: 'messaging' + id: 'kafka-acks', + term: 'acks=0/1/all (Kafka)', + definition: + 'Kafka producer durability setting. `acks=0` β€” fire-and-forget, no acknowledgement; `acks=1` β€” leader has written; `acks=all` β€” every in-sync replica has written. Pick the durability vs latency trade-off explicitly.', + category: 'messaging' }, { - id: 'kafka-offset-commit', - term: 'OffsetCommit (Kafka)', - definition: - "Kafka consumer message that records *group X has processed up to offset N in partition P*. Stored in the internal `__consumer_offsets` topic. On consumer crash, another member of the {{consumer-group|consumer group}} resumes from the committed offset.", - category: 'messaging' + id: 'kafka-offset-commit', + term: 'OffsetCommit (Kafka)', + definition: + 'Kafka consumer message that records *group X has processed up to offset N in partition P*. Stored in the internal `__consumer_offsets` topic. On consumer crash, another member of the {{consumer-group|consumer group}} resumes from the committed offset.', + category: 'messaging' }, { - id: 'consumer-rebalance', - term: 'Consumer rebalance', - definition: - "When a Kafka {{consumer-group|consumer group}} gains or loses members, partition assignments are redistributed so every {{partition|partition}} is owned by exactly one consumer. Each consumer resumes from the last committed {{offset|offset}}.", - category: 'messaging' + id: 'consumer-rebalance', + term: 'Consumer rebalance', + definition: + 'When a Kafka {{consumer-group|consumer group}} gains or loses members, partition assignments are redistributed so every {{partition|partition}} is owned by exactly one consumer. Each consumer resumes from the last committed {{offset|offset}}.', + category: 'messaging' }, { - id: 'log-replay', - term: 'Log replay', - definition: - "Reading messages from a position earlier than the current tail of an append-only log (e.g. [[kafka|Kafka]]). Because the log is immutable, replay is just *reset the {{offset|offset}}* β€” used for re-processing, debugging, and bootstrapping new consumers.", - category: 'messaging' + id: 'log-replay', + term: 'Log replay', + definition: + 'Reading messages from a position earlier than the current tail of an append-only log (e.g. [[kafka|Kafka]]). Because the log is immutable, replay is just *reset the {{offset|offset}}* β€” used for re-processing, debugging, and bootstrapping new consumers.', + category: 'messaging' }, { - id: 'mta', - term: 'MTA (Mail Transfer Agent)', - definition: - "A server that accepts, queues, and forwards [[smtp|SMTP]] mail β€” Postfix, Sendmail, Exim, MS Exchange. Mail hops MTA-to-MTA until it reaches the recipient's mailbox.", - category: 'messaging' + id: 'mta', + term: 'MTA (Mail Transfer Agent)', + definition: + "A server that accepts, queues, and forwards [[smtp|SMTP]] mail β€” Postfix, Sendmail, Exim, MS Exchange. Mail hops MTA-to-MTA until it reaches the recipient's mailbox.", + category: 'messaging' }, { - id: 'mx-record', - term: 'MX record', - definition: - "[[dns|DNS]] record type listing the {{mta|mail servers}} responsible for a domain, each with a priority. Sending {{mta|MTAs}} look up the recipient's MX before delivering [[smtp|SMTP]] mail.", - category: 'messaging' + id: 'mx-record', + term: 'MX record', + definition: + "[[dns|DNS]] record type listing the {{mta|mail servers}} responsible for a domain, each with a priority. Sending {{mta|MTAs}} look up the recipient's MX before delivering [[smtp|SMTP]] mail.", + category: 'messaging' }, { - id: 'ptr-record', - term: 'PTR record', - definition: - "[[dns|DNS]] record mapping a name to another name. In reverse DNS, PTRs map an IP back to a hostname; in [[mdns-dns-sd|DNS-SD]], a PTR for `_service._tcp.local` lists the instance names offering that service.", - category: 'infrastructure' + id: 'ptr-record', + term: 'PTR record', + definition: + '[[dns|DNS]] record mapping a name to another name. In reverse DNS, PTRs map an IP back to a hostname; in [[mdns-dns-sd|DNS-SD]], a PTR for `_service._tcp.local` lists the instance names offering that service.', + category: 'infrastructure' }, { - id: 'srv-record', - term: 'SRV record', - definition: - "[[dns|DNS]] record giving the hostname and port for a named service plus priority and weight. Used by [[mdns-dns-sd|DNS-SD]], [[sip|SIP]], [[xmpp|XMPP]] server-to-server lookup, and Active Directory.", - category: 'infrastructure' + id: 'srv-record', + term: 'SRV record', + definition: + '[[dns|DNS]] record giving the hostname and port for a named service plus priority and weight. Used by [[mdns-dns-sd|DNS-SD]], [[sip|SIP]], [[xmpp|XMPP]] server-to-server lookup, and Active Directory.', + category: 'infrastructure' }, { - id: 'txt-record', - term: 'TXT record', - definition: - "[[dns|DNS]] record carrying arbitrary text. Used to publish SPF/DKIM/DMARC email-authentication policies, [[mdns-dns-sd|DNS-SD]] service metadata, and ownership-verification tokens.", - category: 'infrastructure' + id: 'txt-record', + term: 'TXT record', + definition: + '[[dns|DNS]] record carrying arbitrary text. Used to publish SPF/DKIM/DMARC email-authentication policies, [[mdns-dns-sd|DNS-SD]] service metadata, and ownership-verification tokens.', + category: 'infrastructure' }, { - id: 'spf', - term: 'SPF (Sender Policy Framework)', - definition: - "Email-authentication mechanism in which a domain publishes a {{txt-record|TXT record}} listing the IPs allowed to send mail on its behalf. Receiving {{mta|MTAs}} reject or flag messages from other sources.", - category: 'security' + id: 'spf', + term: 'SPF (Sender Policy Framework)', + definition: + 'Email-authentication mechanism in which a domain publishes a {{txt-record|TXT record}} listing the IPs allowed to send mail on its behalf. Receiving {{mta|MTAs}} reject or flag messages from other sources.', + category: 'security' }, { - id: 'dkim', - term: 'DKIM (DomainKeys Identified Mail)', - definition: - "Sending {{mta|MTA}} signs selected headers + body with a private key; receivers fetch the public key from a {{txt-record|TXT record}} and verify. Proves the message wasn't modified in transit and really came from the claimed domain.", - category: 'security' + id: 'dkim', + term: 'DKIM (DomainKeys Identified Mail)', + definition: + "Sending {{mta|MTA}} signs selected headers + body with a private key; receivers fetch the public key from a {{txt-record|TXT record}} and verify. Proves the message wasn't modified in transit and really came from the claimed domain.", + category: 'security' }, { - id: 'dmarc', - term: 'DMARC', - definition: - "Policy layer on top of {{spf|SPF}} and {{dkim|DKIM}}. A domain publishes a {{txt-record|TXT record}} telling receivers *reject / quarantine / monitor* mail that fails authentication and aggregates failure reports back to the domain owner.", - category: 'security' + id: 'dmarc', + term: 'DMARC', + definition: + 'Policy layer on top of {{spf|SPF}} and {{dkim|DKIM}}. A domain publishes a {{txt-record|TXT record}} telling receivers *reject / quarantine / monitor* mail that fails authentication and aggregates failure reports back to the domain owner.', + category: 'security' }, { - id: 'smtp-envelope', - term: 'SMTP envelope', - definition: - "The `MAIL FROM` and `RCPT TO` addresses used by [[smtp|SMTP]] to deliver a message. Separate from the `From:` / `To:` headers shown to humans β€” like the address on a letter's envelope vs the heading inside.", - category: 'messaging' + id: 'smtp-envelope', + term: 'SMTP envelope', + definition: + "The `MAIL FROM` and `RCPT TO` addresses used by [[smtp|SMTP]] to deliver a message. Separate from the `From:` / `To:` headers shown to humans β€” like the address on a letter's envelope vs the heading inside.", + category: 'messaging' }, { - id: 'store-and-forward', - term: 'Store-and-forward', - definition: - "Each hop accepts full responsibility for a message: it commits it to durable storage, then attempts to forward to the next hop with retries. Originating from telegraph relay, it's how [[smtp|SMTP]] email, [[xmpp|XMPP]] federation, and many message queues survive intermittent links.", - category: 'messaging' + id: 'store-and-forward', + term: 'Store-and-forward', + definition: + "Each hop accepts full responsibility for a message: it commits it to durable storage, then attempts to forward to the next hop with retries. Originating from telegraph relay, it's how [[smtp|SMTP]] email, [[xmpp|XMPP]] federation, and many message queues survive intermittent links.", + category: 'messaging' }, { - id: 'pop3', - term: 'POP3 (Post Office Protocol)', - definition: - "Pre-[[imap|IMAP]] mail-retrieval protocol that downloads messages and (by default) deletes them from the server. Simple but offers no server-side state, so multiple clients see different mailboxes.", - category: 'messaging' + id: 'pop3', + term: 'POP3 (Post Office Protocol)', + definition: + 'Pre-[[imap|IMAP]] mail-retrieval protocol that downloads messages and (by default) deletes them from the server. Simple but offers no server-side state, so multiple clients see different mailboxes.', + category: 'messaging' }, { - id: 'imap-idle', - term: 'IDLE (IMAP)', - definition: - "[[imap|IMAP]] command that parks a connection in waiting mode. The server may then push untagged updates (new message arrived, flags changed) without the client polling. Foundation of *push email* on mobile.", - category: 'messaging' + id: 'imap-idle', + term: 'IDLE (IMAP)', + definition: + '[[imap|IMAP]] command that parks a connection in waiting mode. The server may then push untagged updates (new message arrived, flags changed) without the client polling. Foundation of *push email* on mobile.', + category: 'messaging' }, { - id: 'imap-fetch', - term: 'FETCH (IMAP)', - definition: - "[[imap|IMAP]] command to download specific parts of a message (`ENVELOPE`, `BODY[HEADER]`, `BODY[TEXT]`, a particular MIME part) without pulling the whole thing. Lets clients show headers fast and load attachments on demand.", - category: 'messaging' + id: 'imap-fetch', + term: 'FETCH (IMAP)', + definition: + '[[imap|IMAP]] command to download specific parts of a message (`ENVELOPE`, `BODY[HEADER]`, `BODY[TEXT]`, a particular MIME part) without pulling the whole thing. Lets clients show headers fast and load attachments on demand.', + category: 'messaging' }, { - id: 'imap-select', - term: 'SELECT (IMAP)', - definition: - "[[imap|IMAP]] command that opens a mailbox (e.g. `INBOX`) for read-write access. The server immediately pushes its current state β€” message count, recent count, validity tags.", - category: 'messaging' + id: 'imap-select', + term: 'SELECT (IMAP)', + definition: + '[[imap|IMAP]] command that opens a mailbox (e.g. `INBOX`) for read-write access. The server immediately pushes its current state β€” message count, recent count, validity tags.', + category: 'messaging' }, { - id: 'imap-tag', - term: 'IMAP tag', - definition: - "Client-chosen identifier (`A001`, `A002`, ...) prefixed to each [[imap|IMAP]] command. The server's tagged response uses the same tag, so responses can come back out of order without confusion. Untagged responses (starting with `*`) are server-initiated.", - category: 'messaging' + id: 'imap-tag', + term: 'IMAP tag', + definition: + "Client-chosen identifier (`A001`, `A002`, ...) prefixed to each [[imap|IMAP]] command. The server's tagged response uses the same tag, so responses can come back out of order without confusion. Untagged responses (starting with `*`) are server-initiated.", + category: 'messaging' }, { - id: 'imaps', - term: 'IMAPS', - definition: - "[[imap|IMAP]] wrapped in [[tls|TLS]] from the first byte, conventionally on port 993. The implicit-TLS alternative to negotiating {{starttls|STARTTLS}} on port 143.", - category: 'security' + id: 'imaps', + term: 'IMAPS', + definition: + '[[imap|IMAP]] wrapped in [[tls|TLS]] from the first byte, conventionally on port 993. The implicit-TLS alternative to negotiating {{starttls|STARTTLS}} on port 143.', + category: 'security' }, { - id: 'ftp-active-passive', - term: 'FTP active vs passive mode', - definition: - "How [[ftp|FTP]] sets up the data channel. *Active* β€” server opens a TCP connection back to the client (broken behind {{nat|NAT}} or {{firewall|firewall}}). *Passive* (`PASV`) β€” server listens on a new port and tells the client to connect to it. PASV is the modern default.", - category: 'messaging' + id: 'ftp-active-passive', + term: 'FTP active vs passive mode', + definition: + 'How [[ftp|FTP]] sets up the data channel. *Active* β€” server opens a TCP connection back to the client (broken behind {{nat|NAT}} or {{firewall|firewall}}). *Passive* (`PASV`) β€” server listens on a new port and tells the client to connect to it. PASV is the modern default.', + category: 'messaging' }, { - id: 'ftps', - term: 'FTPS', - definition: - "[[ftp|FTP]] over [[tls|TLS]]. The control channel is encrypted via {{starttls|AUTH TLS}}, and the data channel is opened inside TLS as well. Not to be confused with SFTP, which is file transfer over [[ssh|SSH]] and shares only the name.", - category: 'security' + id: 'ftps', + term: 'FTPS', + definition: + '[[ftp|FTP]] over [[tls|TLS]]. The control channel is encrypted via {{starttls|AUTH TLS}}, and the data channel is opened inside TLS as well. Not to be confused with SFTP, which is file transfer over [[ssh|SSH]] and shares only the name.', + category: 'security' }, { - id: 'sftp', - term: 'SFTP', - definition: - "SSH File Transfer Protocol β€” a file-management subsystem of [[ssh|SSH]], unrelated to [[ftp|FTP]] despite the name. Single port (22), no separate data channel, authenticated by SSH keys.", - category: 'security' + id: 'sftp', + term: 'SFTP', + definition: + 'SSH File Transfer Protocol β€” a file-management subsystem of [[ssh|SSH]], unrelated to [[ftp|FTP]] despite the name. Single port (22), no separate data channel, authenticated by SSH keys.', + category: 'security' }, { - id: 'mdns-probe', - term: 'mDNS probe', - definition: - "First step of joining an [[mdns-dns-sd|mDNS]] link: the host sends three Query messages 250 ms apart for its candidate name. If any host claims that name, the prober picks a different one (`-2`, `-3`) and starts over.", - category: 'infrastructure' + id: 'mdns-probe', + term: 'mDNS probe', + definition: + 'First step of joining an [[mdns-dns-sd|mDNS]] link: the host sends three Query messages 250 ms apart for its candidate name. If any host claims that name, the prober picks a different one (`-2`, `-3`) and starts over.', + category: 'infrastructure' }, { - id: 'mdns-announce', - term: 'mDNS announce', - definition: - "After a successful probe an [[mdns-dns-sd|mDNS]] host sends two Response messages 1 s apart with the cache-flush bit set, so every listener replaces any stale entries for the new owner's records.", - category: 'infrastructure' + id: 'mdns-announce', + term: 'mDNS announce', + definition: + "After a successful probe an [[mdns-dns-sd|mDNS]] host sends two Response messages 1 s apart with the cache-flush bit set, so every listener replaces any stale entries for the new owner's records.", + category: 'infrastructure' }, { - id: 'mdns-goodbye', - term: 'mDNS goodbye', - definition: - "At graceful shutdown an [[mdns-dns-sd|mDNS]] host sends a Response with `TTL=0` for every record it owns; receivers flush those entries immediately instead of waiting for the normal {{ttl|TTL}} to expire.", - category: 'infrastructure' + id: 'mdns-goodbye', + term: 'mDNS goodbye', + definition: + 'At graceful shutdown an [[mdns-dns-sd|mDNS]] host sends a Response with `TTL=0` for every record it owns; receivers flush those entries immediately instead of waiting for the normal {{ttl|TTL}} to expire.', + category: 'infrastructure' }, { - id: 'cache-flush-bit', - term: 'Cache-flush bit (mDNS)', - definition: - "Per-record bit in [[mdns-dns-sd|mDNS]] responses that tells receivers *replace any cached records with this name and type with this new one*. Used during announce so a renaming or moving service is reflected everywhere on the link immediately.", - category: 'infrastructure' + id: 'cache-flush-bit', + term: 'Cache-flush bit (mDNS)', + definition: + 'Per-record bit in [[mdns-dns-sd|mDNS]] responses that tells receivers *replace any cached records with this name and type with this new one*. Used during announce so a renaming or moving service is reflected everywhere on the link immediately.', + category: 'infrastructure' }, { - id: 'ipp', - term: 'IPP (Internet Printing Protocol)', - definition: - "[[http1|HTTP]]-based protocol (port 631) for submitting print jobs and querying printer status. Discovered on local networks via [[mdns-dns-sd|DNS-SD]] under `_ipp._tcp.local`.", - category: 'infrastructure' + id: 'ipp', + term: 'IPP (Internet Printing Protocol)', + definition: + '[[http1|HTTP]]-based protocol (port 631) for submitting print jobs and querying printer status. Discovered on local networks via [[mdns-dns-sd|DNS-SD]] under `_ipp._tcp.local`.', + category: 'infrastructure' }, { - id: 'mpeg-ts', - term: 'MPEG-2 Transport Stream (.ts)', - definition: - "Container format originally for digital broadcast TV that packs audio, video, and metadata into 188-byte packets. In [[hls|HLS]] streaming, each ~6-second segment is a `.ts` file delivered as a standalone {{http-method|HTTP GET}} β€” cacheable by any {{cdn|CDN}}.", - wikiUrl: 'https://en.wikipedia.org/wiki/MPEG_transport_stream', - category: 'web' + id: 'mpeg-ts', + term: 'MPEG-2 Transport Stream (.ts)', + definition: + 'Container format originally for digital broadcast TV that packs audio, video, and metadata into 188-byte packets. In [[hls|HLS]] streaming, each ~6-second segment is a `.ts` file delivered as a standalone {{http-method|HTTP GET}} β€” cacheable by any {{cdn|CDN}}.', + wikiUrl: 'https://en.wikipedia.org/wiki/MPEG_transport_stream', + category: 'web' }, { - id: 'abr-segment-switch', - term: 'ABR Segment Boundary Switch', - definition: - "In {{adaptive-bitrate|adaptive bitrate}} streaming ([[hls|HLS]] / [[dash|DASH]]), the player can switch quality levels only at segment boundaries β€” never mid-segment. Each segment is a fully-decodable, self-contained chunk, so swapping in a different bitrate for the next segment is seamless to the viewer.", - category: 'web' + id: 'abr-segment-switch', + term: 'ABR Segment Boundary Switch', + definition: + 'In {{adaptive-bitrate|adaptive bitrate}} streaming ([[hls|HLS]] / [[dash|DASH]]), the player can switch quality levels only at segment boundaries β€” never mid-segment. Each segment is a fully-decodable, self-contained chunk, so swapping in a different bitrate for the next segment is seamless to the viewer.', + category: 'web' }, { - id: 'rtmp-c0-c1-c2', - term: 'RTMP C0 / C1 / C2', - definition: - "The three client-to-server messages of the [[rtmp|RTMP]] {{handshake|handshake}}. **C0** = a single protocol-version byte (0x03 for plain [[rtmp|RTMP]], 0x06 for RTMPE). **C1** = 1,536 random bytes plus the client timestamp. **C2** is a verbatim echo of {{rtmp-s0-s1-s2|S1}} β€” proving the client received it.", - wikiUrl: 'https://en.wikipedia.org/wiki/Real-Time_Messaging_Protocol', - category: 'web' + id: 'rtmp-c0-c1-c2', + term: 'RTMP C0 / C1 / C2', + definition: + 'The three client-to-server messages of the [[rtmp|RTMP]] {{handshake|handshake}}. **C0** = a single protocol-version byte (0x03 for plain [[rtmp|RTMP]], 0x06 for RTMPE). **C1** = 1,536 random bytes plus the client timestamp. **C2** is a verbatim echo of {{rtmp-s0-s1-s2|S1}} β€” proving the client received it.', + wikiUrl: 'https://en.wikipedia.org/wiki/Real-Time_Messaging_Protocol', + category: 'web' }, { - id: 'rtmp-s0-s1-s2', - term: 'RTMP S0 / S1 / S2', - definition: - "Server-side counterparts of {{rtmp-c0-c1-c2|C0/C1/C2}} in the [[rtmp|RTMP]] {{handshake|handshake}}. **S0** = protocol version byte, **S1** = 1,536 random bytes plus server timestamp, **S2** = echo of {{rtmp-c0-c1-c2|C1}}. Once both sides have verified the echoes match, the {{handshake|handshake}} completes.", - wikiUrl: 'https://en.wikipedia.org/wiki/Real-Time_Messaging_Protocol', - category: 'web' + id: 'rtmp-s0-s1-s2', + term: 'RTMP S0 / S1 / S2', + definition: + 'Server-side counterparts of {{rtmp-c0-c1-c2|C0/C1/C2}} in the [[rtmp|RTMP]] {{handshake|handshake}}. **S0** = protocol version byte, **S1** = 1,536 random bytes plus server timestamp, **S2** = echo of {{rtmp-c0-c1-c2|C1}}. Once both sides have verified the echoes match, the {{handshake|handshake}} completes.', + wikiUrl: 'https://en.wikipedia.org/wiki/Real-Time_Messaging_Protocol', + category: 'web' }, { - id: 'rtmp-connect', - term: 'RTMP connect', - definition: - "First AMF0-encoded command after the [[rtmp|RTMP]] {{handshake|handshake}}. Specifies the application path on the server (e.g., `live`) and may carry optional auth parameters. The server replies with `_result` (success) or `_error`.", - category: 'web' + id: 'rtmp-connect', + term: 'RTMP connect', + definition: + 'First AMF0-encoded command after the [[rtmp|RTMP]] {{handshake|handshake}}. Specifies the application path on the server (e.g., `live`) and may carry optional auth parameters. The server replies with `_result` (success) or `_error`.', + category: 'web' }, { - id: 'rtmp-create-stream', - term: 'RTMP createStream', - definition: - "AMF0 command sent after [[rtmp|RTMP]] {{rtmp-connect|connect}}. Allocates a logical stream ID within the connection β€” [[rtmp|RTMP]] can {{multiplexing|multiplex}} multiple streams, though {{live-stream-ingest|live ingest}} typically uses one.", - category: 'web' + id: 'rtmp-create-stream', + term: 'RTMP createStream', + definition: + 'AMF0 command sent after [[rtmp|RTMP]] {{rtmp-connect|connect}}. Allocates a logical stream ID within the connection β€” [[rtmp|RTMP]] can {{multiplexing|multiplex}} multiple streams, though {{live-stream-ingest|live ingest}} typically uses one.', + category: 'web' }, { - id: 'rtmp-publish', - term: 'RTMP publish', - definition: - "AMF0 command that begins pushing audio/video to the server. Takes a {{rtmp-stream-key|stream key}} (the secret token authorising the upload) and a publish type (`live`, `record`, or `append`).", - category: 'web' + id: 'rtmp-publish', + term: 'RTMP publish', + definition: + 'AMF0 command that begins pushing audio/video to the server. Takes a {{rtmp-stream-key|stream key}} (the secret token authorising the upload) and a publish type (`live`, `record`, or `append`).', + category: 'web' }, { - id: 'rtmp-stream-key', - term: 'RTMP Stream Key', - definition: - "The opaque secret token your live encoder (OBS, Wirecast) embeds in the [[rtmp|RTMP]] {{rtmp-publish|publish}} request. Identifies *which channel* the encoder is pushing to and authorises the upload β€” treat it like a password; anyone with the key can hijack your stream.", - category: 'web' + id: 'rtmp-stream-key', + term: 'RTMP Stream Key', + definition: + 'The opaque secret token your live encoder (OBS, Wirecast) embeds in the [[rtmp|RTMP]] {{rtmp-publish|publish}} request. Identifies *which channel* the encoder is pushing to and authorises the upload β€” treat it like a password; anyone with the key can hijack your stream.', + category: 'web' }, { - id: 'live-stream-ingest', - term: 'Live-Stream Ingest', - definition: - "The pipeline that accepts a live video feed from an encoder and prepares it for distribution. The encoder pushes via [[rtmp|RTMP]] (or SRT/WebRTC) to a {{cdn|CDN}} ingest endpoint; the server then {{transcoding|transcodes}} into [[hls|HLS]] / [[dash|DASH]] segments for viewer playback.", - category: 'web' + id: 'live-stream-ingest', + term: 'Live-Stream Ingest', + definition: + 'The pipeline that accepts a live video feed from an encoder and prepares it for distribution. The encoder pushes via [[rtmp|RTMP]] (or SRT/WebRTC) to a {{cdn|CDN}} ingest endpoint; the server then {{transcoding|transcodes}} into [[hls|HLS]] / [[dash|DASH]] segments for viewer playback.', + category: 'web' }, { - id: 'transcoding', - term: 'Transcoding', - definition: - "Re-encoding a media stream from one {{codec|codec}} or bitrate to another. In live streaming, a {{cdn|CDN}} typically transcodes the [[rtmp|RTMP]] ingest into multiple [[hls|HLS]] / [[dash|DASH]] quality variants ({{adaptive-bitrate|adaptive bitrate}}) so players can switch based on {{bandwidth|bandwidth}}.", - wikiUrl: 'https://en.wikipedia.org/wiki/Transcoding', - category: 'web' + id: 'transcoding', + term: 'Transcoding', + definition: + 'Re-encoding a media stream from one {{codec|codec}} or bitrate to another. In live streaming, a {{cdn|CDN}} typically transcodes the [[rtmp|RTMP]] ingest into multiple [[hls|HLS]] / [[dash|DASH]] quality variants ({{adaptive-bitrate|adaptive bitrate}}) so players can switch based on {{bandwidth|bandwidth}}.', + wikiUrl: 'https://en.wikipedia.org/wiki/Transcoding', + category: 'web' }, { - id: 'aac', - term: 'AAC (Advanced Audio Coding)', - definition: - "Lossy audio {{codec|codec}} that superseded MP3 β€” used by virtually every modern streaming service (YouTube, Apple Music, Spotify Connect) and the default audio in [[rtmp|RTMP]] / [[hls|HLS]] / [[dash|DASH]] pipelines. Defined in MPEG-4 Part 3 (ISO/IEC 14496-3).", - wikiUrl: 'https://en.wikipedia.org/wiki/Advanced_Audio_Coding', - category: 'web' + id: 'aac', + term: 'AAC (Advanced Audio Coding)', + definition: + 'Lossy audio {{codec|codec}} that superseded MP3 β€” used by virtually every modern streaming service (YouTube, Apple Music, Spotify Connect) and the default audio in [[rtmp|RTMP]] / [[hls|HLS]] / [[dash|DASH]] pipelines. Defined in MPEG-4 Part 3 (ISO/IEC 14496-3).', + wikiUrl: 'https://en.wikipedia.org/wiki/Advanced_Audio_Coding', + category: 'web' }, { - id: 'h264', - term: 'H.264 / AVC', - definition: - "The dominant video {{codec|codec}} of the 2010s β€” Advanced Video Coding, MPEG-4 Part 10. Ships in virtually every camera, phone, browser, and streaming pipeline. Carried inside [[hls|HLS]] `.ts` segments and [[rtmp|RTMP]] chunks.", - wikiUrl: 'https://en.wikipedia.org/wiki/Advanced_Video_Coding', - category: 'web' + id: 'h264', + term: 'H.264 / AVC', + definition: + 'The dominant video {{codec|codec}} of the 2010s β€” Advanced Video Coding, MPEG-4 Part 10. Ships in virtually every camera, phone, browser, and streaming pipeline. Carried inside [[hls|HLS]] `.ts` segments and [[rtmp|RTMP]] chunks.', + wikiUrl: 'https://en.wikipedia.org/wiki/Advanced_Video_Coding', + category: 'web' }, { - id: 'h265', - term: 'H.265 / HEVC', - definition: - "High Efficiency Video Coding β€” successor to {{h264|H.264}} delivering roughly 2x compression at the same quality. Widely used for 4K [[hls|HLS]] / [[dash|DASH]] but with patent-licensing friction that opened the door for royalty-free alternatives like {{av1|AV1}}.", - wikiUrl: 'https://en.wikipedia.org/wiki/High_Efficiency_Video_Coding', - category: 'web' + id: 'h265', + term: 'H.265 / HEVC', + definition: + 'High Efficiency Video Coding β€” successor to {{h264|H.264}} delivering roughly 2x compression at the same quality. Widely used for 4K [[hls|HLS]] / [[dash|DASH]] but with patent-licensing friction that opened the door for royalty-free alternatives like {{av1|AV1}}.', + wikiUrl: 'https://en.wikipedia.org/wiki/High_Efficiency_Video_Coding', + category: 'web' }, { - id: 'vp9', - term: 'VP9', - definition: - "Royalty-free video {{codec|codec}} developed by {{google|Google}}. Comparable compression to {{h265|H.265}} but free of patent licensing; used heavily by YouTube. Carried in WebM and {{fragmented-mp4|fMP4}} containers for [[dash|DASH]] streaming.", - wikiUrl: 'https://en.wikipedia.org/wiki/VP9', - category: 'web' + id: 'vp9', + term: 'VP9', + definition: + 'Royalty-free video {{codec|codec}} developed by {{google|Google}}. Comparable compression to {{h265|H.265}} but free of patent licensing; used heavily by YouTube. Carried in WebM and {{fragmented-mp4|fMP4}} containers for [[dash|DASH]] streaming.', + wikiUrl: 'https://en.wikipedia.org/wiki/VP9', + category: 'web' }, { - id: 'av1', - term: 'AV1', - definition: - "Open, royalty-free video {{codec|codec}} from the Alliance for Open Media (Google, Netflix, Amazon, Apple). Roughly 30% better compression than {{h265|H.265}}. Native support in Chrome, Firefox, Safari 17+, and modern Android/iOS hardware decoders.", - wikiUrl: 'https://en.wikipedia.org/wiki/AV1', - category: 'web' + id: 'av1', + term: 'AV1', + definition: + 'Open, royalty-free video {{codec|codec}} from the Alliance for Open Media (Google, Netflix, Amazon, Apple). Roughly 30% better compression than {{h265|H.265}}. Native support in Chrome, Firefox, Safari 17+, and modern Android/iOS hardware decoders.', + wikiUrl: 'https://en.wikipedia.org/wiki/AV1', + category: 'web' }, { - id: 'fragmented-mp4', - term: 'Fragmented MP4 (fMP4)', - definition: - "An MP4 file split into independently-decodable fragments. Each `.m4s` segment in a [[dash|DASH]] stream (and modern [[hls|HLS]]) is one fragment β€” small enough to {{cdn|CDN}}-cache and quality-switch at the boundary. Built on {{isobmff|ISOBMFF}}.", - wikiUrl: 'https://en.wikipedia.org/wiki/ISO_base_media_file_format', - category: 'web' + id: 'fragmented-mp4', + term: 'Fragmented MP4 (fMP4)', + definition: + 'An MP4 file split into independently-decodable fragments. Each `.m4s` segment in a [[dash|DASH]] stream (and modern [[hls|HLS]]) is one fragment β€” small enough to {{cdn|CDN}}-cache and quality-switch at the boundary. Built on {{isobmff|ISOBMFF}}.', + wikiUrl: 'https://en.wikipedia.org/wiki/ISO_base_media_file_format', + category: 'web' }, { - id: 'isobmff', - term: 'ISOBMFF (ISO Base Media File Format)', - definition: - "ISO/IEC 14496-12 β€” the box-based container that underlies MP4, {{fragmented-mp4|fMP4}}, QuickTime, 3GP, and the segment format used by [[dash|DASH]] and CMAF [[hls|HLS]]. {{codec|Codec}}-agnostic: stores video, audio, subtitles, and metadata in nested boxes.", - wikiUrl: 'https://en.wikipedia.org/wiki/ISO_base_media_file_format', - category: 'web' + id: 'isobmff', + term: 'ISOBMFF (ISO Base Media File Format)', + definition: + 'ISO/IEC 14496-12 β€” the box-based container that underlies MP4, {{fragmented-mp4|fMP4}}, QuickTime, 3GP, and the segment format used by [[dash|DASH]] and CMAF [[hls|HLS]]. {{codec|Codec}}-agnostic: stores video, audio, subtitles, and metadata in nested boxes.', + wikiUrl: 'https://en.wikipedia.org/wiki/ISO_base_media_file_format', + category: 'web' }, { - id: 'dash-period', - term: 'DASH Period', - definition: - "Top-level segment of a [[dash|DASH]] {{mpd|MPD}} timeline β€” a single chapter of the presentation (e.g., main feature vs. ad break). Each Period contains one or more {{dash-adaptation-set|AdaptationSets}}.", - wikiUrl: 'https://en.wikipedia.org/wiki/Dynamic_Adaptive_Streaming_over_HTTP', - category: 'web' + id: 'dash-period', + term: 'DASH Period', + definition: + 'Top-level segment of a [[dash|DASH]] {{mpd|MPD}} timeline β€” a single chapter of the presentation (e.g., main feature vs. ad break). Each Period contains one or more {{dash-adaptation-set|AdaptationSets}}.', + wikiUrl: 'https://en.wikipedia.org/wiki/Dynamic_Adaptive_Streaming_over_HTTP', + category: 'web' }, { - id: 'dash-adaptation-set', - term: 'DASH AdaptationSet', - definition: - "A track within a [[dash|DASH]] {{dash-period|Period}} β€” typically *video*, *audio*, or *subtitle*. Contains multiple {{dash-representation|Representations}} that are alternative quality variants the player chooses between.", - category: 'web' + id: 'dash-adaptation-set', + term: 'DASH AdaptationSet', + definition: + 'A track within a [[dash|DASH]] {{dash-period|Period}} β€” typically *video*, *audio*, or *subtitle*. Contains multiple {{dash-representation|Representations}} that are alternative quality variants the player chooses between.', + category: 'web' }, { - id: 'dash-representation', - term: 'DASH Representation', - definition: - "A single quality variant inside a {{dash-adaptation-set|DASH AdaptationSet}} β€” e.g., the 720p version of the video track. The {{adaptive-bitrate|ABR}} algorithm switches between Representations as {{bandwidth|bandwidth}} changes.", - category: 'web' + id: 'dash-representation', + term: 'DASH Representation', + definition: + 'A single quality variant inside a {{dash-adaptation-set|DASH AdaptationSet}} β€” e.g., the 720p version of the video track. The {{adaptive-bitrate|ABR}} algorithm switches between Representations as {{bandwidth|bandwidth}} changes.', + category: 'web' }, { - id: 'abr-bola', - term: 'BOLA (Buffer Occupancy based Lyapunov Algorithm)', - definition: - "Buffer-based {{adaptive-bitrate|ABR}} algorithm that picks the next segment's quality based on how full the player's buffer is β€” not on measured throughput. The default in dash.js since 2016. More robust than throughput-only methods under variable network conditions.", - category: 'web' + id: 'abr-bola', + term: 'BOLA (Buffer Occupancy based Lyapunov Algorithm)', + definition: + "Buffer-based {{adaptive-bitrate|ABR}} algorithm that picks the next segment's quality based on how full the player's buffer is β€” not on measured throughput. The default in dash.js since 2016. More robust than throughput-only methods under variable network conditions.", + category: 'web' }, { - id: 'sdp-offer-answer', - term: 'SDP Offer/Answer Model', - definition: - "The negotiation pattern used by [[sip|SIP]] and [[webrtc|WebRTC]] (RFC 3264). Side A sends an [[sdp|SDP]] *offer* listing every {{codec|codec}}/transport it supports; side B replies with an *answer* that contains only the intersection. One round trip β€” no haggling, no renegotiation under steady state.", - wikiUrl: 'https://en.wikipedia.org/wiki/Session_Description_Protocol', - category: 'web' + id: 'sdp-offer-answer', + term: 'SDP Offer/Answer Model', + definition: + 'The negotiation pattern used by [[sip|SIP]] and [[webrtc|WebRTC]] (RFC 3264). Side A sends an [[sdp|SDP]] *offer* listing every {{codec|codec}}/transport it supports; side B replies with an *answer* that contains only the intersection. One round trip β€” no haggling, no renegotiation under steady state.', + wikiUrl: 'https://en.wikipedia.org/wiki/Session_Description_Protocol', + category: 'web' }, { - id: 'sip-invite', - term: 'SIP INVITE', - definition: - "The [[sip|SIP]] request that initiates a session β€” please ring this user. Body carries an [[sdp|SDP]] offer describing what audio/video the caller can send. Uses a {{three-way-handshake|three-way pattern}} (INVITE -> final response -> {{sip-ack|ACK}}) to be safe over [[udp|UDP]].", - wikiUrl: 'https://en.wikipedia.org/wiki/Session_Initiation_Protocol', - category: 'web' + id: 'sip-invite', + term: 'SIP INVITE', + definition: + 'The [[sip|SIP]] request that initiates a session β€” please ring this user. Body carries an [[sdp|SDP]] offer describing what audio/video the caller can send. Uses a {{three-way-handshake|three-way pattern}} (INVITE -> final response -> {{sip-ack|ACK}}) to be safe over [[udp|UDP]].', + wikiUrl: 'https://en.wikipedia.org/wiki/Session_Initiation_Protocol', + category: 'web' }, { - id: 'sip-register', - term: 'SIP REGISTER', - definition: - "[[sip|SIP]] request that maps a SIP URI (`bob@example.com`) to the device's current {{ip-address|IP}} and {{port|port}}. The {{sip-registrar|registrar}} stores this binding so future {{sip-invite|INVITEs}} can be routed to the right device.", - category: 'web' + id: 'sip-register', + term: 'SIP REGISTER', + definition: + "[[sip|SIP]] request that maps a SIP URI (`bob@example.com`) to the device's current {{ip-address|IP}} and {{port|port}}. The {{sip-registrar|registrar}} stores this binding so future {{sip-invite|INVITEs}} can be routed to the right device.", + category: 'web' }, { - id: 'sip-ack', - term: 'SIP ACK', - definition: - "Third leg of the [[sip|SIP]] {{sip-invite|INVITE}} {{three-way-handshake|three-way handshake}}. The caller confirms it received the `{{sip-200-ok|200 OK}}`. Unlike most [[sip|SIP]] requests, the ACK to a 2xx response is hop-by-hop generated by the end user agent β€” not by the proxy.", - category: 'web' + id: 'sip-ack', + term: 'SIP ACK', + definition: + 'Third leg of the [[sip|SIP]] {{sip-invite|INVITE}} {{three-way-handshake|three-way handshake}}. The caller confirms it received the `{{sip-200-ok|200 OK}}`. Unlike most [[sip|SIP]] requests, the ACK to a 2xx response is hop-by-hop generated by the end user agent β€” not by the proxy.', + category: 'web' }, { - id: 'sip-bye', - term: 'SIP BYE', - definition: - "[[sip|SIP]] request that ends an established session. Either side can send BYE; the receiver replies `{{sip-200-ok|200 OK}}` and tears down the dialog. Media flow stops immediately.", - category: 'web' + id: 'sip-bye', + term: 'SIP BYE', + definition: + '[[sip|SIP]] request that ends an established session. Either side can send BYE; the receiver replies `{{sip-200-ok|200 OK}}` and tears down the dialog. Media flow stops immediately.', + category: 'web' }, { - id: 'sip-180-ringing', - term: 'SIP 180 Ringing', - definition: - "[[sip|SIP]] {{sip-provisional-response|provisional response}} (1xx) meaning *the callee's phone is being alerted*. May arrive multiple times as the {{sip-proxy|proxy}} forks the {{sip-invite|INVITE}} to multiple devices. Not a final response β€” the call isn't answered yet.", - category: 'web' + id: 'sip-180-ringing', + term: 'SIP 180 Ringing', + definition: + "[[sip|SIP]] {{sip-provisional-response|provisional response}} (1xx) meaning *the callee's phone is being alerted*. May arrive multiple times as the {{sip-proxy|proxy}} forks the {{sip-invite|INVITE}} to multiple devices. Not a final response β€” the call isn't answered yet.", + category: 'web' }, { - id: 'sip-200-ok', - term: 'SIP 200 OK', - definition: - "[[sip|SIP]] final response (2xx) β€” the callee answered. The 200 OK to an {{sip-invite|INVITE}} carries the [[sdp|SDP]] *answer*, completing {{codec|codec}}/{{port|port}} negotiation. Caller responds with {{sip-ack|ACK}}.", - category: 'web' + id: 'sip-200-ok', + term: 'SIP 200 OK', + definition: + '[[sip|SIP]] final response (2xx) β€” the callee answered. The 200 OK to an {{sip-invite|INVITE}} carries the [[sdp|SDP]] *answer*, completing {{codec|codec}}/{{port|port}} negotiation. Caller responds with {{sip-ack|ACK}}.', + category: 'web' }, { - id: 'sip-provisional-response', - term: 'SIP Provisional Response (1xx)', - definition: - "Any [[sip|SIP]] response in the 100-199 range β€” informational, not final. Common: `100 Trying`, `{{sip-180-ringing|180 Ringing}}`, `183 Session Progress`. Lets the caller know the request is being processed before a final 2xx/4xx/5xx/6xx response arrives.", - category: 'web' + id: 'sip-provisional-response', + term: 'SIP Provisional Response (1xx)', + definition: + 'Any [[sip|SIP]] response in the 100-199 range β€” informational, not final. Common: `100 Trying`, `{{sip-180-ringing|180 Ringing}}`, `183 Session Progress`. Lets the caller know the request is being processed before a final 2xx/4xx/5xx/6xx response arrives.', + category: 'web' }, { - id: 'sip-proxy', - term: 'SIP Proxy', - definition: - "Intermediary server that routes [[sip|SIP]] requests towards the callee β€” like an SMTP relay for VoIP. May fork an {{sip-invite|INVITE}} to multiple registered devices ({{sip-forking|forking}}). Once the session establishes, media usually bypasses the proxy and flows {{peer-to-peer|peer-to-peer}}.", - category: 'web' + id: 'sip-proxy', + term: 'SIP Proxy', + definition: + 'Intermediary server that routes [[sip|SIP]] requests towards the callee β€” like an SMTP relay for VoIP. May fork an {{sip-invite|INVITE}} to multiple registered devices ({{sip-forking|forking}}). Once the session establishes, media usually bypasses the proxy and flows {{peer-to-peer|peer-to-peer}}.', + category: 'web' }, { - id: 'sip-registrar', - term: 'SIP Registrar', - definition: - "[[sip|SIP]] server that accepts {{sip-register|REGISTER}} requests and stores the binding between a SIP URI (`bob@example.com`) and the device's current {{ip-address|IP}} and {{port|port}}. The {{sip-proxy|proxy}} queries the registrar to find where to route incoming calls.", - category: 'web' + id: 'sip-registrar', + term: 'SIP Registrar', + definition: + "[[sip|SIP]] server that accepts {{sip-register|REGISTER}} requests and stores the binding between a SIP URI (`bob@example.com`) and the device's current {{ip-address|IP}} and {{port|port}}. The {{sip-proxy|proxy}} queries the registrar to find where to route incoming calls.", + category: 'web' }, { - id: 'sip-forking', - term: 'SIP Forking', - definition: - "A {{sip-proxy|SIP proxy}} feature: when Bob has multiple devices registered to the same SIP URI, the proxy can fan the {{sip-invite|INVITE}} out to all of them in parallel β€” so every phone he owns rings at once. The first to answer wins; the others get a CANCEL.", - category: 'web' + id: 'sip-forking', + term: 'SIP Forking', + definition: + 'A {{sip-proxy|SIP proxy}} feature: when Bob has multiple devices registered to the same SIP URI, the proxy can fan the {{sip-invite|INVITE}} out to all of them in parallel β€” so every phone he owns rings at once. The first to answer wins; the others get a CANCEL.', + category: 'web' }, { - id: 'ssh-kex-init', - term: 'SSH KEX_INIT', - definition: - "The opening message of the [[ssh|SSH]] {{ssh-key-exchange|key exchange}}. Each side lists the algorithms it supports for {{ssh-key-exchange|key exchange}}, host-key, {{encryption|encryption}}, {{hmac|MAC}}, and compression. Both ends then pick the strongest mutual choice.", - wikiUrl: 'https://en.wikipedia.org/wiki/Secure_Shell', - category: 'security' + id: 'ssh-kex-init', + term: 'SSH KEX_INIT', + definition: + 'The opening message of the [[ssh|SSH]] {{ssh-key-exchange|key exchange}}. Each side lists the algorithms it supports for {{ssh-key-exchange|key exchange}}, host-key, {{encryption|encryption}}, {{hmac|MAC}}, and compression. Both ends then pick the strongest mutual choice.', + wikiUrl: 'https://en.wikipedia.org/wiki/Secure_Shell', + category: 'security' }, { - id: 'ssh-key-exchange', - term: 'SSH Key Exchange', - definition: - "Phase of the [[ssh|SSH]] connection that derives a shared session key β€” typically via {{diffie-hellman|Diffie-Hellman}} or {{ecdh|ECDH}} on Curve25519. The session key encrypts every byte that follows; an eavesdropper with the full transcript still can't recover it.", - category: 'security' + id: 'ssh-key-exchange', + term: 'SSH Key Exchange', + definition: + "Phase of the [[ssh|SSH]] connection that derives a shared session key β€” typically via {{diffie-hellman|Diffie-Hellman}} or {{ecdh|ECDH}} on Curve25519. The session key encrypts every byte that follows; an eavesdropper with the full transcript still can't recover it.", + category: 'security' }, { - id: 'ssh-host-key', - term: 'SSH Host Key', - definition: - "Long-term {{asymmetric-encryption|asymmetric}} key pair that identifies an [[ssh|SSH]] server across reboots. The client pins the public half in `known_hosts`; on later connections it verifies the server signs the {{ssh-key-exchange|KEX}} transcript with the matching {{private-key|private key}}. Defeats {{man-in-the-middle|MITM}}.", - category: 'security' + id: 'ssh-host-key', + term: 'SSH Host Key', + definition: + 'Long-term {{asymmetric-encryption|asymmetric}} key pair that identifies an [[ssh|SSH]] server across reboots. The client pins the public half in `known_hosts`; on later connections it verifies the server signs the {{ssh-key-exchange|KEX}} transcript with the matching {{private-key|private key}}. Defeats {{man-in-the-middle|MITM}}.', + category: 'security' }, { - id: 'ssh-tofu', - term: 'TOFU (Trust on First Use)', - definition: - "Security model used by [[ssh|SSH]] and many other protocols: trust the public key the *first* time you see it, pin it locally, alert loudly if it ever changes. Pragmatic compromise β€” no {{pki|PKI}} needed, but the first connection is unauthenticated.", - wikiUrl: 'https://en.wikipedia.org/wiki/Trust_on_first_use', - category: 'security' + id: 'ssh-tofu', + term: 'TOFU (Trust on First Use)', + definition: + 'Security model used by [[ssh|SSH]] and many other protocols: trust the public key the *first* time you see it, pin it locally, alert loudly if it ever changes. Pragmatic compromise β€” no {{pki|PKI}} needed, but the first connection is unauthenticated.', + wikiUrl: 'https://en.wikipedia.org/wiki/Trust_on_first_use', + category: 'security' }, { - id: 'ssh-publickey-auth', - term: 'SSH publickey Authentication', - definition: - "[[ssh|SSH]] auth method where the client proves possession of a {{private-key|private key}} matching a {{public-key|public key}} the server has authorised (in `~/.ssh/authorized_keys`). The de-facto standard for server access; replaces password auth entirely in modern deployments.", - category: 'security' + id: 'ssh-publickey-auth', + term: 'SSH publickey Authentication', + definition: + '[[ssh|SSH]] auth method where the client proves possession of a {{private-key|private key}} matching a {{public-key|public key}} the server has authorised (in `~/.ssh/authorized_keys`). The de-facto standard for server access; replaces password auth entirely in modern deployments.', + category: 'security' }, { - id: 'ssh-keyboard-interactive', - term: 'SSH keyboard-interactive', - definition: - "[[ssh|SSH]] auth method (RFC 4256) that lets the server prompt the client for arbitrary challenges β€” used for 2FA, OTP tokens, and PAM-driven flows. The server sends a list of prompts; the client returns responses.", - category: 'security' + id: 'ssh-keyboard-interactive', + term: 'SSH keyboard-interactive', + definition: + '[[ssh|SSH]] auth method (RFC 4256) that lets the server prompt the client for arbitrary challenges β€” used for 2FA, OTP tokens, and PAM-driven flows. The server sends a list of prompts; the client returns responses.', + category: 'security' }, { - id: 'ssh-channels', - term: 'SSH Channels', - definition: - "Logical streams inside one [[ssh|SSH]] connection. {{multiplexing|Multiplexes}} interactive shells, file transfer ({{sftp|SFTP}}), {{port-forwarding|port forwarding}}, and X11 forwarding β€” all on the same encrypted [[tcp|TCP]] {{socket|socket}}.", - category: 'security' + id: 'ssh-channels', + term: 'SSH Channels', + definition: + 'Logical streams inside one [[ssh|SSH]] connection. {{multiplexing|Multiplexes}} interactive shells, file transfer ({{sftp|SFTP}}), {{port-forwarding|port forwarding}}, and X11 forwarding β€” all on the same encrypted [[tcp|TCP]] {{socket|socket}}.', + category: 'security' }, { - id: 'tls-certificate-verify', - term: 'TLS CertificateVerify', - definition: - "[[tls|TLS]] 1.3 {{tls-handshake|handshake}} message in which the server signs the entire transcript with the {{private-key|private key}} matching its {{certificate|certificate}}. Proves the server actually owns the cert β€” without this step a {{man-in-the-middle|MITM}} could replay someone else's cert.", - category: 'security' + id: 'tls-certificate-verify', + term: 'TLS CertificateVerify', + definition: + "[[tls|TLS]] 1.3 {{tls-handshake|handshake}} message in which the server signs the entire transcript with the {{private-key|private key}} matching its {{certificate|certificate}}. Proves the server actually owns the cert β€” without this step a {{man-in-the-middle|MITM}} could replay someone else's cert.", + category: 'security' }, { - id: 'csrf', - term: 'CSRF (Cross-Site Request Forgery)', - definition: - "Attack class where a malicious site tricks a logged-in user's browser into making an unwanted request to a target site, riding on the user's session {{cookie|cookies}}. Defences: {{oauth-state|state}} tokens, SameSite cookies, double-submit headers.", - wikiUrl: 'https://en.wikipedia.org/wiki/Cross-site_request_forgery', - category: 'security' + id: 'csrf', + term: 'CSRF (Cross-Site Request Forgery)', + definition: + "Attack class where a malicious site tricks a logged-in user's browser into making an unwanted request to a target site, riding on the user's session {{cookie|cookies}}. Defences: {{oauth-state|state}} tokens, SameSite cookies, double-submit headers.", + wikiUrl: 'https://en.wikipedia.org/wiki/Cross-site_request_forgery', + category: 'security' }, { - id: 'oauth-state', - term: 'OAuth state parameter', - definition: - "Opaque, unpredictable token included in an [[oauth2|OAuth]] authorization request and echoed back in the redirect. Lets the client verify the response matches a request *it* initiated β€” preventing {{csrf|CSRF}} on the callback endpoint. Always required.", - category: 'security' + id: 'oauth-state', + term: 'OAuth state parameter', + definition: + 'Opaque, unpredictable token included in an [[oauth2|OAuth]] authorization request and echoed back in the redirect. Lets the client verify the response matches a request *it* initiated β€” preventing {{csrf|CSRF}} on the callback endpoint. Always required.', + category: 'security' }, { - id: 'oauth-auth-code', - term: 'OAuth Authorization Code', - definition: - "Short-lived (~30 s), single-use token returned by the [[oauth2|OAuth]] authorization server after user {{oauth-consent|consent}}. The client exchanges it (plus {{pkce|PKCE}} `code_verifier`) at the token endpoint for an {{access-token|access token}} + {{oauth-refresh-token|refresh token}}.", - category: 'security' + id: 'oauth-auth-code', + term: 'OAuth Authorization Code', + definition: + 'Short-lived (~30 s), single-use token returned by the [[oauth2|OAuth]] authorization server after user {{oauth-consent|consent}}. The client exchanges it (plus {{pkce|PKCE}} `code_verifier`) at the token endpoint for an {{access-token|access token}} + {{oauth-refresh-token|refresh token}}.', + category: 'security' }, { - id: 'oauth-consent', - term: 'OAuth Consent Screen', - definition: - "The page where the user reviews and approves which {{oauth-scope|scopes}} a client app is requesting access to. Run by the [[oauth2|OAuth]] authorization server β€” the client never sees the user's password.", - category: 'security' + id: 'oauth-consent', + term: 'OAuth Consent Screen', + definition: + "The page where the user reviews and approves which {{oauth-scope|scopes}} a client app is requesting access to. Run by the [[oauth2|OAuth]] authorization server β€” the client never sees the user's password.", + category: 'security' }, { - id: 'oauth-scope', - term: 'OAuth Scope', - definition: - "String identifying a specific permission requested by an [[oauth2|OAuth]] client (e.g., `read:user`, `repo`, `email`). Shown on the {{oauth-consent|consent screen}} so the user knows what they're granting. The {{access-token|access token}} is bound to the approved scopes.", - category: 'security' + id: 'oauth-scope', + term: 'OAuth Scope', + definition: + "String identifying a specific permission requested by an [[oauth2|OAuth]] client (e.g., `read:user`, `repo`, `email`). Shown on the {{oauth-consent|consent screen}} so the user knows what they're granting. The {{access-token|access token}} is bound to the approved scopes.", + category: 'security' }, { - id: 'oauth-client-id', - term: 'OAuth client_id', - definition: - "Public identifier the [[oauth2|OAuth]] authorization server uses to recognise a registered client application. Sent in every request (`/authorize`, `/token`). Not a secret β€” paired with {{pkce|PKCE}} or a `client_secret` for confidential clients.", - category: 'security' + id: 'oauth-client-id', + term: 'OAuth client_id', + definition: + 'Public identifier the [[oauth2|OAuth]] authorization server uses to recognise a registered client application. Sent in every request (`/authorize`, `/token`). Not a secret β€” paired with {{pkce|PKCE}} or a `client_secret` for confidential clients.', + category: 'security' }, { - id: 'oauth-refresh-token', - term: 'OAuth Refresh Token', - definition: - "Long-lived [[oauth2|OAuth]] token used to obtain new {{access-token|access tokens}} without re-prompting the user. Must be stored confidentially (server-side only for web apps). Rotated by the auth server on each use in modern implementations.", - category: 'security' + id: 'oauth-refresh-token', + term: 'OAuth Refresh Token', + definition: + 'Long-lived [[oauth2|OAuth]] token used to obtain new {{access-token|access tokens}} without re-prompting the user. Must be stored confidentially (server-side only for web apps). Rotated by the auth server on each use in modern implementations.', + category: 'security' }, { - id: 'rsa', - term: 'RSA', - definition: - "{{asymmetric-encryption|Asymmetric}} algorithm (Rivest-Shamir-Adleman, 1977) for signatures and key encapsulation. Security rests on the difficulty of factoring large integers. Still common in [[tls|TLS]] / [[ipsec|IPsec]] {{certificate|certificates}}, though {{ecdsa|ECDSA}} and Ed25519 are now preferred.", - wikiUrl: 'https://en.wikipedia.org/wiki/RSA_(cryptosystem)', - category: 'security' + id: 'rsa', + term: 'RSA', + definition: + '{{asymmetric-encryption|Asymmetric}} algorithm (Rivest-Shamir-Adleman, 1977) for signatures and key encapsulation. Security rests on the difficulty of factoring large integers. Still common in [[tls|TLS]] / [[ipsec|IPsec]] {{certificate|certificates}}, though {{ecdsa|ECDSA}} and Ed25519 are now preferred.', + wikiUrl: 'https://en.wikipedia.org/wiki/RSA_(cryptosystem)', + category: 'security' }, { - id: 'ecdsa', - term: 'ECDSA (Elliptic Curve Digital Signature Algorithm)', - definition: - "Digital signature scheme over elliptic curves β€” much shorter keys/signatures than {{rsa|RSA}} for equivalent security. Used in [[tls|TLS]] / [[ssh|SSH]] / [[ipsec|IPsec]] {{certificate|certificates}}, and as the signature algorithm in Bitcoin and Ethereum.", - wikiUrl: 'https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm', - category: 'security' + id: 'ecdsa', + term: 'ECDSA (Elliptic Curve Digital Signature Algorithm)', + definition: + 'Digital signature scheme over elliptic curves β€” much shorter keys/signatures than {{rsa|RSA}} for equivalent security. Used in [[tls|TLS]] / [[ssh|SSH]] / [[ipsec|IPsec]] {{certificate|certificates}}, and as the signature algorithm in Bitcoin and Ethereum.', + wikiUrl: 'https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm', + category: 'security' }, { - id: 'ecdh', - term: 'ECDH (Elliptic Curve Diffie-Hellman)', - definition: - "Variant of {{diffie-hellman|Diffie-Hellman}} key exchange over elliptic curves (commonly Curve25519 or P-256). Much smaller keys, faster computation, same shared-secret derivation. The default {{ssh-key-exchange|key exchange}} in modern [[tls|TLS]] 1.3 and [[ssh|SSH]].", - wikiUrl: 'https://en.wikipedia.org/wiki/Elliptic-curve_Diffie%E2%80%93Hellman', - category: 'security' + id: 'ecdh', + term: 'ECDH (Elliptic Curve Diffie-Hellman)', + definition: + 'Variant of {{diffie-hellman|Diffie-Hellman}} key exchange over elliptic curves (commonly Curve25519 or P-256). Much smaller keys, faster computation, same shared-secret derivation. The default {{ssh-key-exchange|key exchange}} in modern [[tls|TLS]] 1.3 and [[ssh|SSH]].', + wikiUrl: 'https://en.wikipedia.org/wiki/Elliptic-curve_Diffie%E2%80%93Hellman', + category: 'security' }, { - id: 'psk', - term: 'PSK (Pre-Shared Key)', - definition: - "Authentication mode where both parties share a long-term symmetric secret out of band β€” no {{certificate|certificates}}, no {{pki|PKI}}. Used in [[ipsec|IPsec]] site-to-site VPNs, [[wireguard|WireGuard]] (optional mix), and consumer Wi-Fi (WPA-PSK).", - wikiUrl: 'https://en.wikipedia.org/wiki/Pre-shared_key', - category: 'security' + id: 'psk', + term: 'PSK (Pre-Shared Key)', + definition: + 'Authentication mode where both parties share a long-term symmetric secret out of band β€” no {{certificate|certificates}}, no {{pki|PKI}}. Used in [[ipsec|IPsec]] site-to-site VPNs, [[wireguard|WireGuard]] (optional mix), and consumer Wi-Fi (WPA-PSK).', + wikiUrl: 'https://en.wikipedia.org/wiki/Pre-shared_key', + category: 'security' }, { - id: 'curve25519', - term: 'Curve25519', - definition: - "Modern elliptic curve designed by [[pioneer:dan-bernstein|Daniel J. Bernstein]] (2005). Used for {{ecdh|ECDH}} in [[tls|TLS]] 1.3, [[ssh|SSH]], [[wireguard|WireGuard]], Signal β€” fast, side-channel-resistant, and free of suspect NIST parameters.", - wikiUrl: 'https://en.wikipedia.org/wiki/Curve25519', - category: 'security' + id: 'curve25519', + term: 'Curve25519', + definition: + 'Modern elliptic curve designed by [[pioneer:dan-bernstein|Daniel J. Bernstein]] (2005). Used for {{ecdh|ECDH}} in [[tls|TLS]] 1.3, [[ssh|SSH]], [[wireguard|WireGuard]], Signal β€” fast, side-channel-resistant, and free of suspect NIST parameters.', + wikiUrl: 'https://en.wikipedia.org/wiki/Curve25519', + category: 'security' }, { - id: 'poly1305', - term: 'Poly1305', - definition: - "One-time authenticator (Bernstein, 2005) used as the integrity tag in the {{chacha20-poly1305|ChaCha20-Poly1305}} {{aead|AEAD}}. Appends a 16-byte tag the receiver verifies before accepting the ciphertext. Replay-safe when paired with a unique {{nonce|nonce}} per message.", - wikiUrl: 'https://en.wikipedia.org/wiki/Poly1305', - category: 'security' + id: 'poly1305', + term: 'Poly1305', + definition: + 'One-time authenticator (Bernstein, 2005) used as the integrity tag in the {{chacha20-poly1305|ChaCha20-Poly1305}} {{aead|AEAD}}. Appends a 16-byte tag the receiver verifies before accepting the ciphertext. Replay-safe when paired with a unique {{nonce|nonce}} per message.', + wikiUrl: 'https://en.wikipedia.org/wiki/Poly1305', + category: 'security' }, { - id: 'noise-ik', - term: 'Noise_IK pattern', - definition: - "One of the {{noise-protocol|Noise Protocol Framework}} handshake patterns. *I* = initiator's static key sent immediately, *K* = responder's static key already known. The [[wireguard|WireGuard]] handshake is `Noise_IKpsk2` β€” Noise_IK with an optional pre-shared key mixed in at step 2.", - wikiUrl: 'https://en.wikipedia.org/wiki/Noise_Protocol_Framework', - category: 'security' + id: 'noise-ik', + term: 'Noise_IK pattern', + definition: + "One of the {{noise-protocol|Noise Protocol Framework}} handshake patterns. *I* = initiator's static key sent immediately, *K* = responder's static key already known. The [[wireguard|WireGuard]] handshake is `Noise_IKpsk2` β€” Noise_IK with an optional pre-shared key mixed in at step 2.", + wikiUrl: 'https://en.wikipedia.org/wiki/Noise_Protocol_Framework', + category: 'security' }, { - id: 'noise-protocol', - term: 'Noise Protocol Framework', - definition: - "Family of cryptographic handshake patterns by [[pioneer:trevor-perrin|Trevor Perrin]] β€” pick a pattern (IK, XX, NK), plug in DH curve + cipher + hash, get a complete handshake. Powers [[wireguard|WireGuard]], WhatsApp, Signal, and Lightning Network.", - wikiUrl: 'https://en.wikipedia.org/wiki/Noise_Protocol_Framework', - category: 'security' + id: 'noise-protocol', + term: 'Noise Protocol Framework', + definition: + 'Family of cryptographic handshake patterns by [[pioneer:trevor-perrin|Trevor Perrin]] β€” pick a pattern (IK, XX, NK), plug in DH curve + cipher + hash, get a complete handshake. Powers [[wireguard|WireGuard]], WhatsApp, Signal, and Lightning Network.', + wikiUrl: 'https://en.wikipedia.org/wiki/Noise_Protocol_Framework', + category: 'security' }, { - id: 'wg-handshake-initiation', - term: 'WireGuard Handshake Initiation (type=1)', - definition: - "First message of the [[wireguard|WireGuard]] {{noise-ik|Noise_IKpsk2}} handshake β€” 148 bytes. Carries the initiator's ephemeral pubkey, an {{aead|AEAD}}-encrypted copy of its static pubkey, a {{wg-tai64n|TAI64N}} timestamp, and the {{wg-mac1|MAC1}}/{{wg-mac2|MAC2}} cookie pair.", - category: 'security' + id: 'wg-handshake-initiation', + term: 'WireGuard Handshake Initiation (type=1)', + definition: + "First message of the [[wireguard|WireGuard]] {{noise-ik|Noise_IKpsk2}} handshake β€” 148 bytes. Carries the initiator's ephemeral pubkey, an {{aead|AEAD}}-encrypted copy of its static pubkey, a {{wg-tai64n|TAI64N}} timestamp, and the {{wg-mac1|MAC1}}/{{wg-mac2|MAC2}} cookie pair.", + category: 'security' }, { - id: 'wg-handshake-response', - term: 'WireGuard Handshake Response (type=2)', - definition: - "Second message of the [[wireguard|WireGuard]] handshake β€” 92 bytes. The responder's ephemeral pubkey, an {{aead|AEAD}}-encrypted empty payload (proves key agreement), and {{wg-mac1|MAC1}}/{{wg-mac2|MAC2}}. After this, both peers hold matching {{chacha20-poly1305|ChaCha20-Poly1305}} keys.", - category: 'security' + id: 'wg-handshake-response', + term: 'WireGuard Handshake Response (type=2)', + definition: + "Second message of the [[wireguard|WireGuard]] handshake β€” 92 bytes. The responder's ephemeral pubkey, an {{aead|AEAD}}-encrypted empty payload (proves key agreement), and {{wg-mac1|MAC1}}/{{wg-mac2|MAC2}}. After this, both peers hold matching {{chacha20-poly1305|ChaCha20-Poly1305}} keys.", + category: 'security' }, { - id: 'wg-transport-data', - term: 'WireGuard Transport Data (type=4)', - definition: - "Steady-state [[wireguard|WireGuard]] {{packet|packet}} carrying an encrypted inner [[ip|IP]] payload. 16-byte header (type + receiver-index + 64-bit counter) + {{aead|AEAD}} ciphertext + 16-byte {{poly1305|Poly1305}} tag. Counter doubles as both the nonce and {{anti-replay|anti-replay}} sequence number.", - category: 'security' + id: 'wg-transport-data', + term: 'WireGuard Transport Data (type=4)', + definition: + 'Steady-state [[wireguard|WireGuard]] {{packet|packet}} carrying an encrypted inner [[ip|IP]] payload. 16-byte header (type + receiver-index + 64-bit counter) + {{aead|AEAD}} ciphertext + 16-byte {{poly1305|Poly1305}} tag. Counter doubles as both the nonce and {{anti-replay|anti-replay}} sequence number.', + category: 'security' }, { - id: 'wg-ephemeral-key', - term: 'Ephemeral Key (WireGuard)', - definition: - "Single-use Curve25519 key pair generated fresh for each [[wireguard|WireGuard]] {{handshake|handshake}}. Provides {{forward-secrecy|forward secrecy}}: even if the long-term static key leaks later, past session keys cannot be recovered.", - category: 'security' + id: 'wg-ephemeral-key', + term: 'Ephemeral Key (WireGuard)', + definition: + 'Single-use Curve25519 key pair generated fresh for each [[wireguard|WireGuard]] {{handshake|handshake}}. Provides {{forward-secrecy|forward secrecy}}: even if the long-term static key leaks later, past session keys cannot be recovered.', + category: 'security' }, { - id: 'wg-tai64n', - term: 'TAI64N timestamp', - definition: - "12-byte time-of-day stamp embedded in the [[wireguard|WireGuard]] {{wg-handshake-initiation|Handshake Initiation}}. Lets the responder reject replayed initiations that are older than the most recent one seen β€” without keeping per-peer replay tables.", - wikiUrl: 'https://cr.yp.to/libtai/tai64.html', - category: 'security' + id: 'wg-tai64n', + term: 'TAI64N timestamp', + definition: + '12-byte time-of-day stamp embedded in the [[wireguard|WireGuard]] {{wg-handshake-initiation|Handshake Initiation}}. Lets the responder reject replayed initiations that are older than the most recent one seen β€” without keeping per-peer replay tables.', + wikiUrl: 'https://cr.yp.to/libtai/tai64.html', + category: 'security' }, { - id: 'wg-mac1', - term: 'WireGuard MAC1', - definition: - "First message authentication code in every [[wireguard|WireGuard]] handshake packet. Computed over the message using the responder's static public key β€” proves the sender already knows that pubkey. Cheap anti-amplification check.", - category: 'security' + id: 'wg-mac1', + term: 'WireGuard MAC1', + definition: + "First message authentication code in every [[wireguard|WireGuard]] handshake packet. Computed over the message using the responder's static public key β€” proves the sender already knows that pubkey. Cheap anti-amplification check.", + category: 'security' }, { - id: 'wg-mac2', - term: 'WireGuard MAC2 (Cookie)', - definition: - "Second [[wireguard|WireGuard]] handshake MAC, normally zero but populated with a server-issued cookie when the responder is under DoS load. Acts as a stateless rate-limiter β€” initiators must prove reachability before the responder spends CPU verifying signatures.", - category: 'security' + id: 'wg-mac2', + term: 'WireGuard MAC2 (Cookie)', + definition: + 'Second [[wireguard|WireGuard]] handshake MAC, normally zero but populated with a server-issued cookie when the responder is under DoS load. Acts as a stateless rate-limiter β€” initiators must prove reachability before the responder spends CPU verifying signatures.', + category: 'security' }, { - id: 'post-quantum', - term: 'Post-Quantum Cryptography (PQC)', - definition: - "Algorithms believed to resist attacks by future large-scale quantum computers β€” e.g., {{ml-kem|ML-KEM}}, ML-DSA, SLH-DSA (NIST FIPS 203/204/205, 2024). Being added to [[tls|TLS]], [[ssh|SSH]], [[ipsec|IPsec]] via hybrid handshakes that mix PQC with classical {{ecdh|ECDH}}.", - wikiUrl: 'https://en.wikipedia.org/wiki/Post-quantum_cryptography', - category: 'security' + id: 'post-quantum', + term: 'Post-Quantum Cryptography (PQC)', + definition: + 'Algorithms believed to resist attacks by future large-scale quantum computers β€” e.g., {{ml-kem|ML-KEM}}, ML-DSA, SLH-DSA (NIST FIPS 203/204/205, 2024). Being added to [[tls|TLS]], [[ssh|SSH]], [[ipsec|IPsec]] via hybrid handshakes that mix PQC with classical {{ecdh|ECDH}}.', + wikiUrl: 'https://en.wikipedia.org/wiki/Post-quantum_cryptography', + category: 'security' }, { - id: 'kem', - term: 'KEM (Key Encapsulation Mechanism)', - definition: - "Cryptographic primitive for transmitting a symmetric key under a recipient's {{public-key|public key}}. {{post-quantum|Post-quantum}} {{ml-kem|ML-KEM}} is a KEM, as is classical RSA-KEM. KEMs replace ephemeral {{diffie-hellman|DH}} in PQC-era [[tls|TLS]] / [[ipsec|IPsec]] handshakes.", - wikiUrl: 'https://en.wikipedia.org/wiki/Key_encapsulation_mechanism', - category: 'security' + id: 'kem', + term: 'KEM (Key Encapsulation Mechanism)', + definition: + "Cryptographic primitive for transmitting a symmetric key under a recipient's {{public-key|public key}}. {{post-quantum|Post-quantum}} {{ml-kem|ML-KEM}} is a KEM, as is classical RSA-KEM. KEMs replace ephemeral {{diffie-hellman|DH}} in PQC-era [[tls|TLS]] / [[ipsec|IPsec]] handshakes.", + wikiUrl: 'https://en.wikipedia.org/wiki/Key_encapsulation_mechanism', + category: 'security' }, { - id: 'ipsec-ike-sa-init', - term: 'IKE_SA_INIT', - definition: - "First [[ipsec|IPsec]] {{ike|IKEv2}} exchange β€” proposes a {{cipher-suite|cipher suite}}, runs {{diffie-hellman|Diffie-Hellman}} / {{ecdh|ECDH}} / {{kem|KEM}}, exchanges {{nonce|Nonces}}, and runs {{ipsec-nat-detection|NAT_DETECTION}}. No {{encryption|encryption}} yet β€” keys don't exist until this completes.", - category: 'security' + id: 'ipsec-ike-sa-init', + term: 'IKE_SA_INIT', + definition: + "First [[ipsec|IPsec]] {{ike|IKEv2}} exchange β€” proposes a {{cipher-suite|cipher suite}}, runs {{diffie-hellman|Diffie-Hellman}} / {{ecdh|ECDH}} / {{kem|KEM}}, exchanges {{nonce|Nonces}}, and runs {{ipsec-nat-detection|NAT_DETECTION}}. No {{encryption|encryption}} yet β€” keys don't exist until this completes.", + category: 'security' }, { - id: 'ipsec-ike-intermediate', - term: 'IKE_INTERMEDIATE', - definition: - "[[ipsec|IPsec]] {{ike|IKEv2}} exchange added by [[rfc:9242|RFC 9242]] to ship large {{post-quantum|post-quantum}} keys ({{ml-kem|ML-KEM-1024}} ~ 1.5 KB) that won't fit in a single {{ipsec-ike-sa-init|IKE_SA_INIT}} [[udp|UDP]] datagram. Runs encrypted, before identity is revealed; can chain extra {{kem|KEMs}} per [[rfc:9370|RFC 9370]].", - category: 'security' + id: 'ipsec-ike-intermediate', + term: 'IKE_INTERMEDIATE', + definition: + "[[ipsec|IPsec]] {{ike|IKEv2}} exchange added by [[rfc:9242|RFC 9242]] to ship large {{post-quantum|post-quantum}} keys ({{ml-kem|ML-KEM-1024}} ~ 1.5 KB) that won't fit in a single {{ipsec-ike-sa-init|IKE_SA_INIT}} [[udp|UDP]] datagram. Runs encrypted, before identity is revealed; can chain extra {{kem|KEMs}} per [[rfc:9370|RFC 9370]].", + category: 'security' }, { - id: 'ipsec-ike-auth', - term: 'IKE_AUTH', - definition: - "Second [[ipsec|IPsec]] {{ike|IKEv2}} exchange. Carries the identities (`IDi`, `IDr`), authenticates the {{ipsec-ike-sa-init|IKE_SA_INIT}} transcript (with {{rsa|RSA}}/{{ecdsa|ECDSA}} {{certificate|certs}}, {{psk|PSK}}, or {{eap|EAP}}), and negotiates the first {{child-sa|Child SA}}.", - category: 'security' + id: 'ipsec-ike-auth', + term: 'IKE_AUTH', + definition: + 'Second [[ipsec|IPsec]] {{ike|IKEv2}} exchange. Carries the identities (`IDi`, `IDr`), authenticates the {{ipsec-ike-sa-init|IKE_SA_INIT}} transcript (with {{rsa|RSA}}/{{ecdsa|ECDSA}} {{certificate|certs}}, {{psk|PSK}}, or {{eap|EAP}}), and negotiates the first {{child-sa|Child SA}}.', + category: 'security' }, { - id: 'ipsec-create-child-sa', - term: 'CREATE_CHILD_SA', - definition: - "[[ipsec|IPsec]] {{ike|IKEv2}} exchange used both to add new {{child-sa|Child SAs}} and to rekey existing ones (with the `REKEY_SA` notify). Optional fresh {{diffie-hellman|DH}}/{{kem|KEM}} provides {{pfs|Perfect Forward Secrecy}}.", - category: 'security' + id: 'ipsec-create-child-sa', + term: 'CREATE_CHILD_SA', + definition: + '[[ipsec|IPsec]] {{ike|IKEv2}} exchange used both to add new {{child-sa|Child SAs}} and to rekey existing ones (with the `REKEY_SA` notify). Optional fresh {{diffie-hellman|DH}}/{{kem|KEM}} provides {{pfs|Perfect Forward Secrecy}}.', + category: 'security' }, { - id: 'ipsec-informational', - term: 'INFORMATIONAL (IKEv2)', - definition: - "Encrypted [[ipsec|IPsec]] {{ike|IKEv2}} exchange for housekeeping β€” DELETE notifications when a {{security-association|SA}} expires, dead-peer-detection liveness probes, MOBIKE address updates, error messages.", - category: 'security' + id: 'ipsec-informational', + term: 'INFORMATIONAL (IKEv2)', + definition: + 'Encrypted [[ipsec|IPsec]] {{ike|IKEv2}} exchange for housekeeping β€” DELETE notifications when a {{security-association|SA}} expires, dead-peer-detection liveness probes, MOBIKE address updates, error messages.', + category: 'security' }, { - id: 'ipsec-nat-detection', - term: 'NAT_DETECTION (IKEv2)', - definition: - "Pair of hash payloads exchanged in {{ipsec-ike-sa-init|IKE_SA_INIT}}: each side hashes its own and peer's IP/port and compares with what arrived. A mismatch means one of them is behind {{nat|NAT}} β€” triggers UDP-encapsulation of {{esp|ESP}} on port 4500 (NAT-T).", - category: 'security' + id: 'ipsec-nat-detection', + term: 'NAT_DETECTION (IKEv2)', + definition: + "Pair of hash payloads exchanged in {{ipsec-ike-sa-init|IKE_SA_INIT}}: each side hashes its own and peer's IP/port and compares with what arrived. A mismatch means one of them is behind {{nat|NAT}} β€” triggers UDP-encapsulation of {{esp|ESP}} on port 4500 (NAT-T).", + category: 'security' }, { - id: 'ipsec-skeyseed', - term: 'SKEYSEED', - definition: - "The seed value [[ipsec|IPsec]] {{ike|IKEv2}} derives from the {{ipsec-ike-sa-init|IKE_SA_INIT}} Diffie-Hellman shared secret plus the two {{nonce|Nonces}}. All subsequent {{ike-sa|IKE SA}} keys (`SK_d`, `SK_e`, `SK_a`, `SK_p`) are expanded from SKEYSEED via the prf.", - category: 'security' + id: 'ipsec-skeyseed', + term: 'SKEYSEED', + definition: + 'The seed value [[ipsec|IPsec]] {{ike|IKEv2}} derives from the {{ipsec-ike-sa-init|IKE_SA_INIT}} Diffie-Hellman shared secret plus the two {{nonce|Nonces}}. All subsequent {{ike-sa|IKE SA}} keys (`SK_d`, `SK_e`, `SK_a`, `SK_p`) are expanded from SKEYSEED via the prf.', + category: 'security' }, { - id: 'kerberos-kdc', - term: 'KDC (Key Distribution Center)', - definition: - "Central trusted server in [[kerberos|Kerberos]] β€” split into the Authentication Service (AS, issues {{kerberos-tgt|TGTs}}) and the {{kerberos-tgs|Ticket Granting Service}} (TGS, issues service tickets). Knows every principal's long-term key; never speaks to services directly.", - wikiUrl: 'https://en.wikipedia.org/wiki/Key_distribution_center', - category: 'security' + id: 'kerberos-kdc', + term: 'KDC (Key Distribution Center)', + definition: + "Central trusted server in [[kerberos|Kerberos]] β€” split into the Authentication Service (AS, issues {{kerberos-tgt|TGTs}}) and the {{kerberos-tgs|Ticket Granting Service}} (TGS, issues service tickets). Knows every principal's long-term key; never speaks to services directly.", + wikiUrl: 'https://en.wikipedia.org/wiki/Key_distribution_center', + category: 'security' }, { - id: 'kerberos-tgs', - term: 'Ticket Granting Service (TGS)', - definition: - "Half of the [[kerberos|Kerberos]] {{kerberos-kdc|KDC}}. Accepts a {{kerberos-tgt|TGT}} + {{kerberos-authenticator|authenticator}} ({{kerberos-tgs-req|TGS-REQ}}) and returns a {{kerberos-service-ticket|service ticket}} for the requested service ({{kerberos-tgs-rep|TGS-REP}}).", - category: 'security' + id: 'kerberos-tgs', + term: 'Ticket Granting Service (TGS)', + definition: + 'Half of the [[kerberos|Kerberos]] {{kerberos-kdc|KDC}}. Accepts a {{kerberos-tgt|TGT}} + {{kerberos-authenticator|authenticator}} ({{kerberos-tgs-req|TGS-REQ}}) and returns a {{kerberos-service-ticket|service ticket}} for the requested service ({{kerberos-tgs-rep|TGS-REP}}).', + category: 'security' }, { - id: 'kerberos-tgt', - term: 'TGT (Ticket Granting Ticket)', - definition: - "Time-bounded [[kerberos|Kerberos]] credential issued by the Authentication Service in {{kerberos-as-rep|AS-REP}}. {{encryption|Encrypted}} under the {{kerberos-krbtgt|krbtgt}} key (only the KDC reads it). Lets the client request {{kerberos-service-ticket|service tickets}} without re-entering its password β€” typically valid 10 hours.", - wikiUrl: 'https://en.wikipedia.org/wiki/Ticket_Granting_Ticket', - category: 'security' + id: 'kerberos-tgt', + term: 'TGT (Ticket Granting Ticket)', + definition: + 'Time-bounded [[kerberos|Kerberos]] credential issued by the Authentication Service in {{kerberos-as-rep|AS-REP}}. {{encryption|Encrypted}} under the {{kerberos-krbtgt|krbtgt}} key (only the KDC reads it). Lets the client request {{kerberos-service-ticket|service tickets}} without re-entering its password β€” typically valid 10 hours.', + wikiUrl: 'https://en.wikipedia.org/wiki/Ticket_Granting_Ticket', + category: 'security' }, { - id: 'kerberos-krbtgt', - term: 'krbtgt', - definition: - "Special [[kerberos|Kerberos]] {{kerberos-principal|principal}} whose long-term key encrypts every {{kerberos-tgt|TGT}}. Compromise of the krbtgt password hash = the famous *Golden Ticket* attack: an attacker can mint TGTs for any user in the realm.", - category: 'security' + id: 'kerberos-krbtgt', + term: 'krbtgt', + definition: + 'Special [[kerberos|Kerberos]] {{kerberos-principal|principal}} whose long-term key encrypts every {{kerberos-tgt|TGT}}. Compromise of the krbtgt password hash = the famous *Golden Ticket* attack: an attacker can mint TGTs for any user in the realm.', + category: 'security' }, { - id: 'kerberos-principal', - term: 'Kerberos Principal', - definition: - "Named identity in a [[kerberos|Kerberos]] realm β€” either a user (`alice@EXAMPLE.COM`) or a service (`HTTP/web1.example.com@EXAMPLE.COM`). Each principal has a long-term key derived from its password (users) or stored in a {{kerberos-keytab|keytab}} (services).", - category: 'security' + id: 'kerberos-principal', + term: 'Kerberos Principal', + definition: + 'Named identity in a [[kerberos|Kerberos]] realm β€” either a user (`alice@EXAMPLE.COM`) or a service (`HTTP/web1.example.com@EXAMPLE.COM`). Each principal has a long-term key derived from its password (users) or stored in a {{kerberos-keytab|keytab}} (services).', + category: 'security' }, { - id: 'kerberos-authenticator', - term: 'Kerberos Authenticator', - definition: - "Small encrypted blob the client builds fresh per request β€” typically containing a timestamp and the client's principal. {{encryption|Encrypted}} under the session key inside whichever ticket it accompanies. Proves the client *just now* holds the key β€” not just that it once did.", - category: 'security' + id: 'kerberos-authenticator', + term: 'Kerberos Authenticator', + definition: + "Small encrypted blob the client builds fresh per request β€” typically containing a timestamp and the client's principal. {{encryption|Encrypted}} under the session key inside whichever ticket it accompanies. Proves the client *just now* holds the key β€” not just that it once did.", + category: 'security' }, { - id: 'kerberos-keytab', - term: 'Kerberos Keytab', - definition: - "File on a service host that stores the long-term keys for service {{kerberos-principal|principals}}. The service uses its keytab to decrypt incoming {{kerberos-service-ticket|service tickets}} in {{kerberos-ap-req|AP-REQ}} β€” without contacting the {{kerberos-kdc|KDC}}.", - category: 'security' + id: 'kerberos-keytab', + term: 'Kerberos Keytab', + definition: + 'File on a service host that stores the long-term keys for service {{kerberos-principal|principals}}. The service uses its keytab to decrypt incoming {{kerberos-service-ticket|service tickets}} in {{kerberos-ap-req|AP-REQ}} β€” without contacting the {{kerberos-kdc|KDC}}.', + category: 'security' }, { - id: 'kerberos-service-ticket', - term: 'Kerberos Service Ticket', - definition: - "Per-service [[kerberos|Kerberos]] credential returned in {{kerberos-tgs-rep|TGS-REP}}. {{encryption|Encrypted}} under the target service's long-term key (so only that service can read it), containing the client identity and a fresh client<->service session key.", - category: 'security' + id: 'kerberos-service-ticket', + term: 'Kerberos Service Ticket', + definition: + "Per-service [[kerberos|Kerberos]] credential returned in {{kerberos-tgs-rep|TGS-REP}}. {{encryption|Encrypted}} under the target service's long-term key (so only that service can read it), containing the client identity and a fresh client<->service session key.", + category: 'security' }, { - id: 'kerberos-pa-enc-timestamp', - term: 'PA-ENC-TIMESTAMP', - definition: - "Pre-authentication data attached to a [[kerberos|Kerberos]] {{kerberos-as-req|AS-REQ}}: a fresh timestamp {{encryption|encrypted}} under the user's password-derived key. Lets the {{kerberos-kdc|KDC}} verify the user knows their password before issuing a {{kerberos-tgt|TGT}} β€” blocks offline-cracking attacks on AS-REP.", - category: 'security' + id: 'kerberos-pa-enc-timestamp', + term: 'PA-ENC-TIMESTAMP', + definition: + "Pre-authentication data attached to a [[kerberos|Kerberos]] {{kerberos-as-req|AS-REQ}}: a fresh timestamp {{encryption|encrypted}} under the user's password-derived key. Lets the {{kerberos-kdc|KDC}} verify the user knows their password before issuing a {{kerberos-tgt|TGT}} β€” blocks offline-cracking attacks on AS-REP.", + category: 'security' }, { - id: 'kerberos-as-req', - term: 'Kerberos AS-REQ', - definition: - "First [[kerberos|Kerberos]] message β€” client to {{kerberos-kdc|KDC}} Authentication Service. Carries the client's {{kerberos-principal|principal}} name, requested {{kerberos-tgt|TGT}} options, and {{kerberos-pa-enc-timestamp|PA-ENC-TIMESTAMP}}.", - category: 'security' + id: 'kerberos-as-req', + term: 'Kerberos AS-REQ', + definition: + "First [[kerberos|Kerberos]] message β€” client to {{kerberos-kdc|KDC}} Authentication Service. Carries the client's {{kerberos-principal|principal}} name, requested {{kerberos-tgt|TGT}} options, and {{kerberos-pa-enc-timestamp|PA-ENC-TIMESTAMP}}.", + category: 'security' }, { - id: 'kerberos-as-rep', - term: 'Kerberos AS-REP', - definition: - "{{kerberos-kdc|KDC}} response to a successful {{kerberos-as-req|AS-REQ}}. Carries the {{kerberos-tgt|TGT}} ({{encryption|encrypted}} under {{kerberos-krbtgt|krbtgt}}) and the new session key (encrypted under the user's long-term key).", - category: 'security' + id: 'kerberos-as-rep', + term: 'Kerberos AS-REP', + definition: + "{{kerberos-kdc|KDC}} response to a successful {{kerberos-as-req|AS-REQ}}. Carries the {{kerberos-tgt|TGT}} ({{encryption|encrypted}} under {{kerberos-krbtgt|krbtgt}}) and the new session key (encrypted under the user's long-term key).", + category: 'security' }, { - id: 'kerberos-tgs-req', - term: 'Kerberos TGS-REQ', - definition: - "Request from a [[kerberos|Kerberos]] client to the {{kerberos-tgs|Ticket Granting Service}}: give me a ticket for service X. Carries the {{kerberos-tgt|TGT}} and a fresh {{kerberos-authenticator|authenticator}} encrypted under the TGT's session key.", - category: 'security' + id: 'kerberos-tgs-req', + term: 'Kerberos TGS-REQ', + definition: + "Request from a [[kerberos|Kerberos]] client to the {{kerberos-tgs|Ticket Granting Service}}: give me a ticket for service X. Carries the {{kerberos-tgt|TGT}} and a fresh {{kerberos-authenticator|authenticator}} encrypted under the TGT's session key.", + category: 'security' }, { - id: 'kerberos-tgs-rep', - term: 'Kerberos TGS-REP', - definition: - "{{kerberos-tgs|TGS}} response to a successful {{kerberos-tgs-req|TGS-REQ}}: returns a {{kerberos-service-ticket|service ticket}} (encrypted under the service's long-term key) plus the new client<->service session key.", - category: 'security' + id: 'kerberos-tgs-rep', + term: 'Kerberos TGS-REP', + definition: + "{{kerberos-tgs|TGS}} response to a successful {{kerberos-tgs-req|TGS-REQ}}: returns a {{kerberos-service-ticket|service ticket}} (encrypted under the service's long-term key) plus the new client<->service session key.", + category: 'security' }, { - id: 'kerberos-ap-req', - term: 'Kerberos AP-REQ', - definition: - "Message the client sends *to the service* (not the KDC): the {{kerberos-service-ticket|service ticket}} plus a fresh {{kerberos-authenticator|authenticator}}. The service decrypts with its {{kerberos-keytab|keytab}}, verifies the authenticator's timestamp is within Β±5 min, and authenticates the client.", - category: 'security' + id: 'kerberos-ap-req', + term: 'Kerberos AP-REQ', + definition: + "Message the client sends *to the service* (not the KDC): the {{kerberos-service-ticket|service ticket}} plus a fresh {{kerberos-authenticator|authenticator}}. The service decrypts with its {{kerberos-keytab|keytab}}, verifies the authenticator's timestamp is within Β±5 min, and authenticates the client.", + category: 'security' }, { - id: 'kerberos-ap-rep', - term: 'Kerberos AP-REP', - definition: - "Optional reply from the service to the client β€” an encrypted timestamp proving the service also knows the session key. Provides mutual authentication: client now knows the service is genuine, not an impostor with a stolen ticket.", - category: 'security' + id: 'kerberos-ap-rep', + term: 'Kerberos AP-REP', + definition: + 'Optional reply from the service to the client β€” an encrypted timestamp proving the service also knows the session key. Provides mutual authentication: client now knows the service is genuine, not an impostor with a stolen ticket.', + category: 'security' }, { - id: 'nameserver', - term: 'Nameserver', - definition: - "A [[dns|DNS]] server that holds and serves zone data. Three flavors matter: **root** (knows the {{tld|TLDs}}), **TLD** (knows the registrars' authoritative servers), and **authoritative** (the final source of truth for a domain's records).", - wikiUrl: 'https://en.wikipedia.org/wiki/Name_server', - category: 'infrastructure' + id: 'nameserver', + term: 'Nameserver', + definition: + "A [[dns|DNS]] server that holds and serves zone data. Three flavors matter: **root** (knows the {{tld|TLDs}}), **TLD** (knows the registrars' authoritative servers), and **authoritative** (the final source of truth for a domain's records).", + wikiUrl: 'https://en.wikipedia.org/wiki/Name_server', + category: 'infrastructure' }, { - id: 'tld', - term: 'TLD (Top-Level Domain)', - definition: - "The rightmost label of a domain name β€” `.com`, `.org`, `.net`, country codes like `.uk`. Run by registries (Verisign for `.com`); their {{nameserver|nameservers}} know which {{authoritative-nameserver|authoritative server}} owns each second-level domain.", - wikiUrl: 'https://en.wikipedia.org/wiki/Top-level_domain', - category: 'infrastructure' + id: 'tld', + term: 'TLD (Top-Level Domain)', + definition: + 'The rightmost label of a domain name β€” `.com`, `.org`, `.net`, country codes like `.uk`. Run by registries (Verisign for `.com`); their {{nameserver|nameservers}} know which {{authoritative-nameserver|authoritative server}} owns each second-level domain.', + wikiUrl: 'https://en.wikipedia.org/wiki/Top-level_domain', + category: 'infrastructure' }, { - id: 'root-server', - term: 'Root Nameserver', - definition: - "One of 13 logical {{nameserver|nameservers}} (`a.root-servers.net` … `m.root-servers.net`, replicated globally via {{anycast|anycast}}) that anchor the [[dns|DNS]] hierarchy. They don't know specific domains β€” they just know which {{tld|TLD}} server to ask next.", - wikiUrl: 'https://en.wikipedia.org/wiki/Root_name_server', - category: 'infrastructure' + id: 'root-server', + term: 'Root Nameserver', + definition: + "One of 13 logical {{nameserver|nameservers}} (`a.root-servers.net` … `m.root-servers.net`, replicated globally via {{anycast|anycast}}) that anchor the [[dns|DNS]] hierarchy. They don't know specific domains β€” they just know which {{tld|TLD}} server to ask next.", + wikiUrl: 'https://en.wikipedia.org/wiki/Root_name_server', + category: 'infrastructure' }, { - id: 'authoritative-nameserver', - term: 'Authoritative Nameserver', - definition: - "A {{nameserver|nameserver}} that holds the definitive records for a domain (set by the registrant). Returns *answers*, not referrals β€” the final stop in {{iterative-resolution|iterative resolution}}.", - wikiUrl: 'https://en.wikipedia.org/wiki/Name_server#Authoritative_name_server', - category: 'infrastructure' + id: 'authoritative-nameserver', + term: 'Authoritative Nameserver', + definition: + 'A {{nameserver|nameserver}} that holds the definitive records for a domain (set by the registrant). Returns *answers*, not referrals β€” the final stop in {{iterative-resolution|iterative resolution}}.', + wikiUrl: 'https://en.wikipedia.org/wiki/Name_server#Authoritative_name_server', + category: 'infrastructure' }, { - id: 'recursive-resolver', - term: 'Recursive Resolver', - definition: - "A [[dns|DNS]] server that does the legwork of resolution on the client's behalf β€” walks the hierarchy ({{root-server|root}} β†’ {{tld|TLD}} β†’ {{authoritative-nameserver|authoritative}}) and returns the final answer. Caches aggressively. Operated by ISPs and public services like `1.1.1.1` or `8.8.8.8`.", - wikiUrl: 'https://en.wikipedia.org/wiki/Domain_Name_System#DNS_resolvers', - category: 'infrastructure' + id: 'recursive-resolver', + term: 'Recursive Resolver', + definition: + "A [[dns|DNS]] server that does the legwork of resolution on the client's behalf β€” walks the hierarchy ({{root-server|root}} β†’ {{tld|TLD}} β†’ {{authoritative-nameserver|authoritative}}) and returns the final answer. Caches aggressively. Operated by ISPs and public services like `1.1.1.1` or `8.8.8.8`.", + wikiUrl: 'https://en.wikipedia.org/wiki/Domain_Name_System#DNS_resolvers', + category: 'infrastructure' }, { - id: 'iterative-resolution', - term: 'Iterative Resolution', - definition: - "DNS lookup strategy where the {{recursive-resolver|resolver}} walks the hierarchy itself β€” each {{nameserver|nameserver}} answers *go ask this other server* (a referral), not the final answer, until an {{authoritative-nameserver|authoritative}} server replies with the record.", - wikiUrl: 'https://en.wikipedia.org/wiki/Domain_Name_System#DNS_resolvers', - category: 'protocol-mechanics' + id: 'iterative-resolution', + term: 'Iterative Resolution', + definition: + 'DNS lookup strategy where the {{recursive-resolver|resolver}} walks the hierarchy itself β€” each {{nameserver|nameserver}} answers *go ask this other server* (a referral), not the final answer, until an {{authoritative-nameserver|authoritative}} server replies with the record.', + wikiUrl: 'https://en.wikipedia.org/wiki/Domain_Name_System#DNS_resolvers', + category: 'protocol-mechanics' }, { - id: 'a-record', - term: 'A Record', - definition: - "Address record β€” maps a domain name to a 32-bit IPv4 address. The most basic [[dns|DNS]] record type; the answer to *what's `example.com`'s IP?*.", - wikiUrl: 'https://en.wikipedia.org/wiki/List_of_DNS_record_types', - category: 'infrastructure' + id: 'a-record', + term: 'A Record', + definition: + "Address record β€” maps a domain name to a 32-bit IPv4 address. The most basic [[dns|DNS]] record type; the answer to *what's `example.com`'s IP?*.", + wikiUrl: 'https://en.wikipedia.org/wiki/List_of_DNS_record_types', + category: 'infrastructure' }, { - id: 'aaaa-record', - term: 'AAAA Record', - definition: - "Quad-A record β€” maps a domain name to a 128-bit [[ipv6|IPv6]] address. The [[ipv6|IPv6]] counterpart to the {{a-record|A record}}.", - wikiUrl: 'https://en.wikipedia.org/wiki/IPv6_address#Domain_Name_System', - category: 'infrastructure' + id: 'aaaa-record', + term: 'AAAA Record', + definition: + 'Quad-A record β€” maps a domain name to a 128-bit [[ipv6|IPv6]] address. The [[ipv6|IPv6]] counterpart to the {{a-record|A record}}.', + wikiUrl: 'https://en.wikipedia.org/wiki/IPv6_address#Domain_Name_System', + category: 'infrastructure' }, { - id: 'cname-record', - term: 'CNAME Record', - definition: - "Canonical Name record. A [[dns|DNS]] alias β€” *`www.example.com` is really called `example.com`*. Resolvers chase the chain until they hit an {{a-record|A}}/{{aaaa-record|AAAA}}.", - wikiUrl: 'https://en.wikipedia.org/wiki/CNAME_record', - category: 'infrastructure' + id: 'cname-record', + term: 'CNAME Record', + definition: + 'Canonical Name record. A [[dns|DNS]] alias β€” *`www.example.com` is really called `example.com`*. Resolvers chase the chain until they hit an {{a-record|A}}/{{aaaa-record|AAAA}}.', + wikiUrl: 'https://en.wikipedia.org/wiki/CNAME_record', + category: 'infrastructure' }, { - id: 'ns-record', - term: 'NS Record', - definition: - "Nameserver record. Delegates a [[dns|DNS]] zone to a set of {{authoritative-nameserver|authoritative nameservers}}. How the parent zone (e.g. `.com`) points to the child zone's nameservers.", - wikiUrl: 'https://en.wikipedia.org/wiki/List_of_DNS_record_types#NS', - category: 'infrastructure' + id: 'ns-record', + term: 'NS Record', + definition: + "Nameserver record. Delegates a [[dns|DNS]] zone to a set of {{authoritative-nameserver|authoritative nameservers}}. How the parent zone (e.g. `.com`) points to the child zone's nameservers.", + wikiUrl: 'https://en.wikipedia.org/wiki/List_of_DNS_record_types#NS', + category: 'infrastructure' }, { - id: 'dora', - term: 'DORA (Discover, Offer, Request, Ack)', - definition: - "The mnemonic for the four-message [[dhcp|DHCP]] {{handshake|exchange}}: **D**ISCOVER (client broadcasts), **O**FFER (server proposes), **R**EQUEST (client accepts), **A**CK (server confirms). Yields an {{ip-address|IP address}}, gateway, [[dns|DNS]] settings, and {{dhcp-lease|lease}}.", - wikiUrl: 'https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol#Operation', - category: 'protocol-mechanics' + id: 'dora', + term: 'DORA (Discover, Offer, Request, Ack)', + definition: + 'The mnemonic for the four-message [[dhcp|DHCP]] {{handshake|exchange}}: **D**ISCOVER (client broadcasts), **O**FFER (server proposes), **R**EQUEST (client accepts), **A**CK (server confirms). Yields an {{ip-address|IP address}}, gateway, [[dns|DNS]] settings, and {{dhcp-lease|lease}}.', + wikiUrl: 'https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol#Operation', + category: 'protocol-mechanics' }, { - id: 'dhcp-discover', - term: 'DHCPDISCOVER', - definition: - "The first message of the {{dora|DORA}} {{handshake|exchange}}. A new client {{broadcast|broadcasts}} *I need an IP* from `0.0.0.0` to `255.255.255.255` so any [[dhcp|DHCP]] server on the {{lan|LAN}} can hear it.", - wikiUrl: 'https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol', - category: 'protocol-mechanics' + id: 'dhcp-discover', + term: 'DHCPDISCOVER', + definition: + 'The first message of the {{dora|DORA}} {{handshake|exchange}}. A new client {{broadcast|broadcasts}} *I need an IP* from `0.0.0.0` to `255.255.255.255` so any [[dhcp|DHCP]] server on the {{lan|LAN}} can hear it.', + wikiUrl: 'https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol', + category: 'protocol-mechanics' }, { - id: 'dhcp-offer', - term: 'DHCPOFFER', - definition: - "The server's reply in the {{dora|DORA}} {{handshake|exchange}}: *here's a candidate {{ip-address|IP}} from my pool, plus a {{dhcp-lease|lease}} time*. Multiple servers may offer; the client picks one.", - wikiUrl: 'https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol', - category: 'protocol-mechanics' + id: 'dhcp-offer', + term: 'DHCPOFFER', + definition: + "The server's reply in the {{dora|DORA}} {{handshake|exchange}}: *here's a candidate {{ip-address|IP}} from my pool, plus a {{dhcp-lease|lease}} time*. Multiple servers may offer; the client picks one.", + wikiUrl: 'https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol', + category: 'protocol-mechanics' }, { - id: 'dhcp-request', - term: 'DHCPREQUEST', - definition: - "Third message of {{dora|DORA}}: client confirms *I'll take this offer*. Also {{broadcast|broadcast}} so other [[dhcp|DHCP]] servers know to release their offers.", - wikiUrl: 'https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol', - category: 'protocol-mechanics' + id: 'dhcp-request', + term: 'DHCPREQUEST', + definition: + "Third message of {{dora|DORA}}: client confirms *I'll take this offer*. Also {{broadcast|broadcast}} so other [[dhcp|DHCP]] servers know to release their offers.", + wikiUrl: 'https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol', + category: 'protocol-mechanics' }, { - id: 'dhcp-ack', - term: 'DHCPACK', - definition: - "Final message of {{dora|DORA}}: server confirms the {{dhcp-lease|lease}} and ships the full network config (subnet mask, default gateway, [[dns|DNS]] servers).", - wikiUrl: 'https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol', - category: 'protocol-mechanics' + id: 'dhcp-ack', + term: 'DHCPACK', + definition: + 'Final message of {{dora|DORA}}: server confirms the {{dhcp-lease|lease}} and ships the full network config (subnet mask, default gateway, [[dns|DNS]] servers).', + wikiUrl: 'https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol', + category: 'protocol-mechanics' }, { - id: 'dhcp-lease', - term: 'DHCP Lease', - definition: - "A time-bounded grant of an {{ip-address|IP address}} by a [[dhcp|DHCP]] server. Clients renew at T1 (~50%) and T2 (~87.5%) of the lease duration; if neither succeeds, they re-{{dhcp-discover|DISCOVER}} before expiry.", - wikiUrl: 'https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol#Lease', - category: 'protocol-mechanics' + id: 'dhcp-lease', + term: 'DHCP Lease', + definition: + 'A time-bounded grant of an {{ip-address|IP address}} by a [[dhcp|DHCP]] server. Clients renew at T1 (~50%) and T2 (~87.5%) of the lease duration; if neither succeeds, they re-{{dhcp-discover|DISCOVER}} before expiry.', + wikiUrl: 'https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol#Lease', + category: 'protocol-mechanics' }, { - id: 'clock-drift', - term: 'Clock Drift', - definition: - "The tendency of a hardware clock to deviate from true time. Crystal oscillators in computers gain or lose seconds per day; [[ntp|NTP]] and PTP correct for this continuously.", - wikiUrl: 'https://en.wikipedia.org/wiki/Clock_drift', - category: 'networking-basics' + id: 'clock-drift', + term: 'Clock Drift', + definition: + 'The tendency of a hardware clock to deviate from true time. Crystal oscillators in computers gain or lose seconds per day; [[ntp|NTP]] and PTP correct for this continuously.', + wikiUrl: 'https://en.wikipedia.org/wiki/Clock_drift', + category: 'networking-basics' }, { - id: 'marzullos-algorithm', - term: "Marzullo's Algorithm", - definition: - "Algorithm that finds the smallest interval consistent with the largest number of estimates, used by [[ntp|NTP]] to discard outlier time samples and converge on a single accurate offset.", - wikiUrl: 'https://en.wikipedia.org/wiki/Marzullo%27s_algorithm', - category: 'protocol-mechanics' + id: 'marzullos-algorithm', + term: "Marzullo's Algorithm", + definition: + 'Algorithm that finds the smallest interval consistent with the largest number of estimates, used by [[ntp|NTP]] to discard outlier time samples and converge on a single accurate offset.', + wikiUrl: 'https://en.wikipedia.org/wiki/Marzullo%27s_algorithm', + category: 'protocol-mechanics' }, { - id: 'nts', - term: 'NTS (Network Time Security)', - definition: - "Cryptographic extension to [[ntp|NTP]] ([[rfc:8915|RFC 8915]]) that authenticates time replies β€” defeats {{man-in-the-middle|MITM}} attackers who would otherwise manipulate clocks to break certificate validation.", - wikiUrl: 'https://en.wikipedia.org/wiki/Network_Time_Security', - category: 'security' + id: 'nts', + term: 'NTS (Network Time Security)', + definition: + 'Cryptographic extension to [[ntp|NTP]] ([[rfc:8915|RFC 8915]]) that authenticates time replies β€” defeats {{man-in-the-middle|MITM}} attackers who would otherwise manipulate clocks to break certificate validation.', + wikiUrl: 'https://en.wikipedia.org/wiki/Network_Time_Security', + category: 'security' }, { - id: 'ping', - term: 'ping', - definition: - "The simplest reachability test on the internet. Sends an [[icmp|ICMP]] {{echo-request|Echo Request}} and times the {{echo-reply|Echo Reply}} β€” gives you {{rtt|round-trip time}} and packet-loss percentage.", - wikiUrl: 'https://en.wikipedia.org/wiki/Ping_(networking_utility)', - category: 'infrastructure' + id: 'ping', + term: 'ping', + definition: + 'The simplest reachability test on the internet. Sends an [[icmp|ICMP]] {{echo-request|Echo Request}} and times the {{echo-reply|Echo Reply}} β€” gives you {{rtt|round-trip time}} and packet-loss percentage.', + wikiUrl: 'https://en.wikipedia.org/wiki/Ping_(networking_utility)', + category: 'infrastructure' }, { - id: 'traceroute', - term: 'traceroute', - definition: - "Diagnostic that maps the {{hop|hops}} between you and a destination. Sends packets with increasing {{ttl|TTL}} (1, 2, 3 …); each router whose TTL hits 0 returns an [[icmp|ICMP]] {{time-exceeded|Time Exceeded}}, revealing its address.", - wikiUrl: 'https://en.wikipedia.org/wiki/Traceroute', - category: 'infrastructure' + id: 'traceroute', + term: 'traceroute', + definition: + 'Diagnostic that maps the {{hop|hops}} between you and a destination. Sends packets with increasing {{ttl|TTL}} (1, 2, 3 …); each router whose TTL hits 0 returns an [[icmp|ICMP]] {{time-exceeded|Time Exceeded}}, revealing its address.', + wikiUrl: 'https://en.wikipedia.org/wiki/Traceroute', + category: 'infrastructure' }, { - id: 'echo-request', - term: 'Echo Request (ICMP Type 8)', - definition: - "The [[icmp|ICMP]] message {{ping|ping}} sends. Type 8 for IPv4, Type 128 for [[ipv6|IPv6]] ({{icmpv6|ICMPv6}}). Carries an identifier + sequence number; the {{echo-reply|Echo Reply}} copies them back.", - wikiUrl: 'https://en.wikipedia.org/wiki/Internet_Control_Message_Protocol#Echo_request', - category: 'protocol-mechanics' + id: 'echo-request', + term: 'Echo Request (ICMP Type 8)', + definition: + 'The [[icmp|ICMP]] message {{ping|ping}} sends. Type 8 for IPv4, Type 128 for [[ipv6|IPv6]] ({{icmpv6|ICMPv6}}). Carries an identifier + sequence number; the {{echo-reply|Echo Reply}} copies them back.', + wikiUrl: 'https://en.wikipedia.org/wiki/Internet_Control_Message_Protocol#Echo_request', + category: 'protocol-mechanics' }, { - id: 'echo-reply', - term: 'Echo Reply (ICMP Type 0)', - definition: - "The [[icmp|ICMP]] response to an {{echo-request|Echo Request}}. Type 0 for IPv4, Type 129 for [[ipv6|IPv6]]. The send/receive timestamps give you {{rtt|round-trip time}}.", - wikiUrl: 'https://en.wikipedia.org/wiki/Internet_Control_Message_Protocol#Echo_reply', - category: 'protocol-mechanics' + id: 'echo-reply', + term: 'Echo Reply (ICMP Type 0)', + definition: + 'The [[icmp|ICMP]] response to an {{echo-request|Echo Request}}. Type 0 for IPv4, Type 129 for [[ipv6|IPv6]]. The send/receive timestamps give you {{rtt|round-trip time}}.', + wikiUrl: 'https://en.wikipedia.org/wiki/Internet_Control_Message_Protocol#Echo_reply', + category: 'protocol-mechanics' }, { - id: 'time-exceeded', - term: 'Time Exceeded (ICMP Type 11)', - definition: - "[[icmp|ICMP]] error sent by a router when a packet's {{ttl|TTL}} hits 0. {{traceroute|traceroute}} relies on this β€” each TTL value reveals one more {{hop|hop}} along the path.", - wikiUrl: 'https://en.wikipedia.org/wiki/Internet_Control_Message_Protocol#Time_exceeded', - category: 'protocol-mechanics' + id: 'time-exceeded', + term: 'Time Exceeded (ICMP Type 11)', + definition: + "[[icmp|ICMP]] error sent by a router when a packet's {{ttl|TTL}} hits 0. {{traceroute|traceroute}} relies on this β€” each TTL value reveals one more {{hop|hop}} along the path.", + wikiUrl: 'https://en.wikipedia.org/wiki/Internet_Control_Message_Protocol#Time_exceeded', + category: 'protocol-mechanics' }, { - id: 'arp-cache', - term: 'ARP Cache', - definition: - "Per-host table of recently-learned IPβ†’{{mac-address|MAC}} mappings. [[arp|ARP]] consults it before broadcasting a request; entries expire after 1–5 minutes (OS-dependent) so changes propagate.", - wikiUrl: 'https://en.wikipedia.org/wiki/Address_Resolution_Protocol#ARP_cache', - category: 'networking-basics' + id: 'arp-cache', + term: 'ARP Cache', + definition: + 'Per-host table of recently-learned IPβ†’{{mac-address|MAC}} mappings. [[arp|ARP]] consults it before broadcasting a request; entries expire after 1–5 minutes (OS-dependent) so changes propagate.', + wikiUrl: 'https://en.wikipedia.org/wiki/Address_Resolution_Protocol#ARP_cache', + category: 'networking-basics' }, { - id: 'arp-request', - term: 'ARP Request', - definition: - "The *who has this {{ip-address|IP}}?* {{broadcast|broadcast}} sent to destination [[ethernet|Ethernet]] address `FF:FF:FF:FF:FF:FF` so every host on the {{lan|LAN}} receives and processes it.", - wikiUrl: 'https://en.wikipedia.org/wiki/Address_Resolution_Protocol', - category: 'protocol-mechanics' + id: 'arp-request', + term: 'ARP Request', + definition: + 'The *who has this {{ip-address|IP}}?* {{broadcast|broadcast}} sent to destination [[ethernet|Ethernet]] address `FF:FF:FF:FF:FF:FF` so every host on the {{lan|LAN}} receives and processes it.', + wikiUrl: 'https://en.wikipedia.org/wiki/Address_Resolution_Protocol', + category: 'protocol-mechanics' }, { - id: 'arp-reply', - term: 'ARP Reply', - definition: - "The {{unicast|unicast}} response to an {{arp-request|ARP Request}} carrying the answering host's {{mac-address|MAC address}}. Only the matching host responds.", - wikiUrl: 'https://en.wikipedia.org/wiki/Address_Resolution_Protocol', - category: 'protocol-mechanics' + id: 'arp-reply', + term: 'ARP Reply', + definition: + "The {{unicast|unicast}} response to an {{arp-request|ARP Request}} carrying the answering host's {{mac-address|MAC address}}. Only the matching host responds.", + wikiUrl: 'https://en.wikipedia.org/wiki/Address_Resolution_Protocol', + category: 'protocol-mechanics' }, { - id: 'bgp-open', - term: 'BGP OPEN', - definition: - "First [[bgp|BGP]] message after the [[tcp|TCP]] connection forms β€” peers exchange their {{asn|AS number}}, BGP version, {{hold-timer|hold time}}, and a router ID. Failure aborts the session.", - wikiUrl: 'https://en.wikipedia.org/wiki/Border_Gateway_Protocol', - category: 'protocol-mechanics' + id: 'bgp-open', + term: 'BGP OPEN', + definition: + 'First [[bgp|BGP]] message after the [[tcp|TCP]] connection forms β€” peers exchange their {{asn|AS number}}, BGP version, {{hold-timer|hold time}}, and a router ID. Failure aborts the session.', + wikiUrl: 'https://en.wikipedia.org/wiki/Border_Gateway_Protocol', + category: 'protocol-mechanics' }, { - id: 'bgp-update', - term: 'BGP UPDATE', - definition: - "The workhorse [[bgp|BGP]] message β€” announces new routes (NLRI + path attributes like {{as-path|AS_PATH}}, NEXT_HOP, LOCAL_PREF, MED) or withdraws previously announced ones.", - wikiUrl: 'https://en.wikipedia.org/wiki/Border_Gateway_Protocol', - category: 'protocol-mechanics' + id: 'bgp-update', + term: 'BGP UPDATE', + definition: + 'The workhorse [[bgp|BGP]] message β€” announces new routes (NLRI + path attributes like {{as-path|AS_PATH}}, NEXT_HOP, LOCAL_PREF, MED) or withdraws previously announced ones.', + wikiUrl: 'https://en.wikipedia.org/wiki/Border_Gateway_Protocol', + category: 'protocol-mechanics' }, { - id: 'bgp-keepalive', - term: 'BGP KEEPALIVE', - definition: - "Tiny 19-byte heartbeat sent every ~30s on quiet [[bgp|BGP]] sessions. Proves the peer is alive even when there's nothing to {{bgp-update|UPDATE}}. Resets the {{hold-timer|hold timer}}.", - wikiUrl: 'https://en.wikipedia.org/wiki/Border_Gateway_Protocol', - category: 'protocol-mechanics' + id: 'bgp-keepalive', + term: 'BGP KEEPALIVE', + definition: + "Tiny 19-byte heartbeat sent every ~30s on quiet [[bgp|BGP]] sessions. Proves the peer is alive even when there's nothing to {{bgp-update|UPDATE}}. Resets the {{hold-timer|hold timer}}.", + wikiUrl: 'https://en.wikipedia.org/wiki/Border_Gateway_Protocol', + category: 'protocol-mechanics' }, { - id: 'hold-timer', - term: 'Hold Timer', - definition: - "How long a [[bgp|BGP]] peer waits without receiving a {{bgp-keepalive|KEEPALIVE}} or {{bgp-update|UPDATE}} before declaring the neighbor dead. Default 90s, negotiated in {{bgp-open|OPEN}}.", - wikiUrl: 'https://en.wikipedia.org/wiki/Border_Gateway_Protocol', - category: 'protocol-mechanics' + id: 'hold-timer', + term: 'Hold Timer', + definition: + 'How long a [[bgp|BGP]] peer waits without receiving a {{bgp-keepalive|KEEPALIVE}} or {{bgp-update|UPDATE}} before declaring the neighbor dead. Default 90s, negotiated in {{bgp-open|OPEN}}.', + wikiUrl: 'https://en.wikipedia.org/wiki/Border_Gateway_Protocol', + category: 'protocol-mechanics' }, { - id: 'router-solicitation', - term: 'Router Solicitation (ICMPv6 Type 133)', - definition: - "{{ndp|NDP}} message a new host sends to find any routers on the link. Multicast to `ff02::2` (all-routers). Routers reply with {{router-advertisement|Router Advertisements}}.", - wikiUrl: 'https://en.wikipedia.org/wiki/Neighbor_Discovery_Protocol', - category: 'protocol-mechanics' + id: 'router-solicitation', + term: 'Router Solicitation (ICMPv6 Type 133)', + definition: + '{{ndp|NDP}} message a new host sends to find any routers on the link. Multicast to `ff02::2` (all-routers). Routers reply with {{router-advertisement|Router Advertisements}}.', + wikiUrl: 'https://en.wikipedia.org/wiki/Neighbor_Discovery_Protocol', + category: 'protocol-mechanics' }, { - id: 'router-advertisement', - term: 'Router Advertisement (ICMPv6 Type 134)', - definition: - "{{ndp|NDP}} message routers send (periodically or in response to {{router-solicitation|Router Solicitation}}) carrying the link prefix, MTU, default gateway, and flags that drive [[ipv6|IPv6]] autoconfiguration ({{slaac|SLAAC}}).", - wikiUrl: 'https://en.wikipedia.org/wiki/Neighbor_Discovery_Protocol', - category: 'protocol-mechanics' + id: 'router-advertisement', + term: 'Router Advertisement (ICMPv6 Type 134)', + definition: + '{{ndp|NDP}} message routers send (periodically or in response to {{router-solicitation|Router Solicitation}}) carrying the link prefix, MTU, default gateway, and flags that drive [[ipv6|IPv6]] autoconfiguration ({{slaac|SLAAC}}).', + wikiUrl: 'https://en.wikipedia.org/wiki/Neighbor_Discovery_Protocol', + category: 'protocol-mechanics' }, { - id: 'neighbor-solicitation', - term: 'Neighbor Solicitation (ICMPv6 Type 135)', - definition: - "{{ndp|NDP}} message β€” the [[ipv6|IPv6]] equivalent of [[arp|ARP Request]]. Asks *who has this address?*, sent to a {{solicited-node-multicast|solicited-node multicast}} address so only candidate matches process it.", - wikiUrl: 'https://en.wikipedia.org/wiki/Neighbor_Discovery_Protocol', - category: 'protocol-mechanics' + id: 'neighbor-solicitation', + term: 'Neighbor Solicitation (ICMPv6 Type 135)', + definition: + '{{ndp|NDP}} message β€” the [[ipv6|IPv6]] equivalent of [[arp|ARP Request]]. Asks *who has this address?*, sent to a {{solicited-node-multicast|solicited-node multicast}} address so only candidate matches process it.', + wikiUrl: 'https://en.wikipedia.org/wiki/Neighbor_Discovery_Protocol', + category: 'protocol-mechanics' }, { - id: 'neighbor-advertisement', - term: 'Neighbor Advertisement (ICMPv6 Type 136)', - definition: - "{{ndp|NDP}} message β€” the [[ipv6|IPv6]] equivalent of [[arp|ARP Reply]]. Carries the responder's link-layer address. Also sent unsolicited when an address changes.", - wikiUrl: 'https://en.wikipedia.org/wiki/Neighbor_Discovery_Protocol', - category: 'protocol-mechanics' + id: 'neighbor-advertisement', + term: 'Neighbor Advertisement (ICMPv6 Type 136)', + definition: + "{{ndp|NDP}} message β€” the [[ipv6|IPv6]] equivalent of [[arp|ARP Reply]]. Carries the responder's link-layer address. Also sent unsolicited when an address changes.", + wikiUrl: 'https://en.wikipedia.org/wiki/Neighbor_Discovery_Protocol', + category: 'protocol-mechanics' }, { - id: 'solicited-node-multicast', - term: 'Solicited-Node Multicast', - definition: - "An [[ipv6|IPv6]] {{multicast|multicast}} address derived from the last 24 bits of a host's address (`ff02::1:ffXX:XXXX`). {{ndp|NDP}} uses it instead of {{broadcast|broadcast}} so only ~1 of 2²⁴ hosts processes each query.", - wikiUrl: 'https://en.wikipedia.org/wiki/Solicited-node_multicast_address', - category: 'protocol-mechanics' + id: 'solicited-node-multicast', + term: 'Solicited-Node Multicast', + definition: + "An [[ipv6|IPv6]] {{multicast|multicast}} address derived from the last 24 bits of a host's address (`ff02::1:ffXX:XXXX`). {{ndp|NDP}} uses it instead of {{broadcast|broadcast}} so only ~1 of 2²⁴ hosts processes each query.", + wikiUrl: 'https://en.wikipedia.org/wiki/Solicited-node_multicast_address', + category: 'protocol-mechanics' }, { - id: 'hop-limit', - term: 'Hop Limit', - definition: - "[[ipv6|IPv6]]'s rename of {{ttl|TTL}}. Decremented by 1 at every router; hits 0 β†’ packet dropped + {{icmpv6|ICMPv6}} Time Exceeded returned. Loop prevention.", - wikiUrl: 'https://en.wikipedia.org/wiki/IPv6_packet#Fixed_header', - category: 'protocol-mechanics' + id: 'hop-limit', + term: 'Hop Limit', + definition: + "[[ipv6|IPv6]]'s rename of {{ttl|TTL}}. Decremented by 1 at every router; hits 0 β†’ packet dropped + {{icmpv6|ICMPv6}} Time Exceeded returned. Loop prevention.", + wikiUrl: 'https://en.wikipedia.org/wiki/IPv6_packet#Fixed_header', + category: 'protocol-mechanics' }, { - id: 'icmpv6', - term: 'ICMPv6', - definition: - "[[icmp|ICMP]] for [[ipv6|IPv6]]. Same role β€” diagnostics and errors β€” but also carries {{ndp|NDP}}, MLD, and Router Renumbering. Mandatory; firewalls must not block it blindly.", - wikiUrl: 'https://en.wikipedia.org/wiki/Internet_Control_Message_Protocol_for_IPv6', - category: 'protocol-mechanics' + id: 'icmpv6', + term: 'ICMPv6', + definition: + '[[icmp|ICMP]] for [[ipv6|IPv6]]. Same role β€” diagnostics and errors β€” but also carries {{ndp|NDP}}, MLD, and Router Renumbering. Mandatory; firewalls must not block it blindly.', + wikiUrl: 'https://en.wikipedia.org/wiki/Internet_Control_Message_Protocol_for_IPv6', + category: 'protocol-mechanics' }, { - id: 'router-id', - term: 'Router ID (RID)', - definition: - "32-bit identifier (formatted like an IPv4 address) that uniquely identifies a router in [[ospf|OSPF]] / [[bgp|BGP]]. Usually the highest loopback or active interface address.", - wikiUrl: 'https://en.wikipedia.org/wiki/Open_Shortest_Path_First#Router_ID', - category: 'protocol-mechanics' + id: 'router-id', + term: 'Router ID (RID)', + definition: + '32-bit identifier (formatted like an IPv4 address) that uniquely identifies a router in [[ospf|OSPF]] / [[bgp|BGP]]. Usually the highest loopback or active interface address.', + wikiUrl: 'https://en.wikipedia.org/wiki/Open_Shortest_Path_First#Router_ID', + category: 'protocol-mechanics' }, { - id: 'ospf-hello', - term: 'OSPF Hello', - definition: - "[[ospf|OSPF]] message multicast to `224.0.0.5` every 10s on point-to-point links. Carries router ID, HelloInterval, DeadInterval, neighbors seen β€” must match exactly for {{adjacency|adjacency}} to form.", - wikiUrl: 'https://en.wikipedia.org/wiki/Open_Shortest_Path_First', - category: 'protocol-mechanics' + id: 'ospf-hello', + term: 'OSPF Hello', + definition: + '[[ospf|OSPF]] message multicast to `224.0.0.5` every 10s on point-to-point links. Carries router ID, HelloInterval, DeadInterval, neighbors seen β€” must match exactly for {{adjacency|adjacency}} to form.', + wikiUrl: 'https://en.wikipedia.org/wiki/Open_Shortest_Path_First', + category: 'protocol-mechanics' }, { - id: 'dbd', - term: 'DBD (Database Description)', - definition: - "[[ospf|OSPF]] message exchanged in the ExStart/{{exchange|Exchange}} state. Master/slave is elected by router ID; each side sends {{lsa|LSA}} headers (not full LSAs) so peers learn what they're missing.", - wikiUrl: 'https://en.wikipedia.org/wiki/Open_Shortest_Path_First', - category: 'protocol-mechanics' + id: 'dbd', + term: 'DBD (Database Description)', + definition: + "[[ospf|OSPF]] message exchanged in the ExStart/{{exchange|Exchange}} state. Master/slave is elected by router ID; each side sends {{lsa|LSA}} headers (not full LSAs) so peers learn what they're missing.", + wikiUrl: 'https://en.wikipedia.org/wiki/Open_Shortest_Path_First', + category: 'protocol-mechanics' }, { - id: 'lsr', - term: 'LSR (Link State Request)', - definition: - "[[ospf|OSPF]] message: *send me these {{lsa|LSAs}}*. Used during the Loading state to fetch full link-state records the router doesn't have or has older copies of.", - wikiUrl: 'https://en.wikipedia.org/wiki/Open_Shortest_Path_First', - category: 'protocol-mechanics' + id: 'lsr', + term: 'LSR (Link State Request)', + definition: + "[[ospf|OSPF]] message: *send me these {{lsa|LSAs}}*. Used during the Loading state to fetch full link-state records the router doesn't have or has older copies of.", + wikiUrl: 'https://en.wikipedia.org/wiki/Open_Shortest_Path_First', + category: 'protocol-mechanics' }, { - id: 'lsu', - term: 'LSU (Link State Update)', - definition: - "[[ospf|OSPF]] message carrying one or more {{lsa|LSAs}}. The actual link-state data β€” checksummed, age-stamped, sequence-numbered. Acknowledged by {{lsack|LSAck}}.", - wikiUrl: 'https://en.wikipedia.org/wiki/Open_Shortest_Path_First', - category: 'protocol-mechanics' + id: 'lsu', + term: 'LSU (Link State Update)', + definition: + '[[ospf|OSPF]] message carrying one or more {{lsa|LSAs}}. The actual link-state data β€” checksummed, age-stamped, sequence-numbered. Acknowledged by {{lsack|LSAck}}.', + wikiUrl: 'https://en.wikipedia.org/wiki/Open_Shortest_Path_First', + category: 'protocol-mechanics' }, { - id: 'lsack', - term: 'LSAck (Link State Acknowledgment)', - definition: - "[[ospf|OSPF]] message that acknowledges receipt of an {{lsu|LSU}}. Required because [[ospf|OSPF]] runs directly on [[ip|IP]] (protocol 89) without [[tcp|TCP]] β€” it implements its own reliable delivery.", - wikiUrl: 'https://en.wikipedia.org/wiki/Open_Shortest_Path_First', - category: 'protocol-mechanics' + id: 'lsack', + term: 'LSAck (Link State Acknowledgment)', + definition: + '[[ospf|OSPF]] message that acknowledges receipt of an {{lsu|LSU}}. Required because [[ospf|OSPF]] runs directly on [[ip|IP]] (protocol 89) without [[tcp|TCP]] β€” it implements its own reliable delivery.', + wikiUrl: 'https://en.wikipedia.org/wiki/Open_Shortest_Path_First', + category: 'protocol-mechanics' }, { - id: 'adjacency', - term: 'Adjacency', - definition: - "An [[ospf|OSPF]] relationship between two neighboring routers that has progressed through the eight-state machine (Down β†’ Init β†’ 2-Way β†’ ExStart β†’ {{exchange|Exchange}} β†’ Loading β†’ Full) and now exchanges link-state info.", - wikiUrl: 'https://en.wikipedia.org/wiki/Open_Shortest_Path_First', - category: 'protocol-mechanics' + id: 'adjacency', + term: 'Adjacency', + definition: + 'An [[ospf|OSPF]] relationship between two neighboring routers that has progressed through the eight-state machine (Down β†’ Init β†’ 2-Way β†’ ExStart β†’ {{exchange|Exchange}} β†’ Loading β†’ Full) and now exchanges link-state info.', + wikiUrl: 'https://en.wikipedia.org/wiki/Open_Shortest_Path_First', + category: 'protocol-mechanics' }, { - id: 'fib', - term: 'FIB (Forwarding Information Base)', - definition: - "The compiled, fast-lookup table that the data plane actually uses to forward packets. Derived from the {{routing-table|RIB}} but optimized for line-rate {{ip-address|IP}} matching (typically TCAM in hardware routers).", - wikiUrl: 'https://en.wikipedia.org/wiki/Forwarding_information_base', - category: 'infrastructure' + id: 'fib', + term: 'FIB (Forwarding Information Base)', + definition: + 'The compiled, fast-lookup table that the data plane actually uses to forward packets. Derived from the {{routing-table|RIB}} but optimized for line-rate {{ip-address|IP}} matching (typically TCAM in hardware routers).', + wikiUrl: 'https://en.wikipedia.org/wiki/Forwarding_information_base', + category: 'infrastructure' }, { - id: 'beacon', - term: 'Beacon Frame', - definition: - "[[wifi|Wi-Fi]] management frame broadcast by an {{access-point|AP}} ~10Γ— per second. Carries the {{ssid|SSID}}, supported rates, security mode (WPA2/WPA3), and capabilities β€” how clients discover the network.", - wikiUrl: 'https://en.wikipedia.org/wiki/Beacon_frame', - category: 'protocol-mechanics' + id: 'beacon', + term: 'Beacon Frame', + definition: + '[[wifi|Wi-Fi]] management frame broadcast by an {{access-point|AP}} ~10Γ— per second. Carries the {{ssid|SSID}}, supported rates, security mode (WPA2/WPA3), and capabilities β€” how clients discover the network.', + wikiUrl: 'https://en.wikipedia.org/wiki/Beacon_frame', + category: 'protocol-mechanics' }, { - id: 'ssid', - term: 'SSID (Service Set Identifier)', - definition: - "The human-readable network name advertised by a [[wifi|Wi-Fi]] {{access-point|AP}} (e.g. `MyNetwork`). Up to 32 bytes; multiple APs can share the same SSID to form an ESS.", - wikiUrl: 'https://en.wikipedia.org/wiki/Service_set_(802.11_network)#SSID', - category: 'networking-basics' + id: 'ssid', + term: 'SSID (Service Set Identifier)', + definition: + 'The human-readable network name advertised by a [[wifi|Wi-Fi]] {{access-point|AP}} (e.g. `MyNetwork`). Up to 32 bytes; multiple APs can share the same SSID to form an ESS.', + wikiUrl: 'https://en.wikipedia.org/wiki/Service_set_(802.11_network)#SSID', + category: 'networking-basics' }, { - id: 'authentication-frame', - term: '802.11 Authentication Frame', - definition: - "Legacy [[wifi|802.11]] management frame from before WPA. Today it's a formality β€” modern security happens in the {{wpa2-handshake|WPA2/3 4-way handshake}}. Originally for WEP shared-key auth.", - wikiUrl: 'https://en.wikipedia.org/wiki/IEEE_802.11', - category: 'protocol-mechanics' + id: 'authentication-frame', + term: '802.11 Authentication Frame', + definition: + "Legacy [[wifi|802.11]] management frame from before WPA. Today it's a formality β€” modern security happens in the {{wpa2-handshake|WPA2/3 4-way handshake}}. Originally for WEP shared-key auth.", + wikiUrl: 'https://en.wikipedia.org/wiki/IEEE_802.11', + category: 'protocol-mechanics' }, { - id: 'association-request', - term: 'Association Request', - definition: - "[[wifi|Wi-Fi]] management frame β€” *I want to use this network*. Carries the client's capabilities and the {{ssid|SSID}}. The {{access-point|AP}} replies with an {{association-response|Association Response}} carrying an {{aid|AID}}.", - wikiUrl: 'https://en.wikipedia.org/wiki/IEEE_802.11', - category: 'protocol-mechanics' + id: 'association-request', + term: 'Association Request', + definition: + "[[wifi|Wi-Fi]] management frame β€” *I want to use this network*. Carries the client's capabilities and the {{ssid|SSID}}. The {{access-point|AP}} replies with an {{association-response|Association Response}} carrying an {{aid|AID}}.", + wikiUrl: 'https://en.wikipedia.org/wiki/IEEE_802.11', + category: 'protocol-mechanics' }, { - id: 'association-response', - term: 'Association Response', - definition: - "[[wifi|Wi-Fi]] management frame from the {{access-point|AP}} accepting (or rejecting) an {{association-request|Association Request}}. On success, it carries the assigned {{aid|AID}} (1–2007).", - wikiUrl: 'https://en.wikipedia.org/wiki/IEEE_802.11', - category: 'protocol-mechanics' + id: 'association-response', + term: 'Association Response', + definition: + '[[wifi|Wi-Fi]] management frame from the {{access-point|AP}} accepting (or rejecting) an {{association-request|Association Request}}. On success, it carries the assigned {{aid|AID}} (1–2007).', + wikiUrl: 'https://en.wikipedia.org/wiki/IEEE_802.11', + category: 'protocol-mechanics' }, { - id: 'wpa2-handshake', - term: 'WPA2 4-way Handshake', - definition: - "The post-association {{handshake|exchange}} that derives session keys from the {{pmk|PMK}} (passphrase): {{anonce|ANonce}} β†’ {{snonce|SNonce}}+{{mic|MIC}} β†’ {{gtk|GTK}}+{{mic|MIC}} β†’ {{ack|ACK}}. Both sides prove they know the passphrase without sending it.", - wikiUrl: 'https://en.wikipedia.org/wiki/IEEE_802.11i-2004#The_four-way_handshake', - category: 'security' + id: 'wpa2-handshake', + term: 'WPA2 4-way Handshake', + definition: + 'The post-association {{handshake|exchange}} that derives session keys from the {{pmk|PMK}} (passphrase): {{anonce|ANonce}} β†’ {{snonce|SNonce}}+{{mic|MIC}} β†’ {{gtk|GTK}}+{{mic|MIC}} β†’ {{ack|ACK}}. Both sides prove they know the passphrase without sending it.', + wikiUrl: 'https://en.wikipedia.org/wiki/IEEE_802.11i-2004#The_four-way_handshake', + category: 'security' }, { - id: 'anonce', - term: 'ANonce', - definition: - "Authenticator Nonce β€” the random number the {{access-point|AP}} sends in step 1 of the {{wpa2-handshake|WPA2 4-way handshake}}. Combined with the {{snonce|SNonce}} and both {{mac-address|MAC}} addresses to derive the {{ptk|PTK}}.", - wikiUrl: 'https://en.wikipedia.org/wiki/IEEE_802.11i-2004', - category: 'security' + id: 'anonce', + term: 'ANonce', + definition: + 'Authenticator Nonce β€” the random number the {{access-point|AP}} sends in step 1 of the {{wpa2-handshake|WPA2 4-way handshake}}. Combined with the {{snonce|SNonce}} and both {{mac-address|MAC}} addresses to derive the {{ptk|PTK}}.', + wikiUrl: 'https://en.wikipedia.org/wiki/IEEE_802.11i-2004', + category: 'security' }, { - id: 'snonce', - term: 'SNonce', - definition: - "Supplicant Nonce β€” the random number the client sends in step 2 of the {{wpa2-handshake|WPA2 4-way handshake}}. Lets each side independently derive the {{ptk|PTK}} from the {{pmk|PMK}} + nonces + MACs.", - wikiUrl: 'https://en.wikipedia.org/wiki/IEEE_802.11i-2004', - category: 'security' + id: 'snonce', + term: 'SNonce', + definition: + 'Supplicant Nonce β€” the random number the client sends in step 2 of the {{wpa2-handshake|WPA2 4-way handshake}}. Lets each side independently derive the {{ptk|PTK}} from the {{pmk|PMK}} + nonces + MACs.', + wikiUrl: 'https://en.wikipedia.org/wiki/IEEE_802.11i-2004', + category: 'security' }, { - id: 'adv-ind', - term: 'ADV_IND', - definition: - "[[bluetooth|BLE]] connectable, undirected advertising packet β€” the default *I'm here, talk to me* beacon. Broadcast on channels 37/38/39 at the advertising interval. Carries Flags + Service UUIDs + local name (≀31 bytes).", - wikiUrl: 'https://en.wikipedia.org/wiki/Bluetooth_Low_Energy', - category: 'protocol-mechanics' + id: 'adv-ind', + term: 'ADV_IND', + definition: + "[[bluetooth|BLE]] connectable, undirected advertising packet β€” the default *I'm here, talk to me* beacon. Broadcast on channels 37/38/39 at the advertising interval. Carries Flags + Service UUIDs + local name (≀31 bytes).", + wikiUrl: 'https://en.wikipedia.org/wiki/Bluetooth_Low_Energy', + category: 'protocol-mechanics' }, { - id: 'connect-ind', - term: 'CONNECT_IND', - definition: - "[[bluetooth|BLE]] link-layer packet a Central sends in response to {{adv-ind|ADV_IND}} to open a connection. Carries the 32-bit Access Address, channel-hop pattern, connection interval, and supervision timeout.", - wikiUrl: 'https://en.wikipedia.org/wiki/Bluetooth_Low_Energy', - category: 'protocol-mechanics' + id: 'connect-ind', + term: 'CONNECT_IND', + definition: + '[[bluetooth|BLE]] link-layer packet a Central sends in response to {{adv-ind|ADV_IND}} to open a connection. Carries the 32-bit Access Address, channel-hop pattern, connection interval, and supervision timeout.', + wikiUrl: 'https://en.wikipedia.org/wiki/Bluetooth_Low_Energy', + category: 'protocol-mechanics' }, { - id: 'att-mtu', - term: 'ATT MTU', - definition: - "The maximum payload size of an {{gatt|ATT}} PDU on a [[bluetooth|BLE]] link. Defaults to 23 (only 20 bytes usable) β€” the *first thing to fix on every new BLE connection* via an ATT MTU Exchange (up to 247 or 517).", - wikiUrl: 'https://en.wikipedia.org/wiki/Bluetooth_Low_Energy', - category: 'protocol-mechanics' + id: 'att-mtu', + term: 'ATT MTU', + definition: + 'The maximum payload size of an {{gatt|ATT}} PDU on a [[bluetooth|BLE]] link. Defaults to 23 (only 20 bytes usable) β€” the *first thing to fix on every new BLE connection* via an ATT MTU Exchange (up to 247 or 517).', + wikiUrl: 'https://en.wikipedia.org/wiki/Bluetooth_Low_Energy', + category: 'protocol-mechanics' }, { - id: 'att-read', - term: 'ATT Read', - definition: - "{{gatt|GATT}} operation that retrieves a characteristic's value by handle or UUID. Read by Type lets a Central skip the handle-discovery step when it already knows the UUID.", - wikiUrl: 'https://en.wikipedia.org/wiki/Bluetooth_Low_Energy', - category: 'protocol-mechanics' + id: 'att-read', + term: 'ATT Read', + definition: + "{{gatt|GATT}} operation that retrieves a characteristic's value by handle or UUID. Read by Type lets a Central skip the handle-discovery step when it already knows the UUID.", + wikiUrl: 'https://en.wikipedia.org/wiki/Bluetooth_Low_Energy', + category: 'protocol-mechanics' }, { - id: 'att-write', - term: 'ATT Write', - definition: - "{{gatt|GATT}} operation that sets a characteristic's value. *Write Request* expects a confirmation; *Write Without Response* (fire-and-forget) is the high-throughput variant.", - wikiUrl: 'https://en.wikipedia.org/wiki/Bluetooth_Low_Energy', - category: 'protocol-mechanics' + id: 'att-write', + term: 'ATT Write', + definition: + "{{gatt|GATT}} operation that sets a characteristic's value. *Write Request* expects a confirmation; *Write Without Response* (fire-and-forget) is the high-throughput variant.", + wikiUrl: 'https://en.wikipedia.org/wiki/Bluetooth_Low_Energy', + category: 'protocol-mechanics' }, { - id: 'att-notify', - term: 'ATT Notify', - definition: - "Unsolicited {{gatt|GATT}} push from a Peripheral to a Central β€” no ACK at the ATT layer. Enabled by writing `0x0001` to the {{cccd|CCCD}}. The mechanism behind every push-based BLE sensor.", - wikiUrl: 'https://en.wikipedia.org/wiki/Bluetooth_Low_Energy', - category: 'protocol-mechanics' + id: 'att-notify', + term: 'ATT Notify', + definition: + 'Unsolicited {{gatt|GATT}} push from a Peripheral to a Central β€” no ACK at the ATT layer. Enabled by writing `0x0001` to the {{cccd|CCCD}}. The mechanism behind every push-based BLE sensor.', + wikiUrl: 'https://en.wikipedia.org/wiki/Bluetooth_Low_Energy', + category: 'protocol-mechanics' }, { - id: 'cccd', - term: 'CCCD (Client Characteristic Configuration Descriptor)', - definition: - "{{gatt|GATT}} descriptor (UUID 0x2902) attached to notifiable characteristics. Write `0x0001` to enable {{att-notify|notifications}}, `0x0002` for indications, `0x0000` to disable.", - wikiUrl: 'https://en.wikipedia.org/wiki/Bluetooth_Low_Energy', - category: 'protocol-mechanics' + id: 'cccd', + term: 'CCCD (Client Characteristic Configuration Descriptor)', + definition: + '{{gatt|GATT}} descriptor (UUID 0x2902) attached to notifiable characteristics. Write `0x0001` to enable {{att-notify|notifications}}, `0x0002` for indications, `0x0000` to disable.', + wikiUrl: 'https://en.wikipedia.org/wiki/Bluetooth_Low_Energy', + category: 'protocol-mechanics' }, { - id: 'smp-pairing', - term: 'SMP Pairing', - definition: - "Security Manager Protocol β€” [[bluetooth|BLE]]'s pairing layer. Modern devices use **LE Secure Connections** (ECDH on Curve P-256) to derive a Long-Term Key; legacy *Just-Works* is vulnerable to relay attacks.", - wikiUrl: 'https://en.wikipedia.org/wiki/Bluetooth_Low_Energy#Security', - category: 'security' + id: 'smp-pairing', + term: 'SMP Pairing', + definition: + "Security Manager Protocol β€” [[bluetooth|BLE]]'s pairing layer. Modern devices use **LE Secure Connections** (ECDH on Curve P-256) to derive a Long-Term Key; legacy *Just-Works* is vulnerable to relay attacks.", + wikiUrl: 'https://en.wikipedia.org/wiki/Bluetooth_Low_Energy#Security', + category: 'security' }, { - id: 'll-enc-req', - term: 'LL_ENC_REQ', - definition: - "[[bluetooth|BLE]] Link Layer Control PDU that initiates link encryption. After {{smp-pairing|SMP pairing}} establishes the Long-Term Key, LL_ENC_REQ turns on AES-CCM for every subsequent PDU.", - wikiUrl: 'https://en.wikipedia.org/wiki/Bluetooth_Low_Energy', - category: 'security' + id: 'll-enc-req', + term: 'LL_ENC_REQ', + definition: + '[[bluetooth|BLE]] Link Layer Control PDU that initiates link encryption. After {{smp-pairing|SMP pairing}} establishes the Long-Term Key, LL_ENC_REQ turns on AES-CCM for every subsequent PDU.', + wikiUrl: 'https://en.wikipedia.org/wiki/Bluetooth_Low_Energy', + category: 'security' }, { - id: 'pcd', - term: 'PCD (Proximity Coupling Device)', - definition: - "The {{rfid|RFID}}/[[nfc|NFC]] reader side β€” the *terminal* that energizes the 13.56 MHz field and initiates commands. ISO/IEC 14443 nomenclature.", - wikiUrl: 'https://en.wikipedia.org/wiki/ISO/IEC_14443', - category: 'protocol-mechanics' + id: 'pcd', + term: 'PCD (Proximity Coupling Device)', + definition: + 'The {{rfid|RFID}}/[[nfc|NFC]] reader side β€” the *terminal* that energizes the 13.56 MHz field and initiates commands. ISO/IEC 14443 nomenclature.', + wikiUrl: 'https://en.wikipedia.org/wiki/ISO/IEC_14443', + category: 'protocol-mechanics' }, { - id: 'picc', - term: 'PICC (Proximity Integrated Circuit Card)', - definition: - "The {{rfid|RFID}}/[[nfc|NFC]] *card* side β€” passive (powered by {{inductive-coupling|inductive coupling}} from the {{pcd|PCD}}'s field) or active (phone in card-emulation mode).", - wikiUrl: 'https://en.wikipedia.org/wiki/ISO/IEC_14443', - category: 'protocol-mechanics' + id: 'picc', + term: 'PICC (Proximity Integrated Circuit Card)', + definition: + "The {{rfid|RFID}}/[[nfc|NFC]] *card* side β€” passive (powered by {{inductive-coupling|inductive coupling}} from the {{pcd|PCD}}'s field) or active (phone in card-emulation mode).", + wikiUrl: 'https://en.wikipedia.org/wiki/ISO/IEC_14443', + category: 'protocol-mechanics' }, { - id: 'reqa', - term: 'REQA / WUPA', - definition: - "7-bit short frame ([[nfc|NFC]] Type A): REQA `0x26` wakes IDLE {{picc|PICCs}}, WUPA `0x52` wakes both IDLE and HALT. First message of the [[nfc|NFC]] anti-collision dance.", - wikiUrl: 'https://en.wikipedia.org/wiki/ISO/IEC_14443', - category: 'protocol-mechanics' + id: 'reqa', + term: 'REQA / WUPA', + definition: + '7-bit short frame ([[nfc|NFC]] Type A): REQA `0x26` wakes IDLE {{picc|PICCs}}, WUPA `0x52` wakes both IDLE and HALT. First message of the [[nfc|NFC]] anti-collision dance.', + wikiUrl: 'https://en.wikipedia.org/wiki/ISO/IEC_14443', + category: 'protocol-mechanics' }, { - id: 'atqa', - term: 'ATQA (Answer to Request, Type A)', - definition: - "The {{picc|PICC}}'s reply to {{reqa|REQA}}/WUPA. 16 bits indicating the UID size (4/7/10 bytes) and which anti-collision bit-frame to use.", - wikiUrl: 'https://en.wikipedia.org/wiki/ISO/IEC_14443', - category: 'protocol-mechanics' + id: 'atqa', + term: 'ATQA (Answer to Request, Type A)', + definition: + "The {{picc|PICC}}'s reply to {{reqa|REQA}}/WUPA. 16 bits indicating the UID size (4/7/10 bytes) and which anti-collision bit-frame to use.", + wikiUrl: 'https://en.wikipedia.org/wiki/ISO/IEC_14443', + category: 'protocol-mechanics' }, { - id: 'rats', - term: 'RATS / ATS', - definition: - "Request for Answer To Select β€” the [[nfc|NFC]] command that promotes a card from raw ISO 14443-3 anti-collision to the higher-layer ISO 14443-4 protocol. The ATS response declares Frame Size and Frame Waiting Time.", - wikiUrl: 'https://en.wikipedia.org/wiki/ISO/IEC_14443', - category: 'protocol-mechanics' + id: 'rats', + term: 'RATS / ATS', + definition: + 'Request for Answer To Select β€” the [[nfc|NFC]] command that promotes a card from raw ISO 14443-3 anti-collision to the higher-layer ISO 14443-4 protocol. The ATS response declares Frame Size and Frame Waiting Time.', + wikiUrl: 'https://en.wikipedia.org/wiki/ISO/IEC_14443', + category: 'protocol-mechanics' }, { - id: 'anti-collision', - term: 'Anti-Collision', - definition: - "The bit-by-bit loop ([[nfc|NFC]] Type A: SEL + NVB cascade) that singles out exactly one card when multiple {{picc|PICCs}} share the {{pcd|PCD}}'s field. Resolves the UID one bit at a time.", - wikiUrl: 'https://en.wikipedia.org/wiki/ISO/IEC_14443', - category: 'protocol-mechanics' + id: 'anti-collision', + term: 'Anti-Collision', + definition: + "The bit-by-bit loop ([[nfc|NFC]] Type A: SEL + NVB cascade) that singles out exactly one card when multiple {{picc|PICCs}} share the {{pcd|PCD}}'s field. Resolves the UID one bit at a time.", + wikiUrl: 'https://en.wikipedia.org/wiki/ISO/IEC_14443', + category: 'protocol-mechanics' }, { - id: 'select-aid', - term: 'SELECT AID', - definition: - "ISO 7816-4 command (`00 A4 04 00 …`) that selects an application by its {{aid|AID}}. In contactless payment: first SELECT {{ppse|PPSE}}, then SELECT the chosen card AID (Visa, Mastercard, AmEx).", - wikiUrl: 'https://en.wikipedia.org/wiki/Smart_card_application_protocol_data_unit', - category: 'protocol-mechanics' + id: 'select-aid', + term: 'SELECT AID', + definition: + 'ISO 7816-4 command (`00 A4 04 00 …`) that selects an application by its {{aid|AID}}. In contactless payment: first SELECT {{ppse|PPSE}}, then SELECT the chosen card AID (Visa, Mastercard, AmEx).', + wikiUrl: 'https://en.wikipedia.org/wiki/Smart_card_application_protocol_data_unit', + category: 'protocol-mechanics' }, { - id: 'pdol', - term: 'PDOL (Processing Data Object List)', - definition: - "List of EMV tags the card needs filled in by the terminal before {{gpo|GPO}}: amount, currency, country, transaction date, terminal verification results, unpredictable number, etc.", - wikiUrl: 'https://en.wikipedia.org/wiki/EMV', - category: 'protocol-mechanics' + id: 'pdol', + term: 'PDOL (Processing Data Object List)', + definition: + 'List of EMV tags the card needs filled in by the terminal before {{gpo|GPO}}: amount, currency, country, transaction date, terminal verification results, unpredictable number, etc.', + wikiUrl: 'https://en.wikipedia.org/wiki/EMV', + category: 'protocol-mechanics' }, { - id: 'gpo', - term: 'GPO (Get Processing Options)', - definition: - "EMV contactless command that hands the {{pdol|PDOL}}-filled data to the card. The card replies with AIP (modes supported) and {{afl|AFL}} (which records the terminal should next {{read-record|READ}}).", - wikiUrl: 'https://en.wikipedia.org/wiki/EMV', - category: 'protocol-mechanics' + id: 'gpo', + term: 'GPO (Get Processing Options)', + definition: + 'EMV contactless command that hands the {{pdol|PDOL}}-filled data to the card. The card replies with AIP (modes supported) and {{afl|AFL}} (which records the terminal should next {{read-record|READ}}).', + wikiUrl: 'https://en.wikipedia.org/wiki/EMV', + category: 'protocol-mechanics' }, { - id: 'afl', - term: 'AFL (Application File Locator)', - definition: - "EMV record map returned in the {{gpo|GPO}} response β€” tells the terminal exactly which records to {{read-record|READ RECORD}} to assemble the cardholder data, certificate chain, and CDOL.", - wikiUrl: 'https://en.wikipedia.org/wiki/EMV', - category: 'protocol-mechanics' + id: 'afl', + term: 'AFL (Application File Locator)', + definition: + 'EMV record map returned in the {{gpo|GPO}} response β€” tells the terminal exactly which records to {{read-record|READ RECORD}} to assemble the cardholder data, certificate chain, and CDOL.', + wikiUrl: 'https://en.wikipedia.org/wiki/EMV', + category: 'protocol-mechanics' }, { - id: 'read-record', - term: 'READ RECORD', - definition: - "ISO 7816-4 command that retrieves one record from a file on the card. EMV terminals issue several READ RECORDs (one per {{afl|AFL}} entry) to pull DPAN, expiry, CDOL1, and the offline data-authentication certificate chain.", - wikiUrl: 'https://en.wikipedia.org/wiki/Smart_card_application_protocol_data_unit', - category: 'protocol-mechanics' + id: 'read-record', + term: 'READ RECORD', + definition: + 'ISO 7816-4 command that retrieves one record from a file on the card. EMV terminals issue several READ RECORDs (one per {{afl|AFL}} entry) to pull DPAN, expiry, CDOL1, and the offline data-authentication certificate chain.', + wikiUrl: 'https://en.wikipedia.org/wiki/Smart_card_application_protocol_data_unit', + category: 'protocol-mechanics' }, { - id: 'generate-ac', - term: 'GENERATE AC', - definition: - "The EMV command that asks the card to produce an Application Cryptogram from the CDOL1 inputs. Yields the {{arqc|ARQC}} (online) or TC (offline-approved). MAC'd under the per-DPAN key.", - wikiUrl: 'https://en.wikipedia.org/wiki/EMV', - category: 'security' + id: 'generate-ac', + term: 'GENERATE AC', + definition: + "The EMV command that asks the card to produce an Application Cryptogram from the CDOL1 inputs. Yields the {{arqc|ARQC}} (online) or TC (offline-approved). MAC'd under the per-DPAN key.", + wikiUrl: 'https://en.wikipedia.org/wiki/EMV', + category: 'security' }, { - id: 'arqc', - term: 'ARQC (Authorisation Request Cryptogram)', - definition: - "EMV cryptogram returned by {{generate-ac|GENERATE AC}}. The terminal forwards it via acquirer β†’ payment network β†’ issuer; the issuer's HSM verifies and returns an ARPC = APPROVED/DECLINED.", - wikiUrl: 'https://en.wikipedia.org/wiki/EMV', - category: 'security' + id: 'arqc', + term: 'ARQC (Authorisation Request Cryptogram)', + definition: + "EMV cryptogram returned by {{generate-ac|GENERATE AC}}. The terminal forwards it via acquirer β†’ payment network β†’ issuer; the issuer's HSM verifies and returns an ARPC = APPROVED/DECLINED.", + wikiUrl: 'https://en.wikipedia.org/wiki/EMV', + category: 'security' }, { - id: 'dpan', - term: 'DPAN (Device PAN)', - definition: - "The tokenized card number stored on a phone or wearable for contactless payments β€” *not* the real PAN. Real PAN lives only at the issuer; the DPAN is unique per device + per merchant network.", - wikiUrl: 'https://en.wikipedia.org/wiki/Tokenization_(data_security)', - category: 'security' + id: 'dpan', + term: 'DPAN (Device PAN)', + definition: + 'The tokenized card number stored on a phone or wearable for contactless payments β€” *not* the real PAN. Real PAN lives only at the issuer; the DPAN is unique per device + per merchant network.', + wikiUrl: 'https://en.wikipedia.org/wiki/Tokenization_(data_security)', + category: 'security' }, { - id: 'binding-request', - term: 'STUN Binding Request', - definition: - "20-byte {{stun|STUN}} packet β€” magic cookie `0x2112A442` + 96-bit transaction ID. Sent to a STUN server (learns server-reflexive address) or peer (ICE connectivity check).", - wikiUrl: 'https://en.wikipedia.org/wiki/STUN', - category: 'protocol-mechanics' + id: 'binding-request', + term: 'STUN Binding Request', + definition: + '20-byte {{stun|STUN}} packet β€” magic cookie `0x2112A442` + 96-bit transaction ID. Sent to a STUN server (learns server-reflexive address) or peer (ICE connectivity check).', + wikiUrl: 'https://en.wikipedia.org/wiki/STUN', + category: 'protocol-mechanics' }, { - id: 'xor-mapped-address', - term: 'XOR-MAPPED-ADDRESS', - definition: - "{{stun|STUN}} attribute in a Binding Response carrying the source `ip:port` the server observed, XORed against the magic cookie so {{nat|NAT}} middleboxes can't rewrite it. Your server-reflexive candidate.", - wikiUrl: 'https://en.wikipedia.org/wiki/STUN', - category: 'protocol-mechanics' + id: 'xor-mapped-address', + term: 'XOR-MAPPED-ADDRESS', + definition: + "{{stun|STUN}} attribute in a Binding Response carrying the source `ip:port` the server observed, XORed against the magic cookie so {{nat|NAT}} middleboxes can't rewrite it. Your server-reflexive candidate.", + wikiUrl: 'https://en.wikipedia.org/wiki/STUN', + category: 'protocol-mechanics' }, { - id: 'xor-relayed-address', - term: 'XOR-RELAYED-ADDRESS', - definition: - "{{turn|TURN}} attribute in an Allocate Response β€” the public `ip:port` the relay reserved for the client. The fallback path when neither host nor server-reflexive {{ice-candidate|candidates}} work.", - wikiUrl: 'https://en.wikipedia.org/wiki/Traversal_Using_Relays_around_NAT', - category: 'protocol-mechanics' + id: 'xor-relayed-address', + term: 'XOR-RELAYED-ADDRESS', + definition: + '{{turn|TURN}} attribute in an Allocate Response β€” the public `ip:port` the relay reserved for the client. The fallback path when neither host nor server-reflexive {{ice-candidate|candidates}} work.', + wikiUrl: 'https://en.wikipedia.org/wiki/Traversal_Using_Relays_around_NAT', + category: 'protocol-mechanics' }, { - id: 'use-candidate', - term: 'USE-CANDIDATE', - definition: - "{{stun|STUN}} attribute the {{ice|ICE}} controlling agent sets on the connectivity check it wants the other side to use. Nominates the winning candidate pair; media starts flowing on it.", - wikiUrl: 'https://en.wikipedia.org/wiki/Interactive_Connectivity_Establishment', - category: 'protocol-mechanics' + id: 'use-candidate', + term: 'USE-CANDIDATE', + definition: + '{{stun|STUN}} attribute the {{ice|ICE}} controlling agent sets on the connectivity check it wants the other side to use. Nominates the winning candidate pair; media starts flowing on it.', + wikiUrl: 'https://en.wikipedia.org/wiki/Interactive_Connectivity_Establishment', + category: 'protocol-mechanics' }, { - id: 'interface-id', - term: 'Interface ID', - definition: - "Lower 64 bits of an [[ipv6|IPv6]] address β€” identifies a specific interface on a link. Built from the {{mac-address|MAC}} via EUI-64, generated randomly (privacy addresses), or assigned via DHCPv6.", - wikiUrl: 'https://en.wikipedia.org/wiki/IPv6_address#Modified_EUI-64', - category: 'networking-basics' + id: 'interface-id', + term: 'Interface ID', + definition: + 'Lower 64 bits of an [[ipv6|IPv6]] address β€” identifies a specific interface on a link. Built from the {{mac-address|MAC}} via EUI-64, generated randomly (privacy addresses), or assigned via DHCPv6.', + wikiUrl: 'https://en.wikipedia.org/wiki/IPv6_address#Modified_EUI-64', + category: 'networking-basics' }, { - id: 'mac-table', - term: 'MAC Address Table', - definition: - "Per-switch table mapping {{mac-address|MAC addresses}} to switch ports. Learned by snooping the source MAC of frames as they arrive. Entries time out after a few minutes if unused. The reason a switch is faster than a hub.", - wikiUrl: 'https://en.wikipedia.org/wiki/Forwarding_information_base', - category: 'networking-basics' + id: 'mac-table', + term: 'MAC Address Table', + definition: + 'Per-switch table mapping {{mac-address|MAC addresses}} to switch ports. Learned by snooping the source MAC of frames as they arrive. Entries time out after a few minutes if unused. The reason a switch is faster than a hub.', + wikiUrl: 'https://en.wikipedia.org/wiki/Forwarding_information_base', + category: 'networking-basics' }, { - id: 'prach', - term: 'PRACH (Physical Random Access Channel)', - definition: - "The {{5g-nr|5G NR}} / {{lte|LTE}} uplink channel a {{ue|UE}} uses to first contact a {{gnb|base station}}. The UE transmits a PRACH preamble (Msg1) in a contention-based slot; the base station replies with a Random Access Response (RAR / Msg2) carrying initial timing advance and a temporary identifier ({{c-rnti|C-RNTI}}).", - wikiUrl: 'https://en.wikipedia.org/wiki/Physical_layer_(LTE)', - category: 'protocol-mechanics' + id: 'prach', + term: 'PRACH (Physical Random Access Channel)', + definition: + 'The {{5g-nr|5G NR}} / {{lte|LTE}} uplink channel a {{ue|UE}} uses to first contact a {{gnb|base station}}. The UE transmits a PRACH preamble (Msg1) in a contention-based slot; the base station replies with a Random Access Response (RAR / Msg2) carrying initial timing advance and a temporary identifier ({{c-rnti|C-RNTI}}).', + wikiUrl: 'https://en.wikipedia.org/wiki/Physical_layer_(LTE)', + category: 'protocol-mechanics' }, { - id: 'ue', - term: 'UE (User Equipment)', - definition: - "{{3gpp|3GPP}} term for the [[cellular|cellular]] subscriber device β€” phone, tablet, modem, IoT module. The UE pairs with the {{sim-usim|USIM}} to authenticate to the network and runs the {{rrc|RRC}} and {{nas|NAS}} stacks against the {{gnb|gNB}} and {{amf|AMF}}.", - wikiUrl: 'https://en.wikipedia.org/wiki/User_equipment', - category: 'networking-basics' + id: 'ue', + term: 'UE (User Equipment)', + definition: + '{{3gpp|3GPP}} term for the [[cellular|cellular]] subscriber device β€” phone, tablet, modem, IoT module. The UE pairs with the {{sim-usim|USIM}} to authenticate to the network and runs the {{rrc|RRC}} and {{nas|NAS}} stacks against the {{gnb|gNB}} and {{amf|AMF}}.', + wikiUrl: 'https://en.wikipedia.org/wiki/User_equipment', + category: 'networking-basics' }, { - id: 'gnb', - term: 'gNB (Next-Generation NodeB)', - definition: - "The {{5g-nr|5G}} base station β€” the radio access node a {{ue|UE}} attaches to. Speaks {{rrc|RRC}} to UEs over the air and NGAP to the {{amf|AMF}} over the N2 interface. Successor to the {{lte|LTE}} eNB.", - wikiUrl: 'https://en.wikipedia.org/wiki/GNodeB', - category: 'networking-basics' + id: 'gnb', + term: 'gNB (Next-Generation NodeB)', + definition: + 'The {{5g-nr|5G}} base station β€” the radio access node a {{ue|UE}} attaches to. Speaks {{rrc|RRC}} to UEs over the air and NGAP to the {{amf|AMF}} over the N2 interface. Successor to the {{lte|LTE}} eNB.', + wikiUrl: 'https://en.wikipedia.org/wiki/GNodeB', + category: 'networking-basics' }, { - id: 'rrc', - term: 'RRC (Radio Resource Control)', - definition: - "The signalling protocol between a {{ue|UE}} and a {{gnb|gNB}} that sets up, reconfigures, and tears down radio bearers. Walks the UE through an eight-state machine: Idle β†’ RRCSetupRequest β†’ RRCSetup β†’ RRCReconfiguration. Carries security mode, measurement reports, and handover commands.", - wikiUrl: 'https://en.wikipedia.org/wiki/Radio_Resource_Control', - category: 'protocol-mechanics' + id: 'rrc', + term: 'RRC (Radio Resource Control)', + definition: + 'The signalling protocol between a {{ue|UE}} and a {{gnb|gNB}} that sets up, reconfigures, and tears down radio bearers. Walks the UE through an eight-state machine: Idle β†’ RRCSetupRequest β†’ RRCSetup β†’ RRCReconfiguration. Carries security mode, measurement reports, and handover commands.', + wikiUrl: 'https://en.wikipedia.org/wiki/Radio_Resource_Control', + category: 'protocol-mechanics' }, { - id: 'nas', - term: 'NAS (Non-Access Stratum)', - definition: - "The [[cellular|cellular]] signalling layer that runs end-to-end between a {{ue|UE}} and the {{amf|AMF}}, transparent to the {{gnb|gNB}}. Carries Registration, Authentication, Security Mode Command, and PDU Session messages. NAS ciphering (128-NEA) and integrity (128-NIA) sit here.", - wikiUrl: 'https://en.wikipedia.org/wiki/Non-access_stratum', - category: 'protocol-mechanics' + id: 'nas', + term: 'NAS (Non-Access Stratum)', + definition: + 'The [[cellular|cellular]] signalling layer that runs end-to-end between a {{ue|UE}} and the {{amf|AMF}}, transparent to the {{gnb|gNB}}. Carries Registration, Authentication, Security Mode Command, and PDU Session messages. NAS ciphering (128-NEA) and integrity (128-NIA) sit here.', + wikiUrl: 'https://en.wikipedia.org/wiki/Non-access_stratum', + category: 'protocol-mechanics' }, { - id: 'amf', - term: 'AMF (Access and Mobility Management Function)', - definition: - "The {{5g-core|5G core}} function that terminates {{nas|NAS}} signalling for a {{ue|UE}}: handles Registration, mobility, paging, and authentication orchestration with {{ausf|AUSF}} / {{udm|UDM}}. Equivalent role to the {{lte|LTE}} MME.", - wikiUrl: 'https://en.wikipedia.org/wiki/5G_network_slicing', - category: 'infrastructure' + id: 'amf', + term: 'AMF (Access and Mobility Management Function)', + definition: + 'The {{5g-core|5G core}} function that terminates {{nas|NAS}} signalling for a {{ue|UE}}: handles Registration, mobility, paging, and authentication orchestration with {{ausf|AUSF}} / {{udm|UDM}}. Equivalent role to the {{lte|LTE}} MME.', + wikiUrl: 'https://en.wikipedia.org/wiki/5G_network_slicing', + category: 'infrastructure' }, { - id: 'smf', - term: 'SMF (Session Management Function)', - definition: - "The {{5g-core|5G core}} function that creates and manages {{pdu-session|PDU sessions}} β€” assigns [[ip|IP]] addresses, programs the {{upf|UPF}} via {{pfcp|PFCP}}, enforces {{qos|QoS}} rules. Control-plane counterpart to UPF under {{cups|CUPS}}.", - wikiUrl: 'https://en.wikipedia.org/wiki/5G_network_slicing', - category: 'infrastructure' + id: 'smf', + term: 'SMF (Session Management Function)', + definition: + 'The {{5g-core|5G core}} function that creates and manages {{pdu-session|PDU sessions}} β€” assigns [[ip|IP]] addresses, programs the {{upf|UPF}} via {{pfcp|PFCP}}, enforces {{qos|QoS}} rules. Control-plane counterpart to UPF under {{cups|CUPS}}.', + wikiUrl: 'https://en.wikipedia.org/wiki/5G_network_slicing', + category: 'infrastructure' }, { - id: 'upf', - term: 'UPF (User Plane Function)', - definition: - "The {{5g-core|5G core}} data-plane forwarder. Receives user packets from {{gnb|gNB}} via N3 ({{gtp-u|GTP-U}}), applies the PDR/FAR/QER/URR rules installed by the {{smf|SMF}} over {{pfcp|PFCP}}, and forwards to the data network. The packet processor in the {{cups|CUPS}} split.", - wikiUrl: 'https://en.wikipedia.org/wiki/5G_network_slicing', - category: 'infrastructure' + id: 'upf', + term: 'UPF (User Plane Function)', + definition: + 'The {{5g-core|5G core}} data-plane forwarder. Receives user packets from {{gnb|gNB}} via N3 ({{gtp-u|GTP-U}}), applies the PDR/FAR/QER/URR rules installed by the {{smf|SMF}} over {{pfcp|PFCP}}, and forwards to the data network. The packet processor in the {{cups|CUPS}} split.', + wikiUrl: 'https://en.wikipedia.org/wiki/5G_network_slicing', + category: 'infrastructure' }, { - id: 'ausf', - term: 'AUSF (Authentication Server Function)', - definition: - "The {{5g-core|5G core}} function that runs the authentication exchange with a {{ue|UE}}. Receives the authentication vector from {{udm|UDM}}, sends RAND/AUTN to the UE via {{amf|AMF}}, compares the returned RES* against HRES*. The 5G-AKA decision point.", - wikiUrl: 'https://en.wikipedia.org/wiki/5G_security', - category: 'security' + id: 'ausf', + term: 'AUSF (Authentication Server Function)', + definition: + 'The {{5g-core|5G core}} function that runs the authentication exchange with a {{ue|UE}}. Receives the authentication vector from {{udm|UDM}}, sends RAND/AUTN to the UE via {{amf|AMF}}, compares the returned RES* against HRES*. The 5G-AKA decision point.', + wikiUrl: 'https://en.wikipedia.org/wiki/5G_security', + category: 'security' }, { - id: 'udm', - term: 'UDM (Unified Data Management)', - definition: - "The {{5g-core|5G core}} subscriber database β€” holds long-term keys K, subscription profiles, and policy data. Hosts the SIDF (Subscription Identifier De-concealing Function) that decrypts {{suci|SUCI}} back into {{supi|SUPI}}. Equivalent role to the {{lte|LTE}} HSS.", - wikiUrl: 'https://en.wikipedia.org/wiki/5G_security', - category: 'infrastructure' + id: 'udm', + term: 'UDM (Unified Data Management)', + definition: + 'The {{5g-core|5G core}} subscriber database β€” holds long-term keys K, subscription profiles, and policy data. Hosts the SIDF (Subscription Identifier De-concealing Function) that decrypts {{suci|SUCI}} back into {{supi|SUPI}}. Equivalent role to the {{lte|LTE}} HSS.', + wikiUrl: 'https://en.wikipedia.org/wiki/5G_security', + category: 'infrastructure' }, { - id: '5g-core', - term: '5G Core (5GC)', - definition: - "The service-based architecture that replaced the {{lte|LTE}} EPC in {{5g-nr|5G}}. Decomposes mobility, sessions, authentication, and policy into discrete network functions ({{amf|AMF}}, {{smf|SMF}}, {{upf|UPF}}, {{ausf|AUSF}}, {{udm|UDM}}, PCF, NRF) that talk over HTTP/2 service APIs ({{sba|SBA}}).", - wikiUrl: 'https://en.wikipedia.org/wiki/5G', - category: 'infrastructure' + id: '5g-core', + term: '5G Core (5GC)', + definition: + 'The service-based architecture that replaced the {{lte|LTE}} EPC in {{5g-nr|5G}}. Decomposes mobility, sessions, authentication, and policy into discrete network functions ({{amf|AMF}}, {{smf|SMF}}, {{upf|UPF}}, {{ausf|AUSF}}, {{udm|UDM}}, PCF, NRF) that talk over HTTP/2 service APIs ({{sba|SBA}}).', + wikiUrl: 'https://en.wikipedia.org/wiki/5G', + category: 'infrastructure' }, { - id: 'suci', - term: 'SUCI (Subscription Concealed Identifier)', - definition: - "The encrypted form of a subscriber's permanent [[cellular|cellular]] identity. The {{sim-usim|USIM}} encrypts the {{supi|SUPI}} with the home network's public key (ECIES on Curve25519, Profile A) before any transmission β€” so the long-term IMSI is never sent in clear over the air. Introduced in {{5g-nr|5G}} to defeat IMSI catchers.", - wikiUrl: 'https://en.wikipedia.org/wiki/Subscription_Concealed_Identifier', - category: 'security' + id: 'suci', + term: 'SUCI (Subscription Concealed Identifier)', + definition: + "The encrypted form of a subscriber's permanent [[cellular|cellular]] identity. The {{sim-usim|USIM}} encrypts the {{supi|SUPI}} with the home network's public key (ECIES on Curve25519, Profile A) before any transmission β€” so the long-term IMSI is never sent in clear over the air. Introduced in {{5g-nr|5G}} to defeat IMSI catchers.", + wikiUrl: 'https://en.wikipedia.org/wiki/Subscription_Concealed_Identifier', + category: 'security' }, { - id: 'supi', - term: 'SUPI (Subscription Permanent Identifier)', - definition: - "The long-term [[cellular|cellular]] subscriber identity stored on the {{sim-usim|USIM}}. Usually an IMSI (MCC + MNC + MSIN). Never sent in clear in {{5g-nr|5G}} β€” always concealed as a {{suci|SUCI}} on the air interface, decrypted only at the {{udm|UDM}}'s SIDF.", - wikiUrl: 'https://en.wikipedia.org/wiki/International_mobile_subscriber_identity', - category: 'security' + id: 'supi', + term: 'SUPI (Subscription Permanent Identifier)', + definition: + "The long-term [[cellular|cellular]] subscriber identity stored on the {{sim-usim|USIM}}. Usually an IMSI (MCC + MNC + MSIN). Never sent in clear in {{5g-nr|5G}} β€” always concealed as a {{suci|SUCI}} on the air interface, decrypted only at the {{udm|UDM}}'s SIDF.", + wikiUrl: 'https://en.wikipedia.org/wiki/International_mobile_subscriber_identity', + category: 'security' }, { - id: '5g-aka', - term: '5G-AKA (Authentication and Key Agreement)', - definition: - "The mutual authentication and key derivation protocol between a {{ue|UE}} and the home network in {{5g-nr|5G}}. {{ausf|AUSF}} sends RAND + AUTN; the {{sim-usim|USIM}} verifies AUTN.MAC = f1(K, SQN, RAND), computes RES* via KDF(CK || IK); AUSF compares HRES*. Successor to {{lte|LTE}} EPS-AKA with hash-based RES* and {{suci|SUCI}} integration.", - wikiUrl: 'https://en.wikipedia.org/wiki/Authentication_and_Key_Agreement_(protocol)', - category: 'security' + id: '5g-aka', + term: '5G-AKA (Authentication and Key Agreement)', + definition: + 'The mutual authentication and key derivation protocol between a {{ue|UE}} and the home network in {{5g-nr|5G}}. {{ausf|AUSF}} sends RAND + AUTN; the {{sim-usim|USIM}} verifies AUTN.MAC = f1(K, SQN, RAND), computes RES* via KDF(CK || IK); AUSF compares HRES*. Successor to {{lte|LTE}} EPS-AKA with hash-based RES* and {{suci|SUCI}} integration.', + wikiUrl: 'https://en.wikipedia.org/wiki/Authentication_and_Key_Agreement_(protocol)', + category: 'security' }, { - id: 'guti', - term: '5G-GUTI (Globally Unique Temporary Identifier)', - definition: - "The temporary [[cellular|cellular]] identity assigned to a {{ue|UE}} by the {{amf|AMF}} after successful Registration. Used in place of the {{supi|SUPI}} for subsequent paging and signalling, rotated on a per-network policy to prevent tracking.", - wikiUrl: 'https://en.wikipedia.org/wiki/GUTI', - category: 'security' + id: 'guti', + term: '5G-GUTI (Globally Unique Temporary Identifier)', + definition: + 'The temporary [[cellular|cellular]] identity assigned to a {{ue|UE}} by the {{amf|AMF}} after successful Registration. Used in place of the {{supi|SUPI}} for subsequent paging and signalling, rotated on a per-network policy to prevent tracking.', + wikiUrl: 'https://en.wikipedia.org/wiki/GUTI', + category: 'security' }, { - id: 'nssai', - term: 'NSSAI / S-NSSAI (Network Slice Selection)', - definition: - "The {{5g-nr|5G}} identifier that selects which network slice a {{ue|UE}} attaches to. A single S-NSSAI is one slice (SST + SD); NSSAI is the set requested or allowed. Lets one physical [[cellular|cellular]] network present multiple isolated logical networks (eMBB, URLLC, mMTC).", - wikiUrl: 'https://en.wikipedia.org/wiki/5G_network_slicing', - category: 'infrastructure' + id: 'nssai', + term: 'NSSAI / S-NSSAI (Network Slice Selection)', + definition: + 'The {{5g-nr|5G}} identifier that selects which network slice a {{ue|UE}} attaches to. A single S-NSSAI is one slice (SST + SD); NSSAI is the set requested or allowed. Lets one physical [[cellular|cellular]] network present multiple isolated logical networks (eMBB, URLLC, mMTC).', + wikiUrl: 'https://en.wikipedia.org/wiki/5G_network_slicing', + category: 'infrastructure' }, { - id: 'pdu-session', - term: 'PDU Session', - definition: - "The {{5g-nr|5G}} equivalent of \"give me an [[ip|IP]] address.\" A logical connection between the {{ue|UE}} and the data network (identified by {{dnn|DNN}}), set up by the {{smf|SMF}} programming the {{upf|UPF}} via {{pfcp|PFCP}}. Carries one or more {{drb|Data Radio Bearers}} with {{qos|QoS}} flows.", - wikiUrl: 'https://en.wikipedia.org/wiki/5G', - category: 'protocol-mechanics' + id: 'pdu-session', + term: 'PDU Session', + definition: + 'The {{5g-nr|5G}} equivalent of "give me an [[ip|IP]] address." A logical connection between the {{ue|UE}} and the data network (identified by {{dnn|DNN}}), set up by the {{smf|SMF}} programming the {{upf|UPF}} via {{pfcp|PFCP}}. Carries one or more {{drb|Data Radio Bearers}} with {{qos|QoS}} flows.', + wikiUrl: 'https://en.wikipedia.org/wiki/5G', + category: 'protocol-mechanics' }, { - id: 'dnn', - term: 'DNN (Data Network Name)', - definition: - "The {{5g-nr|5G}} successor to {{lte|LTE}} APN. A string (\"internet\", \"ims\", \"private.acme\") that identifies which data network a {{pdu-session|PDU session}} terminates in. The {{smf|SMF}} uses it to pick the {{upf|UPF}} and IP pool.", - wikiUrl: 'https://en.wikipedia.org/wiki/Access_Point_Name', - category: 'networking-basics' + id: 'dnn', + term: 'DNN (Data Network Name)', + definition: + 'The {{5g-nr|5G}} successor to {{lte|LTE}} APN. A string ("internet", "ims", "private.acme") that identifies which data network a {{pdu-session|PDU session}} terminates in. The {{smf|SMF}} uses it to pick the {{upf|UPF}} and IP pool.', + wikiUrl: 'https://en.wikipedia.org/wiki/Access_Point_Name', + category: 'networking-basics' }, { - id: 'c-rnti', - term: 'C-RNTI (Cell Radio Network Temporary Identifier)', - definition: - "The 16-bit temporary identifier a {{gnb|gNB}} assigns to a {{ue|UE}} in its cell. Assigned in the RAR (Msg2) right after the {{prach|PRACH}} preamble succeeds. Addresses the UE in every subsequent radio scheduling command.", - wikiUrl: 'https://en.wikipedia.org/wiki/RNTI', - category: 'protocol-mechanics' + id: 'c-rnti', + term: 'C-RNTI (Cell Radio Network Temporary Identifier)', + definition: + 'The 16-bit temporary identifier a {{gnb|gNB}} assigns to a {{ue|UE}} in its cell. Assigned in the RAR (Msg2) right after the {{prach|PRACH}} preamble succeeds. Addresses the UE in every subsequent radio scheduling command.', + wikiUrl: 'https://en.wikipedia.org/wiki/RNTI', + category: 'protocol-mechanics' }, { - id: 'drb', - term: 'DRB (Data Radio Bearer)', - definition: - "A {{5g-nr|5G}} / {{lte|LTE}} radio-layer pipe for user data, set up by {{rrc|RRCReconfiguration}}. Each DRB carries one or more {{qos|QoS}} flows ({{qfi|QFI}}-tagged) of a {{pdu-session|PDU session}}. The signalling counterpart is the SRB.", - wikiUrl: 'https://en.wikipedia.org/wiki/E-UTRA', - category: 'protocol-mechanics' + id: 'drb', + term: 'DRB (Data Radio Bearer)', + definition: + 'A {{5g-nr|5G}} / {{lte|LTE}} radio-layer pipe for user data, set up by {{rrc|RRCReconfiguration}}. Each DRB carries one or more {{qos|QoS}} flows ({{qfi|QFI}}-tagged) of a {{pdu-session|PDU session}}. The signalling counterpart is the SRB.', + wikiUrl: 'https://en.wikipedia.org/wiki/E-UTRA', + category: 'protocol-mechanics' }, { - id: 'qfi', - term: 'QFI (QoS Flow Identifier)', - definition: - "The 6-bit tag a {{5g-nr|5G}} {{upf|UPF}} stamps on every uplink/downlink packet to identify which {{qos|QoS}} flow of a {{pdu-session|PDU session}} it belongs to. The {{gnb|gNB}} maps QFIs to {{drb|Data Radio Bearers}}.", - wikiUrl: 'https://en.wikipedia.org/wiki/5G', - category: 'protocol-mechanics' + id: 'qfi', + term: 'QFI (QoS Flow Identifier)', + definition: + 'The 6-bit tag a {{5g-nr|5G}} {{upf|UPF}} stamps on every uplink/downlink packet to identify which {{qos|QoS}} flow of a {{pdu-session|PDU session}} it belongs to. The {{gnb|gNB}} maps QFIs to {{drb|Data Radio Bearers}}.', + wikiUrl: 'https://en.wikipedia.org/wiki/5G', + category: 'protocol-mechanics' }, { - id: 'ngap', - term: 'NGAP (NG Application Protocol)', - definition: - "The control-plane signalling protocol between a {{gnb|gNB}} and the {{amf|AMF}} on the N2 interface in {{5g-nr|5G}}. Carries Initial UE Message, NAS PDUs, UE Context Setup, handover requests. Sibling of the {{lte|LTE}} S1AP.", - wikiUrl: 'https://en.wikipedia.org/wiki/NG_Application_Protocol', - category: 'protocol-mechanics' + id: 'ngap', + term: 'NGAP (NG Application Protocol)', + definition: + 'The control-plane signalling protocol between a {{gnb|gNB}} and the {{amf|AMF}} on the N2 interface in {{5g-nr|5G}}. Carries Initial UE Message, NAS PDUs, UE Context Setup, handover requests. Sibling of the {{lte|LTE}} S1AP.', + wikiUrl: 'https://en.wikipedia.org/wiki/NG_Application_Protocol', + category: 'protocol-mechanics' }, { - id: 'pfcp', - term: 'PFCP (Packet Forwarding Control Protocol)', - definition: - "The {{3gpp|3GPP}} protocol over UDP/8805 that lets {{smf|SMF}} program {{upf|UPF}} forwarding state: PDR (Packet Detection Rule), FAR (Forwarding Action Rule), QER ({{qos|QoS}} Enforcement Rule), URR (Usage Reporting Rule). The wire between control and data plane under {{cups|CUPS}}.", - wikiUrl: 'https://en.wikipedia.org/wiki/Packet_Forwarding_Control_Protocol', - category: 'protocol-mechanics' + id: 'pfcp', + term: 'PFCP (Packet Forwarding Control Protocol)', + definition: + 'The {{3gpp|3GPP}} protocol over UDP/8805 that lets {{smf|SMF}} program {{upf|UPF}} forwarding state: PDR (Packet Detection Rule), FAR (Forwarding Action Rule), QER ({{qos|QoS}} Enforcement Rule), URR (Usage Reporting Rule). The wire between control and data plane under {{cups|CUPS}}.', + wikiUrl: 'https://en.wikipedia.org/wiki/Packet_Forwarding_Control_Protocol', + category: 'protocol-mechanics' }, { - id: 'cups', - term: 'CUPS (Control and User Plane Separation)', - definition: - "The {{3gpp|3GPP}} architecture, mandatory in {{5g-nr|5G}}, that splits session-management signalling ({{smf|SMF}}) from packet forwarding ({{upf|UPF}}) and connects them with {{pfcp|PFCP}}. Lets operators scale data plane independently and deploy UPFs at the edge.", - wikiUrl: 'https://en.wikipedia.org/wiki/5G_network_slicing', - category: 'infrastructure' + id: 'cups', + term: 'CUPS (Control and User Plane Separation)', + definition: + 'The {{3gpp|3GPP}} architecture, mandatory in {{5g-nr|5G}}, that splits session-management signalling ({{smf|SMF}}) from packet forwarding ({{upf|UPF}}) and connects them with {{pfcp|PFCP}}. Lets operators scale data plane independently and deploy UPFs at the edge.', + wikiUrl: 'https://en.wikipedia.org/wiki/5G_network_slicing', + category: 'infrastructure' }, { - id: 'ssb', - term: 'SSB (Synchronization Signal Block)', - definition: - "The {{5g-nr|5G}} beacon a {{gnb|gNB}} radiates so {{ue|UEs}} can find it: a periodic burst containing PSS, SSS, and PBCH. UEs measure RSRP/RSRQ on the SSB to pick the best cell before sending a {{prach|PRACH}} preamble.", - wikiUrl: 'https://en.wikipedia.org/wiki/5G_NR_frequency_bands', - category: 'protocol-mechanics' + id: 'ssb', + term: 'SSB (Synchronization Signal Block)', + definition: + 'The {{5g-nr|5G}} beacon a {{gnb|gNB}} radiates so {{ue|UEs}} can find it: a periodic burst containing PSS, SSS, and PBCH. UEs measure RSRP/RSRQ on the SSB to pick the best cell before sending a {{prach|PRACH}} preamble.', + wikiUrl: 'https://en.wikipedia.org/wiki/5G_NR_frequency_bands', + category: 'protocol-mechanics' }, { - id: 'pan-id', - term: 'PAN ID (Personal Area Network Identifier)', - definition: - "The 16-bit identifier of an {{ieee-802-15-4|IEEE 802.15.4}} {{piconet|PAN}}. [[zigbee|Zigbee]] and Thread networks use the PAN ID to filter frames at the {{mac-address|MAC}} layer β€” devices only process frames matching their PAN ID. Picked by the {{zigbee-coordinator|Coordinator}} at network formation.", - wikiUrl: 'https://en.wikipedia.org/wiki/Personal_area_network', - category: 'networking-basics' + id: 'pan-id', + term: 'PAN ID (Personal Area Network Identifier)', + definition: + 'The 16-bit identifier of an {{ieee-802-15-4|IEEE 802.15.4}} {{piconet|PAN}}. [[zigbee|Zigbee]] and Thread networks use the PAN ID to filter frames at the {{mac-address|MAC}} layer β€” devices only process frames matching their PAN ID. Picked by the {{zigbee-coordinator|Coordinator}} at network formation.', + wikiUrl: 'https://en.wikipedia.org/wiki/Personal_area_network', + category: 'networking-basics' }, { - id: 'zigbee-coordinator', - term: 'Zigbee Coordinator', - definition: - "The single mandatory device that forms a [[zigbee|Zigbee]] network β€” picks the channel and {{pan-id|PAN ID}}, distributes the network key as the {{trust-center|Trust Center}}, and owns short address 0x0000. Usually mains-powered and always a {{ffd|Full Function Device}}.", - wikiUrl: 'https://en.wikipedia.org/wiki/Zigbee', - category: 'infrastructure' + id: 'zigbee-coordinator', + term: 'Zigbee Coordinator', + definition: + 'The single mandatory device that forms a [[zigbee|Zigbee]] network β€” picks the channel and {{pan-id|PAN ID}}, distributes the network key as the {{trust-center|Trust Center}}, and owns short address 0x0000. Usually mains-powered and always a {{ffd|Full Function Device}}.', + wikiUrl: 'https://en.wikipedia.org/wiki/Zigbee', + category: 'infrastructure' }, { - id: 'zigbee-router', - term: 'Zigbee Router', - definition: - "A mains-powered [[zigbee|Zigbee]] {{ffd|FFD}} that forwards frames on behalf of neighbours, enabling {{mesh-network|mesh}} routing via AODV. Routers also let new devices join the network by forwarding their Association Requests to the {{trust-center|Trust Center}}.", - wikiUrl: 'https://en.wikipedia.org/wiki/Zigbee', - category: 'infrastructure' + id: 'zigbee-router', + term: 'Zigbee Router', + definition: + 'A mains-powered [[zigbee|Zigbee]] {{ffd|FFD}} that forwards frames on behalf of neighbours, enabling {{mesh-network|mesh}} routing via AODV. Routers also let new devices join the network by forwarding their Association Requests to the {{trust-center|Trust Center}}.', + wikiUrl: 'https://en.wikipedia.org/wiki/Zigbee', + category: 'infrastructure' }, { - id: 'ffd', - term: 'FFD (Full Function Device)', - definition: - "An {{ieee-802-15-4|IEEE 802.15.4}} device that implements the full MAC and can route, act as a {{zigbee-coordinator|Coordinator}} or {{zigbee-router|Router}}, and talk to any other device. Contrast with {{rfd|RFD}} which can only talk to its parent.", - wikiUrl: 'https://en.wikipedia.org/wiki/IEEE_802.15.4', - category: 'networking-basics' + id: 'ffd', + term: 'FFD (Full Function Device)', + definition: + 'An {{ieee-802-15-4|IEEE 802.15.4}} device that implements the full MAC and can route, act as a {{zigbee-coordinator|Coordinator}} or {{zigbee-router|Router}}, and talk to any other device. Contrast with {{rfd|RFD}} which can only talk to its parent.', + wikiUrl: 'https://en.wikipedia.org/wiki/IEEE_802.15.4', + category: 'networking-basics' }, { - id: 'rfd', - term: 'RFD (Reduced Function Device)', - definition: - "An {{ieee-802-15-4|IEEE 802.15.4}} End Device that implements only the minimum MAC needed to talk to its parent. Typically battery-powered ([[zigbee|Zigbee]] sensors, buttons, end-line bulbs) and sleeps most of the time.", - wikiUrl: 'https://en.wikipedia.org/wiki/IEEE_802.15.4', - category: 'networking-basics' + id: 'rfd', + term: 'RFD (Reduced Function Device)', + definition: + 'An {{ieee-802-15-4|IEEE 802.15.4}} End Device that implements only the minimum MAC needed to talk to its parent. Typically battery-powered ([[zigbee|Zigbee]] sensors, buttons, end-line bulbs) and sleeps most of the time.', + wikiUrl: 'https://en.wikipedia.org/wiki/IEEE_802.15.4', + category: 'networking-basics' }, { - id: 'zigbee-joiner', - term: 'Zigbee Joiner', - definition: - "A new [[zigbee|Zigbee]] device attempting to join an existing network. Broadcasts a Beacon Request, picks a parent ({{zigbee-router|Router}} or {{zigbee-coordinator|Coordinator}}), sends an Association Request, and receives the network key encrypted under its pre-configured link key (often an {{install-code|install code}}).", - wikiUrl: 'https://en.wikipedia.org/wiki/Zigbee', - category: 'protocol-mechanics' + id: 'zigbee-joiner', + term: 'Zigbee Joiner', + definition: + 'A new [[zigbee|Zigbee]] device attempting to join an existing network. Broadcasts a Beacon Request, picks a parent ({{zigbee-router|Router}} or {{zigbee-coordinator|Coordinator}}), sends an Association Request, and receives the network key encrypted under its pre-configured link key (often an {{install-code|install code}}).', + wikiUrl: 'https://en.wikipedia.org/wiki/Zigbee', + category: 'protocol-mechanics' }, { - id: 'aps-layer', - term: 'APS (Application Support Sub-layer)', - definition: - "The [[zigbee|Zigbee]] layer sitting between {{zigbee-nwk|NWK}} and the application. Handles end-to-end addressing of clusters, APS-level encryption (Transport-Key commands carry the network key encrypted under the link key), and bindings. Frame format: APS header + ZCL payload.", - wikiUrl: 'https://en.wikipedia.org/wiki/Zigbee', - category: 'protocol-mechanics' + id: 'aps-layer', + term: 'APS (Application Support Sub-layer)', + definition: + 'The [[zigbee|Zigbee]] layer sitting between {{zigbee-nwk|NWK}} and the application. Handles end-to-end addressing of clusters, APS-level encryption (Transport-Key commands carry the network key encrypted under the link key), and bindings. Frame format: APS header + ZCL payload.', + wikiUrl: 'https://en.wikipedia.org/wiki/Zigbee', + category: 'protocol-mechanics' }, { - id: 'zigbee-nwk', - term: 'NWK (Zigbee Network Layer)', - definition: - "The [[zigbee|Zigbee]] layer responsible for {{mesh-network|mesh}} routing (AODV-based), short-address allocation, and Device Announce broadcasts. Sits between {{ieee-802-15-4|802.15.4 MAC}} and {{aps-layer|APS}}; every NWK frame is encrypted with the network key.", - wikiUrl: 'https://en.wikipedia.org/wiki/Zigbee', - category: 'protocol-mechanics' + id: 'zigbee-nwk', + term: 'NWK (Zigbee Network Layer)', + definition: + 'The [[zigbee|Zigbee]] layer responsible for {{mesh-network|mesh}} routing (AODV-based), short-address allocation, and Device Announce broadcasts. Sits between {{ieee-802-15-4|802.15.4 MAC}} and {{aps-layer|APS}}; every NWK frame is encrypted with the network key.', + wikiUrl: 'https://en.wikipedia.org/wiki/Zigbee', + category: 'protocol-mechanics' }, { - id: 'network-key', - term: 'Network Key (Zigbee)', - definition: - "The 128-bit AES key shared by every device on a [[zigbee|Zigbee]] network. Encrypts every {{zigbee-nwk|NWK}} frame in transit. Delivered to a new joiner by the {{trust-center|Trust Center}} via an {{aps-layer|APS}} Transport-Key command, itself encrypted under the joiner's pre-configured link key.", - wikiUrl: 'https://en.wikipedia.org/wiki/Zigbee', - category: 'security' + id: 'network-key', + term: 'Network Key (Zigbee)', + definition: + "The 128-bit AES key shared by every device on a [[zigbee|Zigbee]] network. Encrypts every {{zigbee-nwk|NWK}} frame in transit. Delivered to a new joiner by the {{trust-center|Trust Center}} via an {{aps-layer|APS}} Transport-Key command, itself encrypted under the joiner's pre-configured link key.", + wikiUrl: 'https://en.wikipedia.org/wiki/Zigbee', + category: 'security' }, { - id: 'short-address', - term: 'Short address (16-bit)', - definition: - "A 16-bit address assigned by the {{zigbee-coordinator|Coordinator}} to each [[zigbee|Zigbee]] device after Association. Used in every {{zigbee-nwk|NWK}} header instead of the full 8-byte {{eui-64|EUI-64}} to save airtime on the constrained {{ieee-802-15-4|802.15.4}} radio.", - wikiUrl: 'https://en.wikipedia.org/wiki/IEEE_802.15.4', - category: 'networking-basics' + id: 'short-address', + term: 'Short address (16-bit)', + definition: + 'A 16-bit address assigned by the {{zigbee-coordinator|Coordinator}} to each [[zigbee|Zigbee]] device after Association. Used in every {{zigbee-nwk|NWK}} header instead of the full 8-byte {{eui-64|EUI-64}} to save airtime on the constrained {{ieee-802-15-4|802.15.4}} radio.', + wikiUrl: 'https://en.wikipedia.org/wiki/IEEE_802.15.4', + category: 'networking-basics' }, { - id: 'eui-64', - term: 'EUI-64', - definition: - "A 64-bit globally unique identifier assigned by IEEE OUI to {{ieee-802-15-4|802.15.4}}, [[bluetooth|Bluetooth]], and [[ipv6|IPv6]] devices. The long-term factory-burned identity, exchanged once at join time, then replaced by a {{short-address|short address}} for normal traffic in [[zigbee|Zigbee]].", - wikiUrl: 'https://en.wikipedia.org/wiki/MAC_address', - category: 'networking-basics' + id: 'eui-64', + term: 'EUI-64', + definition: + 'A 64-bit globally unique identifier assigned by IEEE OUI to {{ieee-802-15-4|802.15.4}}, [[bluetooth|Bluetooth]], and [[ipv6|IPv6]] devices. The long-term factory-burned identity, exchanged once at join time, then replaced by a {{short-address|short address}} for normal traffic in [[zigbee|Zigbee]].', + wikiUrl: 'https://en.wikipedia.org/wiki/MAC_address', + category: 'networking-basics' }, { - id: 'zigbee-zdo', - term: 'ZDO (Zigbee Device Object)', - definition: - "Cluster 0x0013 on every [[zigbee|Zigbee]] device β€” handles device announcement, service discovery, binding, and network management. The Device Announce broadcast lets routers update their routing tables when a new device joins.", - wikiUrl: 'https://en.wikipedia.org/wiki/Zigbee', - category: 'protocol-mechanics' + id: 'zigbee-zdo', + term: 'ZDO (Zigbee Device Object)', + definition: + 'Cluster 0x0013 on every [[zigbee|Zigbee]] device β€” handles device announcement, service discovery, binding, and network management. The Device Announce broadcast lets routers update their routing tables when a new device joins.', + wikiUrl: 'https://en.wikipedia.org/wiki/Zigbee', + category: 'protocol-mechanics' }, { - id: 'aodv', - term: 'AODV (Ad-hoc On-demand Distance Vector)', - definition: - "The reactive {{mesh-network|mesh}} routing algorithm used by [[zigbee|Zigbee]] and other low-power meshes. Routes are discovered on demand via Route Request / Route Reply broadcasts; intermediate nodes cache routes and age them out. Trades convergence speed for low memory footprint.", - wikiUrl: 'https://en.wikipedia.org/wiki/Ad_hoc_On-Demand_Distance_Vector_Routing', - category: 'protocol-mechanics' + id: 'aodv', + term: 'AODV (Ad-hoc On-demand Distance Vector)', + definition: + 'The reactive {{mesh-network|mesh}} routing algorithm used by [[zigbee|Zigbee]] and other low-power meshes. Routes are discovered on demand via Route Request / Route Reply broadcasts; intermediate nodes cache routes and age them out. Trades convergence speed for low memory footprint.', + wikiUrl: 'https://en.wikipedia.org/wiki/Ad_hoc_On-Demand_Distance_Vector_Routing', + category: 'protocol-mechanics' }, { - id: 'ds-twr', - term: 'DS-TWR (Double-Sided Two-Way Ranging)', - definition: - "The three-message [[uwb|UWB]] ranging exchange (Poll, Response, Final) whose cross-product cancels relative clock drift between initiator and responder to first order. Achieves 10–30 cm distance accuracy where SS-TWR would drift with ppm clock error. Standardised in {{ieee-802-15-4|IEEE 802.15.4z}}.", - wikiUrl: 'https://en.wikipedia.org/wiki/Real-time_locating_system', - category: 'protocol-mechanics' + id: 'ds-twr', + term: 'DS-TWR (Double-Sided Two-Way Ranging)', + definition: + 'The three-message [[uwb|UWB]] ranging exchange (Poll, Response, Final) whose cross-product cancels relative clock drift between initiator and responder to first order. Achieves 10–30 cm distance accuracy where SS-TWR would drift with ppm clock error. Standardised in {{ieee-802-15-4|IEEE 802.15.4z}}.', + wikiUrl: 'https://en.wikipedia.org/wiki/Real-time_locating_system', + category: 'protocol-mechanics' }, { - id: 'sfd', - term: 'SFD (Start of Frame Delimiter)', - definition: - "The reference symbol an {{ieee-802-15-4|IEEE 802.15.4}} / [[uwb|UWB]] receiver locks onto to timestamp a frame's arrival. UWB DW3000-class chips resolve the SFD to ~15 picosecond precision β€” the foundation of {{tof-ranging|ToF}} distance measurement.", - wikiUrl: 'https://en.wikipedia.org/wiki/IEEE_802.15.4', - category: 'protocol-mechanics' + id: 'sfd', + term: 'SFD (Start of Frame Delimiter)', + definition: + "The reference symbol an {{ieee-802-15-4|IEEE 802.15.4}} / [[uwb|UWB]] receiver locks onto to timestamp a frame's arrival. UWB DW3000-class chips resolve the SFD to ~15 picosecond precision β€” the foundation of {{tof-ranging|ToF}} distance measurement.", + wikiUrl: 'https://en.wikipedia.org/wiki/IEEE_802.15.4', + category: 'protocol-mechanics' }, { - id: 'pake', - term: 'PAKE (Password-Authenticated Key Exchange)', - definition: - "A class of key-exchange protocols (SPAKE2+, OPAQUE, J-PAKE) that derive a strong shared key from a low-entropy password without leaking the password to an eavesdropper or active MITM. Used by {{ccc-digital-key|CCC Digital Key}}, {{matter|Matter}} commissioning, and WPA3 SAE.", - wikiUrl: 'https://en.wikipedia.org/wiki/Password-authenticated_key_agreement', - category: 'security' + id: 'pake', + term: 'PAKE (Password-Authenticated Key Exchange)', + definition: + 'A class of key-exchange protocols (SPAKE2+, OPAQUE, J-PAKE) that derive a strong shared key from a low-entropy password without leaking the password to an eavesdropper or active MITM. Used by {{ccc-digital-key|CCC Digital Key}}, {{matter|Matter}} commissioning, and WPA3 SAE.', + wikiUrl: 'https://en.wikipedia.org/wiki/Password-authenticated_key_agreement', + category: 'security' }, { - id: 'nearby-interaction', - term: 'Nearby Interaction (Apple)', - definition: - "Apple's framework that exposes [[uwb|UWB]] {{ds-twr|DS-TWR}} ranging on iPhone (U1/U2 chip) and Apple Watch to apps. Bootstraps the session over [[bluetooth|BLE]], runs UWB on Channel 9, refreshes distance and angle at ~10 Hz. The mechanism under AirTag Precision Finding.", - wikiUrl: 'https://developer.apple.com/nearbyinteraction/', - category: 'protocol-mechanics' + id: 'nearby-interaction', + term: 'Nearby Interaction (Apple)', + definition: + "Apple's framework that exposes [[uwb|UWB]] {{ds-twr|DS-TWR}} ranging on iPhone (U1/U2 chip) and Apple Watch to apps. Bootstraps the session over [[bluetooth|BLE]], runs UWB on Channel 9, refreshes distance and angle at ~10 Hz. The mechanism under AirTag Precision Finding.", + wikiUrl: 'https://developer.apple.com/nearbyinteraction/', + category: 'protocol-mechanics' }, // ── Acronym densification batch ──────────────────────────────────── @@ -6028,7 +6029,8 @@ export const concepts: Concept[] = [ term: 'API (Application Programming Interface)', definition: 'The contract a piece of software exposes for other software to call. On the web it almost always means an HTTP-spoken interface β€” [[rest|REST]], [[grpc|gRPC]], [[graphql|GraphQL]], [[json-rpc|JSON-RPC]] β€” with a published URL shape, method, request/response schema, and auth model.', - analogy: 'A restaurant menu: the kitchen exposes what it will cook, the rules, and the price β€” you order against the menu, not by walking into the kitchen.', + analogy: + 'A restaurant menu: the kitchen exposes what it will cook, the rules, and the price β€” you order against the menu, not by walking into the kitchen.', wikiUrl: 'https://en.wikipedia.org/wiki/API', category: 'web' }, @@ -6116,7 +6118,7 @@ export const concepts: Concept[] = [ id: 'ram', term: 'RAM (Random-Access Memory)', definition: - "Volatile working memory. In constrained-device contexts ([[coap|CoAP]] sensors, [[zigbee|Zigbee]] nodes), RAM is measured in kilobytes β€” a hard ceiling on how much protocol state you can keep per connection.", + 'Volatile working memory. In constrained-device contexts ([[coap|CoAP]] sensors, [[zigbee|Zigbee]] nodes), RAM is measured in kilobytes β€” a hard ceiling on how much protocol state you can keep per connection.', wikiUrl: 'https://en.wikipedia.org/wiki/Random-access_memory', category: 'infrastructure' }, @@ -6140,7 +6142,7 @@ export const concepts: Concept[] = [ id: 'html', term: 'HTML (HyperText Markup Language)', definition: - "The document format the web ships over [[http1|HTTP]]. Invented by [[pioneer:tim-berners-lee|Tim Berners-Lee]] at CERN in 1989 alongside HTTP and URLs β€” one of the three pillars that made the web a thing.", + 'The document format the web ships over [[http1|HTTP]]. Invented by [[pioneer:tim-berners-lee|Tim Berners-Lee]] at CERN in 1989 alongside HTTP and URLs β€” one of the three pillars that made the web a thing.', wikiUrl: 'https://en.wikipedia.org/wiki/HTML', category: 'web' }, @@ -6172,7 +6174,7 @@ export const concepts: Concept[] = [ id: 'uuid', term: 'UUID (Universally Unique Identifier)', definition: - "128-bit identifier with enough entropy that two systems can mint them independently without collision. Used everywhere from [[bluetooth|BLE]] service IDs to database primary keys to {{matter|Matter}} fabric IDs.", + '128-bit identifier with enough entropy that two systems can mint them independently without collision. Used everywhere from [[bluetooth|BLE]] service IDs to database primary keys to {{matter|Matter}} fabric IDs.', wikiUrl: 'https://en.wikipedia.org/wiki/Universally_unique_identifier', category: 'protocol-mechanics' }, @@ -6219,7 +6221,7 @@ export const concepts: Concept[] = [ id: 'osi', term: 'OSI (Open Systems Interconnection)', definition: - "The seven-layer reference model (Physical, Data Link, Network, Transport, Session, Presentation, Application) that the world learned networking through, even though the actual OSI protocol suite lost to [[tcp|TCP]]/[[ip|IP]]. Still the lingua franca for arguing about which layer a problem belongs to.", + 'The seven-layer reference model (Physical, Data Link, Network, Transport, Session, Presentation, Application) that the world learned networking through, even though the actual OSI protocol suite lost to [[tcp|TCP]]/[[ip|IP]]. Still the lingua franca for arguing about which layer a problem belongs to.', wikiUrl: 'https://en.wikipedia.org/wiki/OSI_model', category: 'networking-basics' }, @@ -6243,7 +6245,7 @@ export const concepts: Concept[] = [ id: 'mtu-acronym', term: 'MTU', definition: - "Maximum Transmission Unit β€” the largest [[ip|IP]] payload that fits in one [[ethernet|link-layer]] frame without fragmentation. Standard Ethernet is 1500 bytes; jumbo frames go to 9000; PMTUD and PLPMTUD find the smallest MTU on a path. See {{mtu|MTU}} for the full entry.", + 'Maximum Transmission Unit β€” the largest [[ip|IP]] payload that fits in one [[ethernet|link-layer]] frame without fragmentation. Standard Ethernet is 1500 bytes; jumbo frames go to 9000; PMTUD and PLPMTUD find the smallest MTU on a path. See {{mtu|MTU}} for the full entry.', wikiUrl: 'https://en.wikipedia.org/wiki/Maximum_transmission_unit', category: 'protocol-mechanics' }, @@ -6251,7 +6253,7 @@ export const concepts: Concept[] = [ id: 'sla', term: 'SLA (Service Level Agreement)', definition: - "The contracted promise β€” typically a percentage uptime, a latency budget, a [[#rto|RTO]] β€” that a service makes to its customers. Often the lever that forces an architecture change after an outage.", + 'The contracted promise β€” typically a percentage uptime, a latency budget, a [[#rto|RTO]] β€” that a service makes to its customers. Often the lever that forces an architecture change after an outage.', wikiUrl: 'https://en.wikipedia.org/wiki/Service-level_agreement', category: 'infrastructure' }, @@ -6301,7 +6303,7 @@ export const concepts: Concept[] = [ id: 'ibm', term: 'IBM', definition: - "International Business Machines. The mainframe giant whose 1970s networking (SNA) the internet replaced β€” and whose later research arms shipped MQTT (Andy Stanford-Clark), RSA-precursor work, and a long tail of standards committee labour.", + 'International Business Machines. The mainframe giant whose 1970s networking (SNA) the internet replaced β€” and whose later research arms shipped MQTT (Andy Stanford-Clark), RSA-precursor work, and a long tail of standards committee labour.', wikiUrl: 'https://en.wikipedia.org/wiki/IBM', category: 'infrastructure' }, @@ -6373,7 +6375,7 @@ export const concepts: Concept[] = [ id: 'parc', term: 'Xerox PARC', definition: - "Palo Alto Research Center. Where Ethernet was sketched in 1973 ([[pioneer:bob-metcalfe|Bob Metcalfe]], David Boggs), where the modern GUI was invented, where the Alto workstation networked over the original 2.94 Mb/s Ethernet β€” a stunning concentration of firsts.", + 'Palo Alto Research Center. Where Ethernet was sketched in 1973 ([[pioneer:bob-metcalfe|Bob Metcalfe]], David Boggs), where the modern GUI was invented, where the Alto workstation networked over the original 2.94 Mb/s Ethernet β€” a stunning concentration of firsts.', wikiUrl: 'https://en.wikipedia.org/wiki/PARC_(company)', category: 'infrastructure' }, @@ -6399,7 +6401,7 @@ export const concepts: Concept[] = [ id: 'aes-128', term: 'AES-128', definition: - "[[#aes|AES]] with a 128-bit key β€” 10 rounds, fast everywhere. Used by MIFARE DESFire EV2/EV3, [[wireguard|WireGuard]] (via ChaCha alternative), TLS 1.3 cipher suites, and [[ipsec|IPsec]] ESP defaults.", + '[[#aes|AES]] with a 128-bit key β€” 10 rounds, fast everywhere. Used by MIFARE DESFire EV2/EV3, [[wireguard|WireGuard]] (via ChaCha alternative), TLS 1.3 cipher suites, and [[ipsec|IPsec]] ESP defaults.', wikiUrl: 'https://en.wikipedia.org/wiki/Advanced_Encryption_Standard', category: 'security' }, @@ -6407,7 +6409,7 @@ export const concepts: Concept[] = [ id: 'md5', term: 'MD5 (Message-Digest 5)', definition: - "The 128-bit hash function Ron Rivest published in 1991. Practical collision attacks since 2004 (Wang Xiaoyun) made it cryptographically dead, but its checksum use in `MD5SUM` files and legacy [[bgp|BGP]] / [[tcp|TCP]]-MD5 lingers.", + 'The 128-bit hash function Ron Rivest published in 1991. Practical collision attacks since 2004 (Wang Xiaoyun) made it cryptographically dead, but its checksum use in `MD5SUM` files and legacy [[bgp|BGP]] / [[tcp|TCP]]-MD5 lingers.', wikiUrl: 'https://en.wikipedia.org/wiki/MD5', category: 'security' }, @@ -6423,7 +6425,7 @@ export const concepts: Concept[] = [ id: 'sha256', term: 'SHA-256', definition: - "256-bit member of the SHA-2 family β€” the workhorse hash for HMAC, [[tls|TLS]] 1.3 transcripts, Bitcoin, [[ssh|SSH]] fingerprints, and almost every modern signature scheme.", + '256-bit member of the SHA-2 family β€” the workhorse hash for HMAC, [[tls|TLS]] 1.3 transcripts, Bitcoin, [[ssh|SSH]] fingerprints, and almost every modern signature scheme.', wikiUrl: 'https://en.wikipedia.org/wiki/SHA-2', category: 'security' }, @@ -6431,7 +6433,7 @@ export const concepts: Concept[] = [ id: 'sha2', term: 'SHA-2', definition: - "Family of [[#nist|NIST]] hash functions (SHA-224/256/384/512) published in 2001 to replace [[#sha1|SHA-1]]. Still considered secure in 2026, but the world is migrating to SHA-3 and post-quantum primitives in parallel.", + 'Family of [[#nist|NIST]] hash functions (SHA-224/256/384/512) published in 2001 to replace [[#sha1|SHA-1]]. Still considered secure in 2026, but the world is migrating to SHA-3 and post-quantum primitives in parallel.', wikiUrl: 'https://en.wikipedia.org/wiki/SHA-2', category: 'security' }, @@ -6455,7 +6457,7 @@ export const concepts: Concept[] = [ id: 'ecc', term: 'ECC (Elliptic Curve Cryptography)', definition: - "Public-key cryptography over elliptic curves β€” equivalent security to RSA at much smaller key sizes (256-bit ECC β‰ˆ 3072-bit RSA). The basis of [[#ecdhe|ECDHE]], [[#ecdsa|ECDSA]], Ed25519, and [[#x25519|X25519]].", + 'Public-key cryptography over elliptic curves β€” equivalent security to RSA at much smaller key sizes (256-bit ECC β‰ˆ 3072-bit RSA). The basis of [[#ecdhe|ECDHE]], [[#ecdsa|ECDSA]], Ed25519, and [[#x25519|X25519]].', wikiUrl: 'https://en.wikipedia.org/wiki/Elliptic-curve_cryptography', category: 'security' }, @@ -6471,7 +6473,7 @@ export const concepts: Concept[] = [ id: 'ecdsa-acr', term: 'ECDSA (Elliptic Curve Digital Signature Algorithm)', definition: - "[[#ecc|Elliptic-curve]] signature scheme used in [[tls|TLS]] server certificates, [[ssh|SSH]] host keys, and most blockchains. Smaller signatures and keys than RSA at equivalent security.", + '[[#ecc|Elliptic-curve]] signature scheme used in [[tls|TLS]] server certificates, [[ssh|SSH]] host keys, and most blockchains. Smaller signatures and keys than RSA at equivalent security.', wikiUrl: 'https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm', category: 'security' }, @@ -6487,7 +6489,7 @@ export const concepts: Concept[] = [ id: 'spake2', term: 'SPAKE2', definition: - "Password-authenticated key {{exchange|exchange}} β€” derives a strong session key from a low-entropy password without leaking it. Used by {{matter|Matter}} commissioning (SPAKE2+), {{ccc-digital-key|CCC Digital Key}}, and a growing slice of zero-trust pairing flows.", + 'Password-authenticated key {{exchange|exchange}} β€” derives a strong session key from a low-entropy password without leaking it. Used by {{matter|Matter}} commissioning (SPAKE2+), {{ccc-digital-key|CCC Digital Key}}, and a growing slice of zero-trust pairing flows.', wikiUrl: 'https://datatracker.ietf.org/doc/rfc9382/', category: 'security' }, @@ -6495,7 +6497,7 @@ export const concepts: Concept[] = [ id: 'pq', term: 'PQ (Post-Quantum)', definition: - "Shorthand for *post-quantum* cryptography β€” primitives believed to survive a sufficiently large quantum computer. Hybrid PQ key exchange (X25519 + ML-KEM) is rolling out in [[tls|TLS]] now to defeat *harvest-now-decrypt-later* adversaries.", + 'Shorthand for *post-quantum* cryptography β€” primitives believed to survive a sufficiently large quantum computer. Hybrid PQ key exchange (X25519 + ML-KEM) is rolling out in [[tls|TLS]] now to defeat *harvest-now-decrypt-later* adversaries.', wikiUrl: 'https://en.wikipedia.org/wiki/Post-quantum_cryptography', category: 'security' }, @@ -6511,7 +6513,7 @@ export const concepts: Concept[] = [ id: 'nist', term: 'NIST (National Institute of Standards and Technology)', definition: - "The US standards body that runs cryptographic standardisation β€” [[#aes|AES]] (FIPS 197), SHA-2/SHA-3, [[#pqc|PQC]] (FIPS 203/204/205). Its calls for proposals quietly set the global crypto agenda.", + 'The US standards body that runs cryptographic standardisation β€” [[#aes|AES]] (FIPS 197), SHA-2/SHA-3, [[#pqc|PQC]] (FIPS 203/204/205). Its calls for proposals quietly set the global crypto agenda.', wikiUrl: 'https://en.wikipedia.org/wiki/National_Institute_of_Standards_and_Technology', category: 'security' }, @@ -6527,7 +6529,7 @@ export const concepts: Concept[] = [ id: 'cve', term: 'CVE (Common Vulnerabilities and Exposures)', definition: - "The MITRE-run public catalogue of disclosed security flaws β€” every entry has a CVE-YYYY-NNNNN identifier so vendors, scanners, and incident responders can talk about the same bug. Most protocol weaknesses you read about here (Heartbleed, KNOB, BLUFFS) have CVE numbers attached.", + 'The MITRE-run public catalogue of disclosed security flaws β€” every entry has a CVE-YYYY-NNNNN identifier so vendors, scanners, and incident responders can talk about the same bug. Most protocol weaknesses you read about here (Heartbleed, KNOB, BLUFFS) have CVE numbers attached.', wikiUrl: 'https://en.wikipedia.org/wiki/Common_Vulnerabilities_and_Exposures', category: 'security' }, @@ -6575,7 +6577,7 @@ export const concepts: Concept[] = [ id: 'hsm', term: 'HSM (Hardware Security Module)', definition: - "A tamper-resistant box (USB key, PCIe card, rack appliance) that holds private keys and signs / decrypts inside the device β€” keys never leave the boundary. Used for [[tls|TLS]] root CAs, payment HSMs, and modern enclave-style auth.", + 'A tamper-resistant box (USB key, PCIe card, rack appliance) that holds private keys and signs / decrypts inside the device β€” keys never leave the boundary. Used for [[tls|TLS]] root CAs, payment HSMs, and modern enclave-style auth.', wikiUrl: 'https://en.wikipedia.org/wiki/Hardware_security_module', category: 'security' }, @@ -6583,7 +6585,7 @@ export const concepts: Concept[] = [ id: 'sso', term: 'SSO (Single Sign-On)', definition: - "Login once, access many services β€” the property [[oauth2|OAuth]] / OIDC / [[ssh|Kerberos]] / SAML all deliver in different shapes. The convenience that makes federated identity worth the integration pain.", + 'Login once, access many services β€” the property [[oauth2|OAuth]] / OIDC / [[ssh|Kerberos]] / SAML all deliver in different shapes. The convenience that makes federated identity worth the integration pain.', wikiUrl: 'https://en.wikipedia.org/wiki/Single_sign-on', category: 'security' }, @@ -6609,7 +6611,7 @@ export const concepts: Concept[] = [ id: 'crud', term: 'CRUD', definition: - "Create, Read, Update, Delete β€” the canonical four operations almost every backend resource maps onto. REST maps these to POST / GET / PUT-PATCH / DELETE.", + 'Create, Read, Update, Delete β€” the canonical four operations almost every backend resource maps onto. REST maps these to POST / GET / PUT-PATCH / DELETE.', wikiUrl: 'https://en.wikipedia.org/wiki/Create,_read,_update_and_delete', category: 'web' }, @@ -6617,7 +6619,7 @@ export const concepts: Concept[] = [ id: 'mime-acr', term: 'MIME', definition: - "Multipurpose Internet Mail Extensions β€” the [[rfc:2045|RFC 2045]] / [[rfc:2046|RFC 2046]] machinery for tagging payload types (`text/html`, `image/png`, `application/json`) and bundling attachments. Born for [[smtp|email]], reused as the `Content-Type` system of [[http1|HTTP]] and HTTP/2/3.", + 'Multipurpose Internet Mail Extensions β€” the [[rfc:2045|RFC 2045]] / [[rfc:2046|RFC 2046]] machinery for tagging payload types (`text/html`, `image/png`, `application/json`) and bundling attachments. Born for [[smtp|email]], reused as the `Content-Type` system of [[http1|HTTP]] and HTTP/2/3.', wikiUrl: 'https://en.wikipedia.org/wiki/MIME', category: 'web' }, @@ -6625,7 +6627,7 @@ export const concepts: Concept[] = [ id: 'ssl-cert', term: 'SSL Cert', definition: - "Colloquial name for a [[tls|TLS]] X.509 server certificate β€” the file your CA issued you, even though SSL itself was retired around 1999. The acronym refuses to die.", + 'Colloquial name for a [[tls|TLS]] X.509 server certificate β€” the file your CA issued you, even though SSL itself was retired around 1999. The acronym refuses to die.', wikiUrl: 'https://en.wikipedia.org/wiki/Public_key_certificate', category: 'security' }, @@ -6675,7 +6677,7 @@ export const concepts: Concept[] = [ id: 'crc', term: 'CRC (Cyclic Redundancy Check)', definition: - "A polynomial checksum used at almost every protocol layer ([[ethernet|Ethernet]] FCS, IP/TCP checksums, [[zigbee|802.15.4]] PHY) to detect bit errors. Cheap to compute in hardware; defeats single- and burst-errors of bounded length.", + 'A polynomial checksum used at almost every protocol layer ([[ethernet|Ethernet]] FCS, IP/TCP checksums, [[zigbee|802.15.4]] PHY) to detect bit errors. Cheap to compute in hardware; defeats single- and burst-errors of bounded length.', wikiUrl: 'https://en.wikipedia.org/wiki/Cyclic_redundancy_check', category: 'protocol-mechanics' }, @@ -6715,7 +6717,7 @@ export const concepts: Concept[] = [ id: 'isis', term: 'IS-IS (Intermediate System to Intermediate System)', definition: - "Link-state routing protocol from the OSI suite ([[#iso-iec|ISO/IEC]] 10589) that quietly runs inside most large ISP backbones β€” same family as [[ospf|OSPF]] but encoded directly on top of [[ethernet|L2]] rather than [[ip|IP]]. Loved by Tier-1s for its multi-protocol cleanliness.", + 'Link-state routing protocol from the OSI suite ([[#iso-iec|ISO/IEC]] 10589) that quietly runs inside most large ISP backbones β€” same family as [[ospf|OSPF]] but encoded directly on top of [[ethernet|L2]] rather than [[ip|IP]]. Loved by Tier-1s for its multi-protocol cleanliness.', wikiUrl: 'https://en.wikipedia.org/wiki/IS-IS', category: 'protocol-mechanics' }, @@ -6731,7 +6733,7 @@ export const concepts: Concept[] = [ id: 'med', term: 'MED (Multi-Exit Discriminator)', definition: - "A [[bgp|BGP]] attribute (path-selection step 7) that lets an AS hint to its neighbour which of multiple links is preferred for inbound traffic. Meaningful only between paths from the *same* neighbouring AS β€” a frequent source of policy confusion.", + 'A [[bgp|BGP]] attribute (path-selection step 7) that lets an AS hint to its neighbour which of multiple links is preferred for inbound traffic. Meaningful only between paths from the *same* neighbouring AS β€” a frequent source of policy confusion.', wikiUrl: 'https://en.wikipedia.org/wiki/Border_Gateway_Protocol#MULTI_EXIT_DISC', category: 'protocol-mechanics' }, @@ -6739,7 +6741,7 @@ export const concepts: Concept[] = [ id: 'sfu', term: 'SFU (Selective Forwarding Unit)', definition: - 'A media server that receives each [[webrtc|WebRTC]] participant\'s stream once and forwards copies to the other participants β€” without transcoding. The scalable middle ground between mesh (every-to-every) and MCU (re-encode in the middle).', + "A media server that receives each [[webrtc|WebRTC]] participant's stream once and forwards copies to the other participants β€” without transcoding. The scalable middle ground between mesh (every-to-every) and MCU (re-encode in the middle).", wikiUrl: 'https://webrtcglossary.com/sfu/', category: 'protocol-mechanics' }, @@ -6747,7 +6749,7 @@ export const concepts: Concept[] = [ id: 'sip-uri', term: 'SIP URI', definition: - "`sip:alice@example.com` or `sips:alice@example.com` β€” the addressable identifier for a [[sip|SIP]] endpoint. `sips:` requires [[tls|TLS]] hop-by-hop but does not promise end-to-end encryption (an upstream relay sees plaintext).", + '`sip:alice@example.com` or `sips:alice@example.com` β€” the addressable identifier for a [[sip|SIP]] endpoint. `sips:` requires [[tls|TLS]] hop-by-hop but does not promise end-to-end encryption (an upstream relay sees plaintext).', wikiUrl: 'https://en.wikipedia.org/wiki/Session_Initiation_Protocol#SIP_URI', category: 'protocol-mechanics' }, @@ -6757,7 +6759,7 @@ export const concepts: Concept[] = [ id: 'gsm', term: 'GSM (Global System for Mobile Communications)', definition: - "The 2G European cellular standard (1991) that ate the world β€” first to digitise voice, first to define the SIM, the only network on which texting (SMS) was an accidental afterthought. Survives in patches for fallback in 2026.", + 'The 2G European cellular standard (1991) that ate the world β€” first to digitise voice, first to define the SIM, the only network on which texting (SMS) was an accidental afterthought. Survives in patches for fallback in 2026.', wikiUrl: 'https://en.wikipedia.org/wiki/GSM', category: 'protocol-mechanics' }, @@ -6765,7 +6767,7 @@ export const concepts: Concept[] = [ id: 'cdma', term: 'CDMA (Code-Division Multiple Access)', definition: - "Spread-spectrum multiple-access scheme [[pioneer:irwin-jacobs|Irwin Jacobs]] and Qualcomm shipped commercially in IS-95 (1995) β€” every user transmits on the same frequency, distinguished by orthogonal codes. The math underneath 3G WCDMA and CDMA2000.", + 'Spread-spectrum multiple-access scheme [[pioneer:irwin-jacobs|Irwin Jacobs]] and Qualcomm shipped commercially in IS-95 (1995) β€” every user transmits on the same frequency, distinguished by orthogonal codes. The math underneath 3G WCDMA and CDMA2000.', wikiUrl: 'https://en.wikipedia.org/wiki/Code-division_multiple_access', category: 'protocol-mechanics' }, @@ -6781,7 +6783,7 @@ export const concepts: Concept[] = [ id: 'umts', term: 'UMTS (Universal Mobile Telecommunications System)', definition: - "The 3GPP-defined 3G family β€” [[#wcdma|WCDMA]] radio + a packet core that finally treated data as a first-class citizen. Replaced by LTE in the 2010s and now shutting down worldwide.", + 'The 3GPP-defined 3G family β€” [[#wcdma|WCDMA]] radio + a packet core that finally treated data as a first-class citizen. Replaced by LTE in the 2010s and now shutting down worldwide.', wikiUrl: 'https://en.wikipedia.org/wiki/UMTS', category: 'protocol-mechanics' }, @@ -6789,7 +6791,7 @@ export const concepts: Concept[] = [ id: 'epc', term: 'EPC (Evolved Packet Core)', definition: - "The 4G/LTE all-IP core network β€” MME, SGW, PGW components β€” replacing the circuit-switched leftovers of 3G. Replaced again in 5G by the service-based architecture (5GC SBA).", + 'The 4G/LTE all-IP core network β€” MME, SGW, PGW components β€” replacing the circuit-switched leftovers of 3G. Replaced again in 5G by the service-based architecture (5GC SBA).', wikiUrl: 'https://en.wikipedia.org/wiki/System_Architecture_Evolution', category: 'protocol-mechanics' }, @@ -6797,7 +6799,7 @@ export const concepts: Concept[] = [ id: 'gps', term: 'GPS (Global Positioning System)', definition: - "US-operated satellite constellation that broadcasts time-stamped signals so a receiver can trilaterate position. Network-adjacent: GPS provides the high-precision time source many [[ntp|NTP]] / PTP stratum-1 servers discipline themselves to.", + 'US-operated satellite constellation that broadcasts time-stamped signals so a receiver can trilaterate position. Network-adjacent: GPS provides the high-precision time source many [[ntp|NTP]] / PTP stratum-1 servers discipline themselves to.', wikiUrl: 'https://en.wikipedia.org/wiki/Global_Positioning_System', category: 'infrastructure' }, @@ -6805,7 +6807,7 @@ export const concepts: Concept[] = [ id: 'qam', term: 'QAM (Quadrature Amplitude Modulation)', definition: - "A modulation scheme that packs multiple bits per symbol by varying amplitude and phase. 4096-QAM (Wi-Fi 7, DOCSIS 4.0) means 12 bits/symbol β€” at the cost of needing a clean SNR.", + 'A modulation scheme that packs multiple bits per symbol by varying amplitude and phase. 4096-QAM (Wi-Fi 7, DOCSIS 4.0) means 12 bits/symbol β€” at the cost of needing a clean SNR.', wikiUrl: 'https://en.wikipedia.org/wiki/Quadrature_amplitude_modulation', category: 'protocol-mechanics' }, @@ -6813,7 +6815,7 @@ export const concepts: Concept[] = [ id: 'bpsk', term: 'BPSK (Binary Phase Shift Keying)', definition: - "The simplest phase-modulation scheme β€” one bit per symbol, two phases 180Β° apart. Robust to noise, used in [[nfc|NFC-A]] PICC-to-PCD return signalling, GPS, and the lowest [[wifi|Wi-Fi]] data rates.", + 'The simplest phase-modulation scheme β€” one bit per symbol, two phases 180Β° apart. Robust to noise, used in [[nfc|NFC-A]] PICC-to-PCD return signalling, GPS, and the lowest [[wifi|Wi-Fi]] data rates.', wikiUrl: 'https://en.wikipedia.org/wiki/Phase-shift_keying#Binary_phase-shift_keying_(BPSK)', category: 'protocol-mechanics' }, @@ -6821,7 +6823,7 @@ export const concepts: Concept[] = [ id: 'csma-cd', term: 'CSMA/CD', definition: - "Carrier-Sense Multiple Access with Collision Detection β€” the original [[ethernet|Ethernet]] mediation algorithm: listen, talk, detect collisions, back off. Obsolete once switches replaced hubs; the modern descendant on Wi-Fi is {{csma-ca|CSMA/CA}}.", + 'Carrier-Sense Multiple Access with Collision Detection β€” the original [[ethernet|Ethernet]] mediation algorithm: listen, talk, detect collisions, back off. Obsolete once switches replaced hubs; the modern descendant on Wi-Fi is {{csma-ca|CSMA/CA}}.', wikiUrl: 'https://en.wikipedia.org/wiki/Carrier-sense_multiple_access_with_collision_detection', category: 'protocol-mechanics' }, @@ -6837,7 +6839,7 @@ export const concepts: Concept[] = [ id: 'mac-media', term: 'MAC (Media Access Control)', definition: - "The data-link sub-layer that decides *who talks next* on a shared medium β€” [[ethernet|Ethernet]] MAC, Wi-Fi MAC, [[zigbee|802.15.4]] MAC. Distinct from a {{mac-address|MAC address}}, which is the identifier the MAC layer uses.", + 'The data-link sub-layer that decides *who talks next* on a shared medium β€” [[ethernet|Ethernet]] MAC, Wi-Fi MAC, [[zigbee|802.15.4]] MAC. Distinct from a {{mac-address|MAC address}}, which is the identifier the MAC layer uses.', wikiUrl: 'https://en.wikipedia.org/wiki/Medium_access_control', category: 'networking-basics' }, @@ -6845,7 +6847,7 @@ export const concepts: Concept[] = [ id: 'ap-access-point', term: 'AP (Access Point)', definition: - "The radio that bridges [[wifi|Wi-Fi]] clients to the wired [[ethernet|Ethernet]] LAN. APs broadcast beacons announcing the SSID, do CSMA/CA arbitration, and own the BSS β€” the unit Wi-Fi roaming hops between.", + 'The radio that bridges [[wifi|Wi-Fi]] clients to the wired [[ethernet|Ethernet]] LAN. APs broadcast beacons announcing the SSID, do CSMA/CA arbitration, and own the BSS β€” the unit Wi-Fi roaming hops between.', wikiUrl: 'https://en.wikipedia.org/wiki/Wireless_access_point', category: 'protocol-mechanics' }, @@ -6853,7 +6855,7 @@ export const concepts: Concept[] = [ id: 'rts-cts', term: 'RTS/CTS', definition: - "Request-To-Send / Clear-To-Send β€” the optional [[wifi|Wi-Fi]] handshake that reserves a duration of the medium before a frame. Trades latency for protection against hidden-node collisions; mostly used at high data rates today.", + 'Request-To-Send / Clear-To-Send β€” the optional [[wifi|Wi-Fi]] handshake that reserves a duration of the medium before a frame. Trades latency for protection against hidden-node collisions; mostly used at high data rates today.', wikiUrl: 'https://en.wikipedia.org/wiki/IEEE_802.11_RTS/CTS', category: 'protocol-mechanics' }, @@ -6861,7 +6863,7 @@ export const concepts: Concept[] = [ id: 'sms', term: 'SMS (Short Message Service)', definition: - "160-character text messaging, born in the [[#gsm|GSM]] standard (1992) as a control-plane afterthought and accidentally becoming the most reliable global-reach messaging system on earth. Still the fallback for satellite Direct-to-Cell.", + '160-character text messaging, born in the [[#gsm|GSM]] standard (1992) as a control-plane afterthought and accidentally becoming the most reliable global-reach messaging system on earth. Still the fallback for satellite Direct-to-Cell.', wikiUrl: 'https://en.wikipedia.org/wiki/SMS', category: 'protocol-mechanics' }, @@ -6869,7 +6871,7 @@ export const concepts: Concept[] = [ id: 'docsis', term: 'DOCSIS (Data Over Cable Service Interface Specification)', definition: - "The protocol stack that turns cable-TV coax into broadband. DOCSIS 4.0 (2026 deployments) adds 4096-QAM, full-duplex, and {{l4s|L4S}} support for low-latency queueing.", + 'The protocol stack that turns cable-TV coax into broadband. DOCSIS 4.0 (2026 deployments) adds 4096-QAM, full-duplex, and {{l4s|L4S}} support for low-latency queueing.', wikiUrl: 'https://en.wikipedia.org/wiki/DOCSIS', category: 'protocol-mechanics' }, @@ -6887,7 +6889,7 @@ export const concepts: Concept[] = [ id: 'hevc', term: 'HEVC', definition: - "H.265 / High Efficiency Video Coding β€” successor to H.264, ~50% better compression for the same quality, but a patent thicket so dense that royalty-free AV1 was created to escape it.", + 'H.265 / High Efficiency Video Coding β€” successor to H.264, ~50% better compression for the same quality, but a patent thicket so dense that royalty-free AV1 was created to escape it.', wikiUrl: 'https://en.wikipedia.org/wiki/High_Efficiency_Video_Coding', category: 'web' }, @@ -6895,7 +6897,7 @@ export const concepts: Concept[] = [ id: 'drm', term: 'DRM (Digital Rights Management)', definition: - "The cryptographic + legal machinery that gates streamed video β€” Widevine, FairPlay, PlayReady. License exchanges flow over [[tls|TLS]] alongside the [[dash|DASH]] / [[hls|HLS]] media segments.", + 'The cryptographic + legal machinery that gates streamed video β€” Widevine, FairPlay, PlayReady. License exchanges flow over [[tls|TLS]] alongside the [[dash|DASH]] / [[hls|HLS]] media segments.', wikiUrl: 'https://en.wikipedia.org/wiki/Digital_rights_management', category: 'security' }, @@ -6913,7 +6915,7 @@ export const concepts: Concept[] = [ id: 'emv', term: 'EMV (Europay, Mastercard, Visa)', definition: - "The smart-card payment standard (and consortium) named after its founders. EMV runs on contactless and chip-and-PIN cards globally β€” over [[#iso-iec|ISO/IEC]] 14443 at the link layer, ISO 7816 at the application layer.", + 'The smart-card payment standard (and consortium) named after its founders. EMV runs on contactless and chip-and-PIN cards globally β€” over [[#iso-iec|ISO/IEC]] 14443 at the link layer, ISO 7816 at the application layer.', wikiUrl: 'https://en.wikipedia.org/wiki/EMV', category: 'protocol-mechanics' }, @@ -6929,7 +6931,7 @@ export const concepts: Concept[] = [ id: 'pcd', term: 'PCD (Proximity Coupling Device)', definition: - "The [[#iso-iec|ISO/IEC]] 14443 name for the *reader* in an [[nfc|NFC]] / contactless-card exchange β€” the active side that powers the antenna and initiates communication.", + 'The [[#iso-iec|ISO/IEC]] 14443 name for the *reader* in an [[nfc|NFC]] / contactless-card exchange β€” the active side that powers the antenna and initiates communication.', wikiUrl: 'https://en.wikipedia.org/wiki/ISO/IEC_14443', category: 'protocol-mechanics' }, @@ -6937,7 +6939,7 @@ export const concepts: Concept[] = [ id: 'tlv', term: 'TLV (Type-Length-Value)', definition: - "A compact, extensible encoding pattern β€” one byte of type, one or more bytes of length, then `length` bytes of value. Used by [[ipsec|IKE]], BGP attributes, [[nfc|NDEF]], EMV ICC data, and many constrained-device protocols.", + 'A compact, extensible encoding pattern β€” one byte of type, one or more bytes of length, then `length` bytes of value. Used by [[ipsec|IKE]], BGP attributes, [[nfc|NDEF]], EMV ICC data, and many constrained-device protocols.', wikiUrl: 'https://en.wikipedia.org/wiki/Type%E2%80%93length%E2%80%93value', category: 'protocol-mechanics' }, @@ -6945,7 +6947,7 @@ export const concepts: Concept[] = [ id: 'icao', term: 'ICAO (International Civil Aviation Organization)', definition: - "The UN agency that, alongside writing aviation rules, also defines the file structure of biometric e-passports β€” the data groups (DG1 MRZ, DG2 photo, EF.SOD, EF.COM) that an [[#iso-iec|ISO/IEC]] 14443-4 reader pulls off the passport chip.", + 'The UN agency that, alongside writing aviation rules, also defines the file structure of biometric e-passports β€” the data groups (DG1 MRZ, DG2 photo, EF.SOD, EF.COM) that an [[#iso-iec|ISO/IEC]] 14443-4 reader pulls off the passport chip.', wikiUrl: 'https://en.wikipedia.org/wiki/International_Civil_Aviation_Organization', category: 'infrastructure' }, @@ -6953,7 +6955,7 @@ export const concepts: Concept[] = [ id: 'se-secure-element', term: 'SE (Secure Element)', definition: - "A tamper-resistant chip inside a phone or card that holds keys and runs sensitive applets (payment, transit, access). The eSE in modern phones replaces SIM-based SE for [[nfc|NFC]] payments.", + 'A tamper-resistant chip inside a phone or card that holds keys and runs sensitive applets (payment, transit, access). The eSE in modern phones replaces SIM-based SE for [[nfc|NFC]] payments.', wikiUrl: 'https://www.globalplatform.org/specificationsdevice.asp', category: 'security' }, @@ -6969,7 +6971,7 @@ export const concepts: Concept[] = [ id: 'sak', term: 'SAK (Select Acknowledge)', definition: - "The byte an [[#iso-iec|ISO/IEC]] 14443-A card returns in response to a SELECT β€” encodes whether the card supports ISO 14443-4 and is the moment the reader decides which protocol stack to switch into.", + 'The byte an [[#iso-iec|ISO/IEC]] 14443-A card returns in response to a SELECT β€” encodes whether the card supports ISO 14443-4 and is the moment the reader decides which protocol stack to switch into.', wikiUrl: 'https://en.wikipedia.org/wiki/ISO/IEC_14443', category: 'protocol-mechanics' }, @@ -6979,7 +6981,7 @@ export const concepts: Concept[] = [ id: 'sig', term: 'SIG (Bluetooth SIG)', definition: - "The Bluetooth Special Interest Group β€” the standards body that owns the [[bluetooth|Bluetooth]] specs (Core, Mesh, LE Audio, BR/EDR). Members like Apple, Google, Samsung, and Microsoft drive what ends up in a release.", + 'The Bluetooth Special Interest Group β€” the standards body that owns the [[bluetooth|Bluetooth]] specs (Core, Mesh, LE Audio, BR/EDR). Members like Apple, Google, Samsung, and Microsoft drive what ends up in a release.', wikiUrl: 'https://www.bluetooth.com/about-us/', category: 'infrastructure' }, @@ -6995,7 +6997,7 @@ export const concepts: Concept[] = [ id: 'le-low-energy', term: 'LE (Low Energy)', definition: - "Short for [[bluetooth|Bluetooth Low Energy]] β€” the 2010 redesign for battery-constrained sensors and wearables. Different radio (BLE 2M PHY), different framing ({{l2cap|L2CAP}} / {{att-mtu|ATT}} / {{gatt|GATT}}), different threat model.", + 'Short for [[bluetooth|Bluetooth Low Energy]] β€” the 2010 redesign for battery-constrained sensors and wearables. Different radio (BLE 2M PHY), different framing ({{l2cap|L2CAP}} / {{att-mtu|ATT}} / {{gatt|GATT}}), different threat model.', wikiUrl: 'https://en.wikipedia.org/wiki/Bluetooth_Low_Energy', category: 'protocol-mechanics' }, @@ -7003,7 +7005,7 @@ export const concepts: Concept[] = [ id: 'att-attribute', term: 'ATT (Attribute Protocol)', definition: - "The [[bluetooth|BLE]] mid-layer that exposes named attributes (UUIDs) for read / write / notify operations. {{gatt|GATT}} is the profile layer on top of ATT.", + 'The [[bluetooth|BLE]] mid-layer that exposes named attributes (UUIDs) for read / write / notify operations. {{gatt|GATT}} is the profile layer on top of ATT.', wikiUrl: 'https://en.wikipedia.org/wiki/Bluetooth_Low_Energy#Generic_Attribute_Profile', category: 'protocol-mechanics' }, @@ -7019,7 +7021,7 @@ export const concepts: Concept[] = [ id: 'bis-broadcast', term: 'BIS (Broadcast Isochronous Stream)', definition: - "The [[bluetooth|BLE Audio]] stream type for one-to-many public audio β€” public Auracast hearing-loop, in-flight entertainment, gym-TV sound. The newer alternative to a {{cis|CIS}} unicast stream.", + 'The [[bluetooth|BLE Audio]] stream type for one-to-many public audio β€” public Auracast hearing-loop, in-flight entertainment, gym-TV sound. The newer alternative to a {{cis|CIS}} unicast stream.', wikiUrl: 'https://en.wikipedia.org/wiki/Bluetooth_LE_Audio', category: 'protocol-mechanics' }, @@ -7027,7 +7029,7 @@ export const concepts: Concept[] = [ id: 'knob-attack', term: 'KNOB Attack', definition: - "Key Negotiation Of Bluetooth (CVE-2019-9506) β€” downgraded BR/EDR pairing to a 1-byte session key, brute-forceable in seconds. Disclosed by Daniele Antonioli et al. in 2019.", + 'Key Negotiation Of Bluetooth (CVE-2019-9506) β€” downgraded BR/EDR pairing to a 1-byte session key, brute-forceable in seconds. Disclosed by Daniele Antonioli et al. in 2019.', wikiUrl: 'https://knobattack.com/', category: 'security' }, @@ -7035,7 +7037,7 @@ export const concepts: Concept[] = [ id: 'bias-attack', term: 'BIAS Attack', definition: - "Bluetooth Impersonation AttackS (CVE-2020-10135) β€” impersonated a previously-bonded BR/EDR device by exploiting the asymmetric authentication of legacy pairing. Same team as KNOB.", + 'Bluetooth Impersonation AttackS (CVE-2020-10135) β€” impersonated a previously-bonded BR/EDR device by exploiting the asymmetric authentication of legacy pairing. Same team as KNOB.', wikiUrl: 'https://francozappa.github.io/about-bias/', category: 'security' }, @@ -7043,7 +7045,7 @@ export const concepts: Concept[] = [ id: 'bluffs-attack', term: 'BLUFFS', definition: - "Bluetooth Forward And Future Secrecy attacks (CVE-2023-24023) β€” broke forward secrecy on BR/EDR Secure Connections sessions by forcing key reuse. Antonioli, 2023.", + 'Bluetooth Forward And Future Secrecy attacks (CVE-2023-24023) β€” broke forward secrecy on BR/EDR Secure Connections sessions by forcing key reuse. Antonioli, 2023.', wikiUrl: 'https://francozappa.github.io/about-bluffs/', category: 'security' }, @@ -7051,7 +7053,7 @@ export const concepts: Concept[] = [ id: 'sig-bluetooth-acronym', term: 'CSA (Connectivity Standards Alliance)', definition: - "The standards body formerly known as the Zigbee Alliance β€” owners of [[zigbee|Zigbee]] PRO and (since 2022) {{matter|Matter}}. Renamed in 2021 to escape the single-protocol branding.", + 'The standards body formerly known as the Zigbee Alliance β€” owners of [[zigbee|Zigbee]] PRO and (since 2022) {{matter|Matter}}. Renamed in 2021 to escape the single-protocol branding.', wikiUrl: 'https://csa-iot.org/', category: 'infrastructure' }, @@ -7061,7 +7063,7 @@ export const concepts: Concept[] = [ id: 'ccc', term: 'CCC (Car Connectivity Consortium)', definition: - "The standards body that defines Digital Key β€” the [[bluetooth|BLE]] + [[uwb|UWB]] protocol your phone uses to unlock and start cars from BMW, Mercedes, Hyundai, and a growing list.", + 'The standards body that defines Digital Key β€” the [[bluetooth|BLE]] + [[uwb|UWB]] protocol your phone uses to unlock and start cars from BMW, Mercedes, Hyundai, and a growing list.', wikiUrl: 'https://carconnectivity.org/', category: 'infrastructure' }, @@ -7069,7 +7071,7 @@ export const concepts: Concept[] = [ id: 'ces-show', term: 'CES (Consumer Electronics Show)', definition: - "The annual Las Vegas trade show where consumer-IoT roadmaps land β€” Matter device announcements, Digital Key partnerships, Wi-Fi alliance demos. Where a protocol becomes a press release.", + 'The annual Las Vegas trade show where consumer-IoT roadmaps land β€” Matter device announcements, Digital Key partnerships, Wi-Fi alliance demos. Where a protocol becomes a press release.', wikiUrl: 'https://en.wikipedia.org/wiki/Consumer_Electronics_Show', category: 'infrastructure' }, @@ -7077,7 +7079,7 @@ export const concepts: Concept[] = [ id: 'oem', term: 'OEM (Original Equipment Manufacturer)', definition: - "The company that builds a product end customers buy β€” BMW, Schlage, Hue. Distinct from a chip vendor (NXP, Qualcomm) or a standards body. The OEM is who has to ship firmware for every new protocol.", + 'The company that builds a product end customers buy β€” BMW, Schlage, Hue. Distinct from a chip vendor (NXP, Qualcomm) or a standards body. The OEM is who has to ship firmware for every new protocol.', wikiUrl: 'https://en.wikipedia.org/wiki/Original_equipment_manufacturer', category: 'infrastructure' }, @@ -7087,7 +7089,7 @@ export const concepts: Concept[] = [ id: 'ikev2', term: 'IKEv2', definition: - "Internet Key Exchange v2 β€” the [[ipsec|IPsec]] key-management protocol that negotiates Security Associations between peers. Defined in [[rfc:7296|RFC 7296]].", + 'Internet Key Exchange v2 β€” the [[ipsec|IPsec]] key-management protocol that negotiates Security Associations between peers. Defined in [[rfc:7296|RFC 7296]].', wikiUrl: 'https://en.wikipedia.org/wiki/Internet_Key_Exchange', category: 'security' }, @@ -7095,7 +7097,7 @@ export const concepts: Concept[] = [ id: 'esp', term: 'ESP (Encapsulating Security Payload)', definition: - "The [[ipsec|IPsec]] sub-protocol ([[rfc:4303|RFC 4303]]) that actually wraps and encrypts traffic between peers β€” distinct from IKE (key exchange) and AH (auth without encryption).", + 'The [[ipsec|IPsec]] sub-protocol ([[rfc:4303|RFC 4303]]) that actually wraps and encrypts traffic between peers β€” distinct from IKE (key exchange) and AH (auth without encryption).', wikiUrl: 'https://en.wikipedia.org/wiki/IPsec#Encapsulating_Security_Payload', category: 'security' }, @@ -7113,7 +7115,7 @@ export const concepts: Concept[] = [ id: 'frr', term: 'FRR (Free Range Routing)', definition: - "An open-source routing daemon ({{bgp|BGP}}, [[ospf|OSPF]], [[isis|IS-IS]], BFD) β€” the FreeBSD-licensed Quagga fork that runs on Linux switches and the Cumulus / SONiC ecosystem.", + 'An open-source routing daemon ({{bgp|BGP}}, [[ospf|OSPF]], [[isis|IS-IS]], BFD) β€” the FreeBSD-licensed Quagga fork that runs on Linux switches and the Cumulus / SONiC ecosystem.', wikiUrl: 'https://frrouting.org/', category: 'infrastructure' }, @@ -7156,14 +7158,15 @@ export const concepts: Concept[] = [ term: 'ROA (Route Origin Authorization)', definition: "A signed [[#rpki-acr|RPKI]] object that says 'AS X is authorised to originate prefix P with max-length M'. Networks running ROV ([[bgp|BGP]] route-origin validation) drop announcements that fail to match.", - wikiUrl: 'https://www.ripe.net/manage-ips-and-asns/resource-management/rpki/route-origin-authorisation', + wikiUrl: + 'https://www.ripe.net/manage-ips-and-asns/resource-management/rpki/route-origin-authorisation', category: 'security' }, { id: 'ripe-ncc', term: 'RIPE NCC', definition: - "RΓ©seaux IP EuropΓ©ens Network Coordination Centre β€” the regional internet registry for Europe and the Middle East. Allocates [[ip|IPv4]] / [[ipv6|IPv6]] address space and AS numbers; runs the {{atlas|RIPE Atlas}} measurement platform.", + 'RΓ©seaux IP EuropΓ©ens Network Coordination Centre β€” the regional internet registry for Europe and the Middle East. Allocates [[ip|IPv4]] / [[ipv6|IPv6]] address space and AS numbers; runs the {{atlas|RIPE Atlas}} measurement platform.', wikiUrl: 'https://www.ripe.net/about-us', category: 'infrastructure' }, @@ -7179,7 +7182,7 @@ export const concepts: Concept[] = [ id: 'arin', term: 'ARIN', definition: - "American Registry for Internet Numbers β€” the regional internet registry for the US, Canada, and parts of the Caribbean. Sister org to {{#ripe-ncc|RIPE NCC}}, {{#apnic|APNIC}}, AFRINIC, and LACNIC.", + 'American Registry for Internet Numbers β€” the regional internet registry for the US, Canada, and parts of the Caribbean. Sister org to {{#ripe-ncc|RIPE NCC}}, {{#apnic|APNIC}}, AFRINIC, and LACNIC.', wikiUrl: 'https://www.arin.net/', category: 'infrastructure' }, @@ -7197,7 +7200,7 @@ export const concepts: Concept[] = [ id: 'smtp-mail-from', term: 'MAIL FROM', definition: - "The [[smtp|SMTP]] command that declares the envelope sender β€” what bounces and 550 rejections route back to. Distinct from the `From:` *header* a user sees; mismatches between the two are how phishing makes a living.", + 'The [[smtp|SMTP]] command that declares the envelope sender β€” what bounces and 550 rejections route back to. Distinct from the `From:` *header* a user sees; mismatches between the two are how phishing makes a living.', wikiUrl: 'https://en.wikipedia.org/wiki/Bounce_address', category: 'protocol-mechanics' }, @@ -7205,7 +7208,7 @@ export const concepts: Concept[] = [ id: 'smtp-rcpt-to', term: 'RCPT TO', definition: - "The [[smtp|SMTP]] command that declares an envelope recipient. Issued once per recipient; each receives an independent reply. The server can accept some and reject others before any message data flows.", + 'The [[smtp|SMTP]] command that declares an envelope recipient. Issued once per recipient; each receives an independent reply. The server can accept some and reject others before any message data flows.', wikiUrl: 'https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol#SMTP_transport_example', category: 'protocol-mechanics' }, @@ -7213,7 +7216,7 @@ export const concepts: Concept[] = [ id: 'smtp-data', term: 'DATA', definition: - "The [[smtp|SMTP]] command that begins the message body β€” headers, MIME parts, attachments β€” terminated by a `.` on its own line. Everything before DATA is envelope; everything after is the user-visible message.", + 'The [[smtp|SMTP]] command that begins the message body β€” headers, MIME parts, attachments β€” terminated by a `.` on its own line. Everything before DATA is envelope; everything after is the user-visible message.', wikiUrl: 'https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol#SMTP_transport_example', category: 'protocol-mechanics' }, @@ -7221,7 +7224,7 @@ export const concepts: Concept[] = [ id: 'smtp-auth', term: 'AUTH (SMTP)', definition: - "The [[smtp|SMTP]] extension ([[rfc:4954|RFC 4954]]) for authenticated submission β€” historically AUTH LOGIN / PLAIN over [[tls|TLS]], now XOAUTH2 / [[oauth2|OAuth]] in modern providers (Microsoft 365 SMTP AUTH retires basic auth in 2026).", + 'The [[smtp|SMTP]] extension ([[rfc:4954|RFC 4954]]) for authenticated submission β€” historically AUTH LOGIN / PLAIN over [[tls|TLS]], now XOAUTH2 / [[oauth2|OAuth]] in modern providers (Microsoft 365 SMTP AUTH retires basic auth in 2026).', wikiUrl: 'https://datatracker.ietf.org/doc/html/rfc4954', category: 'security' }, @@ -7239,7 +7242,7 @@ export const concepts: Concept[] = [ id: 'sip-invite', term: 'INVITE (SIP)', definition: - "The [[sip|SIP]] method that initiates a session β€” `INVITE sip:bob@example.com SIP/2.0`, followed by SDP describing the proposed media. The 100/180/200 responses are the call-progression dance every SIP-stack tutorial draws.", + 'The [[sip|SIP]] method that initiates a session β€” `INVITE sip:bob@example.com SIP/2.0`, followed by SDP describing the proposed media. The 100/180/200 responses are the call-progression dance every SIP-stack tutorial draws.', wikiUrl: 'https://en.wikipedia.org/wiki/Session_Initiation_Protocol#Methods', category: 'protocol-mechanics' }, @@ -7249,7 +7252,7 @@ export const concepts: Concept[] = [ id: 'bgp-update', term: 'UPDATE (BGP)', definition: - "The [[bgp|BGP]] message type that announces or withdraws routes. A storm of UPDATE messages is the visible symptom of every famous route leak ({{as-7007-1997|AS 7007}}, Pakistan-YouTube, Facebook 2021).", + 'The [[bgp|BGP]] message type that announces or withdraws routes. A storm of UPDATE messages is the visible symptom of every famous route leak ({{as-7007-1997|AS 7007}}, Pakistan-YouTube, Facebook 2021).', wikiUrl: 'https://datatracker.ietf.org/doc/html/rfc4271#section-4.3', category: 'protocol-mechanics' }, @@ -7257,7 +7260,7 @@ export const concepts: Concept[] = [ id: 'bgp-keepalive', term: 'KEEPALIVE (BGP)', definition: - "The smallest [[bgp|BGP]] message β€” 19 bytes, no payload β€” sent every Hold-Time / 3 to keep a session alive. Missing for a full Hold-Time tears the session down and triggers route reconvergence.", + 'The smallest [[bgp|BGP]] message β€” 19 bytes, no payload β€” sent every Hold-Time / 3 to keep a session alive. Missing for a full Hold-Time tears the session down and triggers route reconvergence.', wikiUrl: 'https://datatracker.ietf.org/doc/html/rfc4271#section-4.4', category: 'protocol-mechanics' }, @@ -7275,7 +7278,7 @@ export const concepts: Concept[] = [ id: 'kerberos-ap-req-acr', term: 'AP-REQ', definition: - "The [[ssh|Kerberos]] Application Request β€” what a client sends to a service, containing the service ticket + a fresh authenticator. The service decrypts with its long-term key, verifies, and grants access.", + 'The [[ssh|Kerberos]] Application Request β€” what a client sends to a service, containing the service ticket + a fresh authenticator. The service decrypts with its long-term key, verifies, and grants access.', wikiUrl: 'https://datatracker.ietf.org/doc/html/rfc4120#section-3.2', category: 'security' }, @@ -7293,7 +7296,7 @@ export const concepts: Concept[] = [ id: 'eee', term: 'CES (cellular)', definition: - "Carrier Ethernet Services β€” the operator term for [[ethernet|Ethernet]] handoff between mobile networks and metro/aggregation. Different beast from the Vegas trade show CES.", + 'Carrier Ethernet Services β€” the operator term for [[ethernet|Ethernet]] handoff between mobile networks and metro/aggregation. Different beast from the Vegas trade show CES.', wikiUrl: 'https://en.wikipedia.org/wiki/Carrier_Ethernet', category: 'infrastructure' }, @@ -7303,7 +7306,7 @@ export const concepts: Concept[] = [ id: 'acm-org', term: 'ACM (Association for Computing Machinery)', definition: - "The oldest scientific computing society (1947). Runs SIGCOMM and the Web Conference; publishes the Communications of the ACM. Where most foundational networking papers land.", + 'The oldest scientific computing society (1947). Runs SIGCOMM and the Web Conference; publishes the Communications of the ACM. Where most foundational networking papers land.', wikiUrl: 'https://www.acm.org/', category: 'infrastructure' }, @@ -7319,7 +7322,7 @@ export const concepts: Concept[] = [ id: 'usenix-conf', term: 'USENIX', definition: - "The systems-and-security conference family (USENIX Security, NSDI, ATC, SOSP-adjacent). Home of major networking papers (Stevens-era and beyond).", + 'The systems-and-security conference family (USENIX Security, NSDI, ATC, SOSP-adjacent). Home of major networking papers (Stevens-era and beyond).', wikiUrl: 'https://www.usenix.org/', category: 'infrastructure' }, @@ -7327,7 +7330,7 @@ export const concepts: Concept[] = [ id: 'sigcomm-conf', term: 'SIGCOMM', definition: - "The ACM Special Interest Group on Data Communication β€” and its flagship annual conference. The forum that midwifed [[tcp|TCP]] congestion control, BBR, and most of the routing-protocol literature.", + 'The ACM Special Interest Group on Data Communication β€” and its flagship annual conference. The forum that midwifed [[tcp|TCP]] congestion control, BBR, and most of the routing-protocol literature.', wikiUrl: 'https://www.sigcomm.org/', category: 'infrastructure' }, @@ -7347,7 +7350,7 @@ export const concepts: Concept[] = [ id: 'rfc-doc', term: 'RFC', definition: - "Request for Comments β€” the document series that defines internet protocols. Published by the [[ietf|IETF]] (and historically by IAB, IRTF, Independent Stream). Every TCP/IP/HTTP/TLS rule you read about ultimately points to one. See {{ietf|IETF}} for the body that publishes them.", + 'Request for Comments β€” the document series that defines internet protocols. Published by the [[ietf|IETF]] (and historically by IAB, IRTF, Independent Stream). Every TCP/IP/HTTP/TLS rule you read about ultimately points to one. See {{ietf|IETF}} for the body that publishes them.', wikiUrl: 'https://en.wikipedia.org/wiki/Request_for_Comments', category: 'infrastructure' }, @@ -7355,7 +7358,7 @@ export const concepts: Concept[] = [ id: 'scp-copy', term: 'SCP (Secure Copy Protocol)', definition: - "The file-copy command/protocol layered on [[ssh|SSH]] β€” `scp file user@host:/path`. Written by Tatu YlΓΆnen with the original SSH; the wire protocol was deprecated in [[#rhel|RHEL]] 9 / OpenSSH 9.0 in favour of SFTP, though the `scp` command still works (now via SFTP under the hood).", + 'The file-copy command/protocol layered on [[ssh|SSH]] β€” `scp file user@host:/path`. Written by Tatu YlΓΆnen with the original SSH; the wire protocol was deprecated in [[#rhel|RHEL]] 9 / OpenSSH 9.0 in favour of SFTP, though the `scp` command still works (now via SFTP under the hood).', wikiUrl: 'https://en.wikipedia.org/wiki/Secure_copy_protocol', category: 'security' }, @@ -7363,7 +7366,7 @@ export const concepts: Concept[] = [ id: 'ask-modulation', term: 'ASK (Amplitude Shift Keying)', definition: - "A modulation scheme that encodes bits by varying carrier amplitude. [[nfc|NFC]] Type-A uses 100% ASK modified-Miller from reader to card β€” the carrier briefly drops to zero, which is easy to demodulate with the limited silicon in a passive card.", + 'A modulation scheme that encodes bits by varying carrier amplitude. [[nfc|NFC]] Type-A uses 100% ASK modified-Miller from reader to card β€” the carrier briefly drops to zero, which is easy to demodulate with the limited silicon in a passive card.', wikiUrl: 'https://en.wikipedia.org/wiki/Amplitude-shift_keying', category: 'protocol-mechanics' }, @@ -7379,7 +7382,7 @@ export const concepts: Concept[] = [ id: 'sel-iso', term: 'SEL (Select Command, ISO 14443)', definition: - "The [[#iso-iec|ISO/IEC]] 14443-3 anti-collision command β€” the reader walks the binary tree of card UIDs by sending SEL with progressively more of the UID until a single card is selected.", + 'The [[#iso-iec|ISO/IEC]] 14443-3 anti-collision command β€” the reader walks the binary tree of card UIDs by sending SEL with progressively more of the UID until a single card is selected.', wikiUrl: 'https://en.wikipedia.org/wiki/ISO/IEC_14443', category: 'protocol-mechanics' }, @@ -7387,7 +7390,7 @@ export const concepts: Concept[] = [ id: 'hosts-txt', term: 'HOSTS.TXT', definition: - "The single global text file that mapped hostnames to [[ip|IP]] addresses on the [[arpanet|ARPANET]] until 1983 β€” maintained at SRI-NIC, distributed by FTP, hand-edited per change. Replaced by [[dns|DNS]] in 1983 ([[rfc:882|RFC 882]] / [[rfc:883|RFC 883]]).", + 'The single global text file that mapped hostnames to [[ip|IP]] addresses on the [[arpanet|ARPANET]] until 1983 β€” maintained at SRI-NIC, distributed by FTP, hand-edited per change. Replaced by [[dns|DNS]] in 1983 ([[rfc:882|RFC 882]] / [[rfc:883|RFC 883]]).', wikiUrl: 'https://en.wikipedia.org/wiki/Hosts_(file)', category: 'infrastructure' }, @@ -7411,7 +7414,7 @@ export const concepts: Concept[] = [ id: 'cname-bare', term: 'CNAME', definition: - "Canonical-Name [[dns|DNS]] record β€” an alias from one name to another. Resolvers follow the chain. CNAMEs cannot coexist with other records at the same name, which is why the apex of a zone often needs ALIAS / ANAME / CNAME-flattening trickery instead.", + 'Canonical-Name [[dns|DNS]] record β€” an alias from one name to another. Resolvers follow the chain. CNAMEs cannot coexist with other records at the same name, which is why the apex of a zone often needs ALIAS / ANAME / CNAME-flattening trickery instead.', wikiUrl: 'https://en.wikipedia.org/wiki/CNAME_record', category: 'networking-basics' }, @@ -7435,7 +7438,7 @@ export const concepts: Concept[] = [ id: 'ts-3gpp', term: 'TS (3GPP Technical Specification)', definition: - "A numbered standards document published by {{3gpp|3GPP}} β€” TS 23.501 (5G System Architecture), TS 33.501 (Security Architecture), TS 38.401 (RAN Architecture). Different prefix than [[rfc:1|IETF RFCs]] but plays the same role in the cellular world.", + 'A numbered standards document published by {{3gpp|3GPP}} β€” TS 23.501 (5G System Architecture), TS 33.501 (Security Architecture), TS 38.401 (RAN Architecture). Different prefix than [[rfc:1|IETF RFCs]] but plays the same role in the cellular world.', wikiUrl: 'https://www.3gpp.org/specifications-technologies', category: 'protocol-mechanics' }, @@ -7443,7 +7446,7 @@ export const concepts: Concept[] = [ id: 'nba-mms', term: 'NBA-MMS', definition: - "Narrowband-Assisted Multi-Millisecond Sounding β€” the [[bluetooth|Bluetooth]] 6.0 (early 2026) {{channel-sounding|Channel Sounding}} extension that improves ranging accuracy at distance by interleaving a narrowband tone with the wideband sounding pulse.", + 'Narrowband-Assisted Multi-Millisecond Sounding β€” the [[bluetooth|Bluetooth]] 6.0 (early 2026) {{channel-sounding|Channel Sounding}} extension that improves ranging accuracy at distance by interleaving a narrowband tone with the wideband sounding pulse.', wikiUrl: 'https://www.bluetooth.com/specifications/specs/', category: 'protocol-mechanics' }, @@ -7459,7 +7462,7 @@ export const concepts: Concept[] = [ id: 'aes-ccm', term: 'AES-CCM', definition: - "AES in Counter with CBC-MAC mode β€” an AEAD that combines encryption and authentication. Used by [[zigbee|802.15.4]] link-layer security, COSE_Encrypt0 in {{matter|Matter}}, and {{coap|CoAP}}-OSCORE. Less common than {{aes-gcm|AES-GCM}} but easier on constrained hardware.", + 'AES in Counter with CBC-MAC mode β€” an AEAD that combines encryption and authentication. Used by [[zigbee|802.15.4]] link-layer security, COSE_Encrypt0 in {{matter|Matter}}, and {{coap|CoAP}}-OSCORE. Less common than {{aes-gcm|AES-GCM}} but easier on constrained hardware.', wikiUrl: 'https://en.wikipedia.org/wiki/CCM_mode', category: 'security' }, @@ -7467,7 +7470,7 @@ export const concepts: Concept[] = [ id: 'ccm-mode', term: 'CCM (Counter with CBC-MAC)', definition: - "The block-cipher mode of operation that combines CTR encryption with a CBC-MAC tag. CCM is the {{aes-ccm|AES-CCM}} family of constructions widely used in constrained-device networking.", + 'The block-cipher mode of operation that combines CTR encryption with a CBC-MAC tag. CCM is the {{aes-ccm|AES-CCM}} family of constructions widely used in constrained-device networking.', wikiUrl: 'https://en.wikipedia.org/wiki/CCM_mode', category: 'security' }, @@ -7483,7 +7486,7 @@ export const concepts: Concept[] = [ id: 'pq-ciphersuite', term: 'X25519MLKEM768', definition: - "The hybrid post-quantum [[tls|TLS]] 1.3 key {{exchange|exchange}} that combines classic {{#x25519|X25519}} with {{ml-kem|ML-KEM-768}}. Default key share in iOS 26 and Chrome 132+, switched on by default for Cloudflare-fronted sites in 2025.", + 'The hybrid post-quantum [[tls|TLS]] 1.3 key {{exchange|exchange}} that combines classic {{#x25519|X25519}} with {{ml-kem|ML-KEM-768}}. Default key share in iOS 26 and Chrome 132+, switched on by default for Cloudflare-fronted sites in 2025.', wikiUrl: 'https://blog.cloudflare.com/post-quantum-tls-with-x25519mlkem768/', category: 'security' }, @@ -7491,7 +7494,7 @@ export const concepts: Concept[] = [ id: 'nfc-v', term: 'NFC-V', definition: - "The [[#iso-iec|ISO/IEC]] 15693 long-range vicinity-coupling subtype of [[nfc|NFC]] β€” used for libraries, asset tags, and some access-control systems where 10–30 cm read range matters more than payment-grade security.", + 'The [[#iso-iec|ISO/IEC]] 15693 long-range vicinity-coupling subtype of [[nfc|NFC]] β€” used for libraries, asset tags, and some access-control systems where 10–30 cm read range matters more than payment-grade security.', wikiUrl: 'https://en.wikipedia.org/wiki/ISO/IEC_15693', category: 'protocol-mechanics' }, @@ -7499,7 +7502,7 @@ export const concepts: Concept[] = [ id: 'nfc-f', term: 'NFC-F (FeliCa)', definition: - "The Sony-designed [[nfc|NFC]] subtype standardised as {{#iso-iec|ISO/IEC}} 18092 β€” different framing from NFC-A/B, native to Japan (Suica, PASMO) and Hong Kong (Octopus) transit systems, and supported by every modern phone for Japanese-market payments.", + 'The Sony-designed [[nfc|NFC]] subtype standardised as {{#iso-iec|ISO/IEC}} 18092 β€” different framing from NFC-A/B, native to Japan (Suica, PASMO) and Hong Kong (Octopus) transit systems, and supported by every modern phone for Japanese-market payments.', wikiUrl: 'https://en.wikipedia.org/wiki/FeliCa', category: 'protocol-mechanics' }, @@ -7515,7 +7518,7 @@ export const concepts: Concept[] = [ id: 'pgw', term: 'PGW (PDN Gateway)', definition: - "The [[#epc|EPC]] component that connects user-plane traffic to the outside [[ip|IP]] world β€” handles QoS, charging, lawful intercept, and the [[#smtp-mail-from|GTP-U]] tunnels back toward the {{#sgw-3gpp|SGW}}.", + 'The [[#epc|EPC]] component that connects user-plane traffic to the outside [[ip|IP]] world β€” handles QoS, charging, lawful intercept, and the [[#smtp-mail-from|GTP-U]] tunnels back toward the {{#sgw-3gpp|SGW}}.', wikiUrl: 'https://en.wikipedia.org/wiki/System_Architecture_Evolution#PDN_Gateway', category: 'protocol-mechanics' }, @@ -7524,7 +7527,8 @@ export const concepts: Concept[] = [ term: 'MME (Mobility Management Entity)', definition: "The 4G [[#epc|EPC]] signalling brain β€” handles UE attach, authentication via the HSS, paging, and bearer setup. Replaced by AMF + SMF in 5G's service-based architecture.", - wikiUrl: 'https://en.wikipedia.org/wiki/System_Architecture_Evolution#Mobility_Management_Entity', + wikiUrl: + 'https://en.wikipedia.org/wiki/System_Architecture_Evolution#Mobility_Management_Entity', category: 'protocol-mechanics' }, @@ -7541,7 +7545,7 @@ export const concepts: Concept[] = [ id: 'spake2-plus', term: 'SPAKE2', definition: - "Password-authenticated key {{exchange|exchange}} β€” derives a strong session key from a low-entropy password without leaking it. The augmented SPAKE2+ variant ([[rfc:9383|RFC 9383]]) is what {{matter|Matter}} commissioning, {{ccc-digital-key|CCC Digital Key}}, and a growing slice of zero-trust pairing flows use.", + 'Password-authenticated key {{exchange|exchange}} β€” derives a strong session key from a low-entropy password without leaking it. The augmented SPAKE2+ variant ([[rfc:9383|RFC 9383]]) is what {{matter|Matter}} commissioning, {{ccc-digital-key|CCC Digital Key}}, and a growing slice of zero-trust pairing flows use.', wikiUrl: 'https://datatracker.ietf.org/doc/html/rfc9383', category: 'security' }, @@ -7549,7 +7553,7 @@ export const concepts: Concept[] = [ id: 'iso14443', term: 'ISO/IEC 14443', definition: - "The four-part standard for proximity contactless cards at 13.56 MHz β€” Type-A and Type-B physical layers, anti-collision (REQA/ATQA/SEL/SAK or ATQB/ATTRIB), block-oriented transmission. Almost every credit-card tap, transit card, and government-ID interaction passes through ISO 14443.", + 'The four-part standard for proximity contactless cards at 13.56 MHz β€” Type-A and Type-B physical layers, anti-collision (REQA/ATQA/SEL/SAK or ATQB/ATTRIB), block-oriented transmission. Almost every credit-card tap, transit card, and government-ID interaction passes through ISO 14443.', wikiUrl: 'https://en.wikipedia.org/wiki/ISO/IEC_14443', category: 'protocol-mechanics' }, @@ -7567,7 +7571,7 @@ export const concepts: Concept[] = [ id: 'cidr-acr', term: 'CIDR', definition: - "Classless Inter-Domain Routing ([[rfc:1518|RFC 1518]] / 1519, 1993) β€” replaced the rigid Class A/B/C [[ip|IPv4]] partition with the `prefix/length` notation (`10.0.0.0/8`). Without CIDR, [[ipv4|IPv4]] would have exhausted in the mid-1990s.", + 'Classless Inter-Domain Routing ([[rfc:1518|RFC 1518]] / 1519, 1993) β€” replaced the rigid Class A/B/C [[ip|IPv4]] partition with the `prefix/length` notation (`10.0.0.0/8`). Without CIDR, [[ipv4|IPv4]] would have exhausted in the mid-1990s.', wikiUrl: 'https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing', category: 'networking-basics' }, @@ -7575,7 +7579,7 @@ export const concepts: Concept[] = [ id: 'wan-acr', term: 'WAN (Wide-Area Network)', definition: - "A network that spans long distances β€” across cities, countries, continents. Distinguished from a LAN by latency, link cost, and the BGP routing that ties WAN segments together.", + 'A network that spans long distances β€” across cities, countries, continents. Distinguished from a LAN by latency, link cost, and the BGP routing that ties WAN segments together.', wikiUrl: 'https://en.wikipedia.org/wiki/Wide_area_network', category: 'networking-basics' }, @@ -7583,7 +7587,7 @@ export const concepts: Concept[] = [ id: 'lan-acr', term: 'LAN (Local-Area Network)', definition: - "The network inside one building or campus β€” Ethernet switches and Wi-Fi APs, usually one or two BGP-unaware autonomous systems wide.", + 'The network inside one building or campus β€” Ethernet switches and Wi-Fi APs, usually one or two BGP-unaware autonomous systems wide.', wikiUrl: 'https://en.wikipedia.org/wiki/Local_area_network', category: 'networking-basics' }, @@ -7599,7 +7603,7 @@ export const concepts: Concept[] = [ id: 'voip-acr', term: 'VoIP (Voice over IP)', definition: - "Carrying voice telephony over [[ip|IP]] networks instead of dedicated circuits β€” the umbrella the [[sip|SIP]] / [[rtp|RTP]] / [[#sdp-acr|SDP]] stack lives under. Killed the PSTN over two decades.", + 'Carrying voice telephony over [[ip|IP]] networks instead of dedicated circuits β€” the umbrella the [[sip|SIP]] / [[rtp|RTP]] / [[#sdp-acr|SDP]] stack lives under. Killed the PSTN over two decades.', wikiUrl: 'https://en.wikipedia.org/wiki/Voice_over_IP', category: 'protocol-mechanics' }, @@ -7607,7 +7611,7 @@ export const concepts: Concept[] = [ id: 'volte', term: 'VoLTE (Voice over LTE)', definition: - "Carrying voice as packets over the LTE / 5G data plane (typically via the IMS core and RTP) rather than the legacy 3G circuit-switched fallback. The modern default in most carriers as 2G/3G sunset.", + 'Carrying voice as packets over the LTE / 5G data plane (typically via the IMS core and RTP) rather than the legacy 3G circuit-switched fallback. The modern default in most carriers as 2G/3G sunset.', wikiUrl: 'https://en.wikipedia.org/wiki/Voice_over_LTE', category: 'protocol-mechanics' }, @@ -7633,7 +7637,7 @@ export const concepts: Concept[] = [ id: 'sli-metric', term: 'SLI', definition: - "Service Level Indicator β€” the actual measured metric (success rate, p99 latency) used to validate an {{#slo|SLO}}. Distinct from a metric in general because SLIs are picked specifically to map to user pain.", + 'Service Level Indicator β€” the actual measured metric (success rate, p99 latency) used to validate an {{#slo|SLO}}. Distinct from a metric in general because SLIs are picked specifically to map to user pain.', wikiUrl: 'https://en.wikipedia.org/wiki/Service_level_indicator', category: 'infrastructure' }, @@ -7641,7 +7645,7 @@ export const concepts: Concept[] = [ id: 'mtbf', term: 'MTBF (Mean Time Between Failures)', definition: - "Average elapsed time between unplanned outages of a system. Hardware reliability lives here; software people prefer SLOs/error budgets because MTBF stops being a useful aggregate for rapid-release systems.", + 'Average elapsed time between unplanned outages of a system. Hardware reliability lives here; software people prefer SLOs/error budgets because MTBF stops being a useful aggregate for rapid-release systems.', wikiUrl: 'https://en.wikipedia.org/wiki/Mean_time_between_failures', category: 'infrastructure' }, @@ -7649,7 +7653,7 @@ export const concepts: Concept[] = [ id: 'mttr-acr', term: 'MTTR (Mean Time To Recovery)', definition: - "How long, on average, an incident takes to resolve. A leading SRE metric β€” pairs with MTBF and feeds the error-budget math. Often the lever that drives investment in better tooling, deploys, and on-call.", + 'How long, on average, an incident takes to resolve. A leading SRE metric β€” pairs with MTBF and feeds the error-budget math. Often the lever that drives investment in better tooling, deploys, and on-call.', wikiUrl: 'https://en.wikipedia.org/wiki/Mean_time_to_recovery', category: 'infrastructure' }, @@ -7659,7 +7663,7 @@ export const concepts: Concept[] = [ id: 'pop-acr', term: 'PoP (Point of Presence)', definition: - "A physical location where a network provider, CDN, or carrier has gear β€” peering routers, anycast servers, optical regen. The unit of geographic reach for [[cloudflare|Cloudflare]], Netflix Open Connect, and big AS networks.", + 'A physical location where a network provider, CDN, or carrier has gear β€” peering routers, anycast servers, optical regen. The unit of geographic reach for [[cloudflare|Cloudflare]], Netflix Open Connect, and big AS networks.', wikiUrl: 'https://en.wikipedia.org/wiki/Point_of_presence', category: 'infrastructure' }, @@ -7667,7 +7671,7 @@ export const concepts: Concept[] = [ id: 'ix-acr', term: 'IX / IXP (Internet Exchange Point)', definition: - "A physical fabric (usually a building or campus) where many networks peer with each other directly via [[bgp|BGP]] β€” AMS-IX, DE-CIX, LINX, NL-ix. The reason a packet from one ISP to another rarely traverses a Tier-1 transit any more.", + 'A physical fabric (usually a building or campus) where many networks peer with each other directly via [[bgp|BGP]] β€” AMS-IX, DE-CIX, LINX, NL-ix. The reason a packet from one ISP to another rarely traverses a Tier-1 transit any more.', wikiUrl: 'https://en.wikipedia.org/wiki/Internet_exchange_point', category: 'infrastructure' }, @@ -7675,7 +7679,7 @@ export const concepts: Concept[] = [ id: 'cdn-acr', term: 'CDN', definition: - "Content Delivery Network β€” fleet of distributed cache servers that sits between origins and clients ([[cloudflare|Cloudflare]], Fastly, Akamai, Netflix Open Connect, AWS CloudFront). Cuts latency, absorbs DDoS, and terminates [[tls|TLS]] at the edge.", + 'Content Delivery Network β€” fleet of distributed cache servers that sits between origins and clients ([[cloudflare|Cloudflare]], Fastly, Akamai, Netflix Open Connect, AWS CloudFront). Cuts latency, absorbs DDoS, and terminates [[tls|TLS]] at the edge.', wikiUrl: 'https://en.wikipedia.org/wiki/Content_delivery_network', category: 'infrastructure' }, @@ -7685,7 +7689,7 @@ export const concepts: Concept[] = [ id: 'l4s-acr', term: 'L4S', definition: - "Low Latency, Low Loss, Scalable throughput ([[rfc:9330|RFC 9330]]) β€” a new active-queue-management scheme that uses ECN signalling for prompt feedback. Shipped in iOS 26, Apple TV, and DOCSIS 4.0 cable modems in 2025–26.", + 'Low Latency, Low Loss, Scalable throughput ([[rfc:9330|RFC 9330]]) β€” a new active-queue-management scheme that uses ECN signalling for prompt feedback. Shipped in iOS 26, Apple TV, and DOCSIS 4.0 cable modems in 2025–26.', wikiUrl: 'https://en.wikipedia.org/wiki/L4S', category: 'protocol-mechanics' }, @@ -7693,7 +7697,7 @@ export const concepts: Concept[] = [ id: 'wifi-7', term: 'Wi-Fi 7', definition: - "IEEE 802.11be (ratified July 2024, certified mid-2025) β€” 320 MHz channels, 4096-QAM, MLO (multi-link operation simultaneously across bands), 5–10Γ— the throughput of Wi-Fi 6. The first version positioning Wi-Fi as a cable-replacement for indoor 10 Gbps.", + 'IEEE 802.11be (ratified July 2024, certified mid-2025) β€” 320 MHz channels, 4096-QAM, MLO (multi-link operation simultaneously across bands), 5–10Γ— the throughput of Wi-Fi 6. The first version positioning Wi-Fi as a cable-replacement for indoor 10 Gbps.', wikiUrl: 'https://en.wikipedia.org/wiki/Wi-Fi_7', category: 'protocol-mechanics' }, @@ -7701,7 +7705,7 @@ export const concepts: Concept[] = [ id: 'wifi-8', term: 'Wi-Fi 8', definition: - "IEEE 802.11bn (in standards work, ~2028 ratification) β€” focused on reliability and AI/AR workloads rather than peak throughput. Will likely keep 4096-QAM and add tighter coordination across {{ap-access-point|APs}}.", + 'IEEE 802.11bn (in standards work, ~2028 ratification) β€” focused on reliability and AI/AR workloads rather than peak throughput. Will likely keep 4096-QAM and add tighter coordination across {{ap-access-point|APs}}.', wikiUrl: 'https://en.wikipedia.org/wiki/IEEE_802.11bn', category: 'protocol-mechanics' }, @@ -7711,7 +7715,7 @@ export const concepts: Concept[] = [ id: 'etsi', term: 'ETSI (European Telecommunications Standards Institute)', definition: - "The European standards body that co-runs {{3gpp|3GPP}} (alongside ARIB+TTC in Japan, ATIS in North America, CCSA in China, and TTA in Korea). Owns GSM, DECT, and the European side of every cellular standard since.", + 'The European standards body that co-runs {{3gpp|3GPP}} (alongside ARIB+TTC in Japan, ATIS in North America, CCSA in China, and TTA in Korea). Owns GSM, DECT, and the European side of every cellular standard since.', wikiUrl: 'https://www.etsi.org/', category: 'infrastructure' }, @@ -7727,7 +7731,7 @@ export const concepts: Concept[] = [ id: 'dult', term: 'DULT (Detecting Unwanted Location Trackers)', definition: - "Joint Apple-Google standard for tracker-stalking detection β€” born from the AirTag stalking incidents of 2022. Defines how iOS and Android scan for non-owner tracker beacons and warn the user.", + 'Joint Apple-Google standard for tracker-stalking detection β€” born from the AirTag stalking incidents of 2022. Defines how iOS and Android scan for non-owner tracker beacons and warn the user.', wikiUrl: 'https://datatracker.ietf.org/doc/draft-detecting-unwanted-location-trackers/', category: 'security' }, @@ -7751,7 +7755,7 @@ export const concepts: Concept[] = [ id: 'srlg', term: 'SRLG (Shared Risk Link Group)', definition: - "The set of links that share a single failure point (a fibre conduit, a card chassis). Path-computation algorithms ([[ospf|OSPF-TE]], {{isis|IS-IS-TE}}, segment routing) avoid SRLG overlap when building primary/backup pairs.", + 'The set of links that share a single failure point (a fibre conduit, a card chassis). Path-computation algorithms ([[ospf|OSPF-TE]], {{isis|IS-IS-TE}}, segment routing) avoid SRLG overlap when building primary/backup pairs.', wikiUrl: 'https://en.wikipedia.org/wiki/Shared_Risk_Link_Group', category: 'protocol-mechanics' }, @@ -7759,7 +7763,7 @@ export const concepts: Concept[] = [ id: 'ospf-dr', term: 'DR (Designated Router)', definition: - "On a multi-access [[ospf|OSPF]] segment (Ethernet, broadcast), one router is elected DR β€” it sources the network LSA and lets all other routers form adjacencies only with it, not pairwise. A Backup DR (BDR) shadows it.", + 'On a multi-access [[ospf|OSPF]] segment (Ethernet, broadcast), one router is elected DR β€” it sources the network LSA and lets all other routers form adjacencies only with it, not pairwise. A Backup DR (BDR) shadows it.', wikiUrl: 'https://en.wikipedia.org/wiki/Open_Shortest_Path_First#Designated_router', category: 'protocol-mechanics' }, @@ -7767,7 +7771,7 @@ export const concepts: Concept[] = [ id: 'clat-acr', term: 'CLAT (Customer-side Translator)', definition: - "The customer-side half of 464XLAT ([[rfc:6877|RFC 6877]]) β€” translates IPv4 traffic from legacy apps into IPv6 on an IPv6-only access network. Lets a phone or laptop run IPv4-only apps even when its carrier offers only IPv6.", + 'The customer-side half of 464XLAT ([[rfc:6877|RFC 6877]]) β€” translates IPv4 traffic from legacy apps into IPv6 on an IPv6-only access network. Lets a phone or laptop run IPv4-only apps even when its carrier offers only IPv6.', wikiUrl: 'https://datatracker.ietf.org/doc/html/rfc6877', category: 'networking-basics' }, @@ -7775,7 +7779,7 @@ export const concepts: Concept[] = [ id: 'hosts-bare', term: 'HOSTS', definition: - "The {{hosts-txt|HOSTS.TXT}} file β€” the single global text file that mapped hostnames to [[ip|IP]] addresses on the ARPANET before [[dns|DNS]] launched in 1983. Modern operating systems still have a tiny `/etc/hosts` for local overrides.", + 'The {{hosts-txt|HOSTS.TXT}} file β€” the single global text file that mapped hostnames to [[ip|IP]] addresses on the ARPANET before [[dns|DNS]] launched in 1983. Modern operating systems still have a tiny `/etc/hosts` for local overrides.', wikiUrl: 'https://en.wikipedia.org/wiki/Hosts_(file)', category: 'infrastructure' }, @@ -7783,7 +7787,7 @@ export const concepts: Concept[] = [ id: 'hrp-uwb', term: 'HRP (High Rate Pulse Repetition)', definition: - "The high-pulse-rate UWB mode (~64–249.6 MHz pulse repetition) used by IEEE 802.15.4z secure ranging β€” the mode {{#u1-chip|Apple U1}} / U2 chips actually run. Distinguished from LRP (Low Rate Pulse) which optimises for power, not ranging accuracy.", + 'The high-pulse-rate UWB mode (~64–249.6 MHz pulse repetition) used by IEEE 802.15.4z secure ranging β€” the mode {{#u1-chip|Apple U1}} / U2 chips actually run. Distinguished from LRP (Low Rate Pulse) which optimises for power, not ranging accuracy.', wikiUrl: 'https://en.wikipedia.org/wiki/Ultra-wideband', category: 'protocol-mechanics' }, @@ -7791,7 +7795,7 @@ export const concepts: Concept[] = [ id: 'bprf', term: 'BPRF (Base Pulse Repetition Frequency)', definition: - "The IEEE 802.15.4z {{uwb|UWB}} HRP mode that runs at 64 MHz pulse repetition with 499.2 MHz of bandwidth and 6.81 Mbps payload β€” the mainline mode for Apple Nearby Interaction and CCC Digital Key 3.0 ranging.", + 'The IEEE 802.15.4z {{uwb|UWB}} HRP mode that runs at 64 MHz pulse repetition with 499.2 MHz of bandwidth and 6.81 Mbps payload β€” the mainline mode for Apple Nearby Interaction and CCC Digital Key 3.0 ranging.', wikiUrl: 'https://en.wikipedia.org/wiki/IEEE_802.15.4', category: 'protocol-mechanics' }, @@ -7799,7 +7803,7 @@ export const concepts: Concept[] = [ id: 'nxp', term: 'NXP', definition: - "Dutch semiconductor company spun out of Philips in 2006 β€” the dominant supplier of NFC, MIFARE, and secure-element chips for phones, cards, and access readers.", + 'Dutch semiconductor company spun out of Philips in 2006 β€” the dominant supplier of NFC, MIFARE, and secure-element chips for phones, cards, and access readers.', wikiUrl: 'https://en.wikipedia.org/wiki/NXP_Semiconductors', category: 'infrastructure' }, @@ -7807,7 +7811,7 @@ export const concepts: Concept[] = [ id: 'qorvo', term: 'Qorvo', definition: - "US semiconductor company β€” supplies most of the {{uwb|UWB}} radios that ship in Android phones, automotive Digital Key modules, and access-control readers. Competes with NXP in the UWB/NFC space.", + 'US semiconductor company β€” supplies most of the {{uwb|UWB}} radios that ship in Android phones, automotive Digital Key modules, and access-control readers. Competes with NXP in the UWB/NFC space.', wikiUrl: 'https://en.wikipedia.org/wiki/Qorvo', category: 'infrastructure' }, @@ -7815,8 +7819,9 @@ export const concepts: Concept[] = [ id: 'crtc', term: 'CRTC', definition: - "Canadian Radio-television and Telecommunications Commission β€” the national regulator that, after the 2022 Rogers outage, codified telecom networks as critical national infrastructure and forced large carriers to expose their resilience posture.", - wikiUrl: 'https://en.wikipedia.org/wiki/Canadian_Radio-television_and_Telecommunications_Commission', + 'Canadian Radio-television and Telecommunications Commission β€” the national regulator that, after the 2022 Rogers outage, codified telecom networks as critical national infrastructure and forced large carriers to expose their resilience posture.', + wikiUrl: + 'https://en.wikipedia.org/wiki/Canadian_Radio-television_and_Telecommunications_Commission', category: 'infrastructure' }, { @@ -7849,7 +7854,7 @@ export const concepts: Concept[] = [ id: '5gc', term: '5GC (5G Core)', definition: - "The 5G replacement for the 4G [[#epc|EPC]] β€” a service-based architecture where every function (AMF, SMF, UPF, AUSF, UDM, PCF) exposes HTTP/2 + JSON APIs. Cloud-native by design, harder to operate than its EPC predecessor.", + 'The 5G replacement for the 4G [[#epc|EPC]] β€” a service-based architecture where every function (AMF, SMF, UPF, AUSF, UDM, PCF) exposes HTTP/2 + JSON APIs. Cloud-native by design, harder to operate than its EPC predecessor.', wikiUrl: 'https://en.wikipedia.org/wiki/5G_core_network', category: 'protocol-mechanics' }, @@ -7867,7 +7872,7 @@ export const concepts: Concept[] = [ id: 'rrc', term: 'RRC (Radio Resource Control)', definition: - "The cellular control-plane protocol between handset and base station β€” manages the RRC_IDLE β†’ CONNECTED β†’ INACTIVE state machine, bearer setup, paging. Distinct from {{#nas|NAS}} which signals to the core.", + 'The cellular control-plane protocol between handset and base station β€” manages the RRC_IDLE β†’ CONNECTED β†’ INACTIVE state machine, bearer setup, paging. Distinct from {{#nas|NAS}} which signals to the core.', wikiUrl: 'https://en.wikipedia.org/wiki/Radio_Resource_Control', category: 'protocol-mechanics' }, @@ -7875,10 +7880,82 @@ export const concepts: Concept[] = [ id: 'nas', term: 'NAS (Non-Access Stratum)', definition: - "The cellular signalling protocols between the handset and the core network (MME in 4G, AMF in 5G) β€” registration, authentication, mobility, session management. The control-plane layer above {{#rrc|RRC}}.", + 'The cellular signalling protocols between the handset and the core network (MME in 4G, AMF in 5G) β€” registration, authentication, mobility, session management. The control-plane layer above {{#rrc|RRC}}.', wikiUrl: 'https://en.wikipedia.org/wiki/Non-access_stratum', category: 'protocol-mechanics' }, + { + id: 'egp', + term: 'EGP (Exterior Gateway Protocol)', + definition: + 'The original protocol for exchanging routing information between autonomous systems on the early internet (RFC 904, 1984). It assumed a simple tree-shaped network with a single core and could not handle loops, so it was replaced by [[bgp|BGP]] as the internet grew into a mesh of peers.', + wikiUrl: 'https://en.wikipedia.org/wiki/Exterior_Gateway_Protocol', + category: 'infrastructure' + }, + { + id: 'congestion-collapse', + term: 'Congestion Collapse', + definition: + 'A failure mode where a network becomes so overloaded that almost no useful work gets through β€” senders keep retransmitting packets that are already queued or dropped, which adds yet more load. The internet suffered real congestion collapses in 1986; [[tcp|TCP]]’s congestion-control algorithms (slow start, congestion avoidance) were added specifically to prevent it.', + wikiUrl: 'https://en.wikipedia.org/wiki/Network_congestion#Congestive_collapse', + category: 'networking-basics' + }, + { + id: 'ossification', + term: 'Protocol Ossification', + definition: + 'The loss of flexibility that happens when middleboxes (firewalls, NATs, load balancers) inspect and depend on the exact wire format of a protocol, so any change breaks in the field. [[tcp|TCP]] is heavily ossified, which is why [[quic|QUIC]] runs over [[udp|UDP]] and encrypts almost its entire header β€” to keep middleboxes from freezing its design.', + wikiUrl: 'https://en.wikipedia.org/wiki/Protocol_ossification', + category: 'networking-basics' + }, + { + id: 'tcp-handshake', + term: 'TCP Three-Way Handshake', + definition: + 'The connection-setup exchange that opens every [[tcp|TCP]] connection: the client sends SYN, the server replies SYN-ACK, the client answers ACK. It synchronizes initial sequence numbers in both directions and costs one round trip before any data flows β€” the latency [[quic|QUIC]] and TLS 1.3 work hard to fold away.', + wikiUrl: 'https://en.wikipedia.org/wiki/Transmission_Control_Protocol#Connection_establishment', + category: 'protocol-mechanics' + }, + { + id: 'http-verbs', + term: 'HTTP Methods (Verbs)', + definition: + 'The action words at the start of every [[http1|HTTP]] request β€” GET (read), POST (create), PUT (replace), PATCH (modify), DELETE (remove), plus HEAD and OPTIONS. [[rest|REST]] APIs lean on their defined semantics (safe, idempotent) so caches and proxies can reason about a request without understanding the application.', + wikiUrl: 'https://en.wikipedia.org/wiki/HTTP#Request_methods', + category: 'web' + }, + { + id: 'comet', + term: 'Comet (HTTP long-polling)', + definition: + 'An umbrella term for the pre-[[websockets|WebSocket]] techniques that faked server push over plain [[http1|HTTP]] β€” long-polling (hold a request open until there is data) and hidden streaming iframes. Comet powered early live chat and dashboards but wasted connections and added latency, which motivated real bidirectional transports.', + wikiUrl: 'https://en.wikipedia.org/wiki/Comet_(programming)', + category: 'web' + }, + { + id: 'phishing', + term: 'Phishing', + definition: + 'A social-engineering attack that tricks a user into handing credentials to a fake site or approving a malicious request, rather than breaking the cryptography. It is the reason modern auth leans on phishing-resistant factors like WebAuthn/passkeys and hardware security keys instead of passwords and one-time codes alone.', + wikiUrl: 'https://en.wikipedia.org/wiki/Phishing', + category: 'security' + }, + { + id: 'ttls', + term: 'EAP-TTLS', + definition: + 'An 802.1X/EAP authentication method that first builds a [[tls|TLS]] tunnel to the authentication server, then carries the user’s credentials (often a legacy password protocol) safely inside it. Widely used on enterprise and campus [[wifi|Wi-Fi]] because it authenticates users without requiring a client certificate on every device.', + wikiUrl: 'https://en.wikipedia.org/wiki/Extensible_Authentication_Protocol#EAP-TTLS', + category: 'security' + }, + { + id: 'rsn', + term: 'RSN (Robust Security Network)', + definition: + 'The security framework introduced by the 802.11i amendment (the basis of WPA2) that replaced the broken WEP scheme on [[wifi|Wi-Fi]]. An RSN negotiates strong ciphers (CCMP/AES) and the 4-way handshake that derives fresh per-session keys, advertised in the RSN Information Element of management frames.', + wikiUrl: 'https://en.wikipedia.org/wiki/IEEE_802.11i-2004', + category: 'security' + } ]; export const conceptMap = new Map(concepts.map((c) => [c.id, c])); diff --git a/src/lib/data/diagram-definitions.ts b/src/lib/data/diagram-definitions.ts index eb920c7..d2e814b 100644 --- a/src/lib/data/diagram-definitions.ts +++ b/src/lib/data/diagram-definitions.ts @@ -43,21 +43,21 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { caption: '**[[tcp|TCP]]** = Transmission Control Protocol. A {{three-way-handshake|three-way handshake}} opens the connection, **`seq`**/**`ack`** numbers track every byte, and **{{fin|FIN}}** closes it cleanly β€” the foundation of reliable delivery ([[rfc:793|RFC 793]] / [[rfc:9293|RFC 9293]]).', steps: { - 0: 'Before any data flows, both sides must agree they\'re talking. The next three messages β€” {{syn|SYN}}, {{syn-ack|SYN-ACK}}, **{{ack|ACK}}** β€” establish that agreement and sync their {{sequence-number|sequence number}} counters.', + 0: "Before any data flows, both sides must agree they're talking. The next three messages β€” {{syn|SYN}}, {{syn-ack|SYN-ACK}}, **{{ack|ACK}}** β€” establish that agreement and sync their {{sequence-number|sequence number}} counters.", 1: '{{syn|SYN}} = synchronize. The client picks a random {{initial-sequence-number|initial sequence number}} (here `100`) and sends it. The *Hey, can we talk?* step.', - 2: 'Server replies with its own {{syn|SYN}} (random `seq=300`) plus **{{ack|ACK}}** of the client\'s {{syn|SYN}}. **`ack=101`** means *next byte I expect is 101*. *Yes, I hear you β€” can you hear me?*', - 3: 'Client **{{ack|ACK}}**s the server\'s {{syn|SYN}} with `ack=301`. Both sides have now seen each other\'s starting {{sequence-number|sequence numbers}} β€” the {{handshake|handshake}} is complete.', + 2: "Server replies with its own {{syn|SYN}} (random `seq=300`) plus **{{ack|ACK}}** of the client's {{syn|SYN}}. **`ack=101`** means *next byte I expect is 101*. *Yes, I hear you β€” can you hear me?*", + 3: "Client **{{ack|ACK}}**s the server's {{syn|SYN}} with `ack=301`. Both sides have now seen each other's starting {{sequence-number|sequence numbers}} β€” the {{handshake|handshake}} is complete.", 4: 'The connection is open. {{sequence-number|Sequence-number}} counters are synced on both ends, so every byte from now on can be tracked, ordered, and {{ack|acknowledged}}.', 5: 'Client sends 50 bytes of application data starting at {{sequence-number|sequence}} **`101`**. The server will track these as bytes `101–150`.', 6: 'Server replies with **`ack=151`** β€” *I have received through byte 150; send me byte 151 next.* {{ack|ACKs}} always name the next-expected byte, not the last-received.', - 7: 'Client sends another 80 bytes starting at **`151`. Notice it didn\'t wait for individual {{ack|ACKs}} β€” [[tcp|TCP]]\'s {{sliding-window|sliding window}}** lets multiple {{segment|segments}} be in flight at once.', + 7: "Client sends another 80 bytes starting at **`151`. Notice it didn't wait for individual {{ack|ACKs}} β€” [[tcp|TCP]]'s {{sliding-window|sliding window}}** lets multiple {{segment|segments}} be in flight at once.", 8: 'Server {{piggyback-ack|piggybacks}} an **{{ack|ACK}}** onto its own outgoing data β€” `ack=231` covers everything through byte 230. Combining {{ack|ACKs}} with data saves a {{rtt|round trip}}.', 9: 'The sequence/ack accounting is what makes [[tcp|TCP]] reliable. Missing {{ack|ACKs}} trigger {{retransmission|retransmission}}, and out-of-order bytes are reassembled before they reach the application.', 10: 'Either side can initiate close. The next three messages perform a graceful shutdown β€” each direction is flushed independently before the connection is torn down.', - 11: '{{tcp-fin|FIN}} = finish. The client signals *I\'m done sending*. The server can still send any remaining data on its side.', - 12: 'Server **{{ack|ACK}}**s the {{tcp-fin|FIN}} and sends its own {{tcp-fin|FIN}} β€” *I\'m done too*. These are often combined into a single {{segment|segment}}.', - 13: 'Client **{{ack|ACK}}**s the server\'s {{tcp-fin|FIN}}. Both directions are now closed; no more application data can flow on this connection.', - 14: 'Client lingers in **{{time-wait|`TIME_WAIT`}}** for ~60 seconds before releasing the {{socket|socket}}. This catches late-arriving {{packet|packets}} so they don\'t pollute a fresh connection on the same {{port|port}} pair.' + 11: "{{tcp-fin|FIN}} = finish. The client signals *I'm done sending*. The server can still send any remaining data on its side.", + 12: "Server **{{ack|ACK}}**s the {{tcp-fin|FIN}} and sends its own {{tcp-fin|FIN}} β€” *I'm done too*. These are often combined into a single {{segment|segment}}.", + 13: "Client **{{ack|ACK}}**s the server's {{tcp-fin|FIN}}. Both directions are now closed; no more application data can flow on this connection.", + 14: "Client lingers in **{{time-wait|`TIME_WAIT`}}** for ~60 seconds before releasing the {{socket|socket}}. This catches late-arriving {{packet|packets}} so they don't pollute a fresh connection on the same {{port|port}} pair." } }, @@ -76,8 +76,8 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { caption: '**[[udp|UDP]]** = User Datagram Protocol. {{fire-and-forget|Fire-and-forget}} delivery β€” minimal 8-byte header, no {{handshake|handshake}}, no retransmits. The application is responsible for any reliability it needs ([[rfc:768|RFC 768]]).', steps: { - 0: 'No setup. The very first {{packet|packet}} carries data β€” there\'s no {{syn|SYN}}/{{ack|ACK}} ceremony. This is what makes [[udp|UDP]] fast for [[dns|DNS]] lookups, voice, video, and gaming.', - 4: '{{datagram|Datagram}} 4 is dropped in transit. [[udp|UDP]] doesn\'t notice and doesn\'t care β€” there\'s no {{retransmission|retransmission}} machinery.', + 0: "No setup. The very first {{packet|packet}} carries data β€” there's no {{syn|SYN}}/{{ack|ACK}} ceremony. This is what makes [[udp|UDP]] fast for [[dns|DNS]] lookups, voice, video, and gaming.", + 4: "{{datagram|Datagram}} 4 is dropped in transit. [[udp|UDP]] doesn't notice and doesn't care β€” there's no {{retransmission|retransmission}} machinery.", 6: 'Receiver gets `1, 2, 3, 5` β€” *out of order possible* and one missing. [[udp|UDP]] delivers what arrives and leaves the rest to the application.', 7: 'No reliability features at all: no {{ack|ACKs}}, no {{sequence-number|sequence numbers}}, no {{flow-control|flow control}}, no {{congestion-control|congestion control}}. The {{header|header}} is just src/dst {{port|port}}, length, {{checksum|checksum}} β€” a total of `8 bytes`.' } @@ -102,12 +102,12 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { '**[[quic|QUIC]]** = Quick [[udp|UDP]] Internet Connections. Transport + {{encryption|encryption}} fused into one {{handshake|handshake}}. Independent **streams** mean a lost packet only blocks its own stream, not the whole connection ([[rfc:9000|RFC 9000]]).', steps: { 0: 'Where [[tcp|TCP]] needs a separate {{tls-handshake|TLS handshake}} on top, [[quic|QUIC]] merges them β€” connection setup and {{encryption|encryption}} happen in the same exchange, halving the {{rtt|round trips}}.', - 1: 'Client\'s first flight carries the [[tls|TLS]] {{client-hello|ClientHello}} plus [[quic|QUIC]] connection setup. Already includes its {{key-share|key share}} for the {{handshake|handshake}}.', + 1: "Client's first flight carries the [[tls|TLS]] {{client-hello|ClientHello}} plus [[quic|QUIC]] connection setup. Already includes its {{key-share|key share}} for the {{handshake|handshake}}.", 2: 'Server replies with **{{server-hello|ServerHello}}** + {{key-share|key share}} in the same {{initial-packet|Initial packet}}. After this exchange, both sides have shared keys.', 3: 'Server sends its **{{certificate|Certificate}}** and a {{tls-finished|`Finished`}} message β€” already {{encryption|encrypted}} with the new keys.', 4: 'Client confirms it received and verified everything. {{one-rtt|One round trip}} total β€” application data can now flow.', 7: 'A {{packet|packet}} on {{stream|Stream}} 1 is lost. In [[tcp|TCP]] this would block *every* stream behind it β€” **{{head-of-line-blocking|head-of-line blocking}}** at the transport layer.', - 8: '{{stream|Stream}} 2\'s data delivers immediately. [[quic|QUIC]] {{stream-independence|streams are independent}} β€” Stream 1\'s loss doesn\'t pause Stream 2 while waiting for {{retransmission|retransmission}}.', + 8: "{{stream|Stream}} 2's data delivers immediately. [[quic|QUIC]] {{stream-independence|streams are independent}} β€” Stream 1's loss doesn't pause Stream 2 while waiting for {{retransmission|retransmission}}.", 9: 'Returning clients can send data in their first {{packet|packet}} using cached {{session-resumption|session keys}} β€” **{{zero-rtt|0-RTT}}**. Trades a small {{replay-attack|replay-attack}} risk for a faster connection.' } }, @@ -130,13 +130,13 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { caption: '**[[sctp|SCTP]]** = Stream Control Transmission Protocol. [[tcp|TCP]]-like reliability with two superpowers: multiple **independent streams** in one association (no {{head-of-line-blocking|head-of-line blocking}}) and **{{multi-homing|multi-homing}}** for [[ip|IP]]-level {{failover|failover}}. Used as the transport under telecom {{signaling|signaling}} (SIGTRAN) and [[webrtc|WebRTC]] data channels ([[rfc:4960|RFC 4960]] / 9260).', steps: { - 0: 'Unlike [[tcp|TCP]]\'s {{three-way-handshake|three-way}}, [[sctp|SCTP]] uses {{four-way-handshake|four messages}} β€” the extra {{rtt|round trip}} lets the server hand out a {{cookie|cookie}} *before* committing any state, defeating {{syn-flood|SYN-flood}} attacks.', - 1: '{{init-chunk|INIT}} opens the {{sctp-association|association}}. Includes the client\'s address list ({{multi-homing|multi-homing}}) and a {{verification-tag|verification tag}}.', + 0: "Unlike [[tcp|TCP]]'s {{three-way-handshake|three-way}}, [[sctp|SCTP]] uses {{four-way-handshake|four messages}} β€” the extra {{rtt|round trip}} lets the server hand out a {{cookie|cookie}} *before* committing any state, defeating {{syn-flood|SYN-flood}} attacks.", + 1: "{{init-chunk|INIT}} opens the {{sctp-association|association}}. Includes the client's address list ({{multi-homing|multi-homing}}) and a {{verification-tag|verification tag}}.", 2: 'Server replies with {{init-ack-chunk|INIT-ACK}} carrying a {{stateless|stateless}} **{{cookie|cookie}}** β€” a signed token. The server keeps no state yet.', - 3: 'Client echoes the {{cookie|cookie}} back ({{cookie-echo|COOKIE-ECHO}}). Only now does the server allocate resources β€” anyone forging an {{init-chunk|INIT}} couldn\'t fake the {{cookie|cookie}}.', + 3: "Client echoes the {{cookie|cookie}} back ({{cookie-echo|COOKIE-ECHO}}). Only now does the server allocate resources β€” anyone forging an {{init-chunk|INIT}} couldn't fake the {{cookie|cookie}}.", 4: 'Server confirms with {{cookie-ack|COOKIE-ACK}}. {{sctp-association|Association}} established, immune to {{syn-flood|SYN-flood}} DoS.', 7: 'A {{packet|packet}} on {{stream|Stream}} 2 is lost. [[sctp|SCTP]] {{retransmission|retransmits}} it β€” but only Stream 2 is affected.', - 8: '{{stream|Stream}} 3\'s voice traffic flows immediately, untouched by Stream 2\'s recovery. Each {{stream|stream}} has its own ordering β€” same insight [[quic|QUIC]] later adopted.', + 8: "{{stream|Stream}} 3's voice traffic flows immediately, untouched by Stream 2's recovery. Each {{stream|stream}} has its own ordering β€” same insight [[quic|QUIC]] later adopted.", 9: '**{{multi-homing|Multi-homing}}**: the same {{sctp-association|association}} can use multiple network paths. If one [[ip|IP]] fails, traffic reroutes through another without breaking the connection.' } }, @@ -170,8 +170,8 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { 6: '**{{mp-join|`MP_JOIN`}} opens a second {{subflow|subflow}} on the cellular interface. Carries a token (proves it belongs to the existing connection) and a {{nonce|nonce}}** ({{replay-attack|replay protection}}).', 7: 'Server proves it knows `key_A` by sending an **{{hmac|HMAC}}**. Cryptographic binding stops attackers from sneaking in a fake {{subflow|subflow}}.', 8: 'Client returns its own {{hmac|HMAC}}. {{subflow|Subflow}} authenticated.', - 12: 'WiFi disconnects (e.g., walking out of a cafΓ©). The [[mptcp|MPTCP]] layer notices and {{failover|shifts all traffic to cellular}} β€” the app\'s [[tcp|TCP]] {{socket|socket}} never breaks.', - 13: 'Data continues over cellular alone. From the application\'s view it\'s the same connection β€” the most powerful feature of [[mptcp|MPTCP]].' + 12: "WiFi disconnects (e.g., walking out of a cafΓ©). The [[mptcp|MPTCP]] layer notices and {{failover|shifts all traffic to cellular}} β€” the app's [[tcp|TCP]] {{socket|socket}} never breaks.", + 13: "Data continues over cellular alone. From the application's view it's the same connection β€” the most powerful feature of [[mptcp|MPTCP]]." } }, @@ -197,11 +197,11 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { 0: '**`GET`** = the request {{http-method|method}} for *fetching* a resource. Safe (no server-side side effects) and **{{idempotent|idempotent}}** (calling twice = calling once), so responses are freely cacheable. The other common methods: **`POST` (create), `PUT` (replace), `PATCH` (partial update), `DELETE` (remove), `HEAD` (GET without body β€” just headers), `OPTIONS`** (capabilities probe, used in {{cors|CORS}}).', 1: '**`200 OK` = success with body. [[http1|HTTP]] {{status-code|status codes}} are 3-digit, grouped by hundreds: `1xx`** informational (`100 Continue`), **`2xx`** success (`201 Created`, `204 No Content`), **`3xx`** redirect (`301` permanent, `302` temporary, `304 Not Modified`), **`4xx`** client error (`400 Bad Request`, `401 Unauthorized`, `403 Forbidden`, `404 Not Found`, `429 Too Many Requests`), **`5xx`** server error (`500 Internal`, `502 Bad Gateway`, `503 Unavailable`, `504 Gateway Timeout`).', 2: 'Browser scans the HTML and finds **`<link rel="stylesheet">` (CSS), `<script src="...">` (JS), and `<img src="...">` tags pointing to other URLs. Each becomes a fresh request β€” and HTML parsing pauses for blocking scripts** until they download and execute.', - 3: 'Same [[tcp|TCP]] connection. [[http1|HTTP/1.1]]\'s **`Connection: {{keep-alive|keep-alive}}` (the default since 1999) reuses the connection for all requests to the same host, saving the [[tcp|TCP]] + {{tls-handshake|TLS handshake}}** on every fetch. Without keep-alive, each resource would need a brand-new connection.', + 3: "Same [[tcp|TCP]] connection. [[http1|HTTP/1.1]]'s **`Connection: {{keep-alive|keep-alive}}` (the default since 1999) reuses the connection for all requests to the same host, saving the [[tcp|TCP]] + {{tls-handshake|TLS handshake}}** on every fetch. Without keep-alive, each resource would need a brand-new connection.", 4: 'Response carries {{header|headers}} like **`{{content-type|Content-Type}}: text/css` (so the browser interprets it correctly) and `{{cache-control|Cache-Control}}: max-age=31536000, immutable`** (reuse from cache for a year, never re-validate). Caching is *the* [[http1|HTTP]] performance superpower.', - 5: 'Third sequential request on this connection. Even though the browser knew it needed all three resources as soon as the HTML was parsed, [[http1|HTTP/1.1]] can\'t send them in parallel on one connection. To work around this, browsers open up to 6 concurrent connections per origin β€” and *{{domain-sharding|domain sharding}}* (serving assets from `static1.example.com`, `static2.example.com`...) was a common 2010s trick.', + 5: "Third sequential request on this connection. Even though the browser knew it needed all three resources as soon as the HTML was parsed, [[http1|HTTP/1.1]] can't send them in parallel on one connection. To work around this, browsers open up to 6 concurrent connections per origin β€” and *{{domain-sharding|domain sharding}}* (serving assets from `static1.example.com`, `static2.example.com`...) was a common 2010s trick.", 6: 'JS arrives. Conditional requests via **`If-None-Match` + `{{etag|ETag}}` (or `If-Modified-Since` + `Last-Modified`) let the server reply `304 Not Modified` with no body when nothing changed β€” saves bandwidth on repeat visits. {{content-encoding|Compression}}** via `Content-Encoding: gzip` or `br` (Brotli) shrinks the payload further.', - 7: 'Each request must wait for the previous response β€” **{{head-of-line-blocking|head-of-line blocking}}** at the application layer. The 6-connection workaround helps but doesn\'t scale. **[[http2|HTTP/2]]** fixed this by {{multiplexing|multiplexing}} all requests as numbered streams over a single [[tcp|TCP]] connection.' + 7: "Each request must wait for the previous response β€” **{{head-of-line-blocking|head-of-line blocking}}** at the application layer. The 6-connection workaround helps but doesn't scale. **[[http2|HTTP/2]]** fixed this by {{multiplexing|multiplexing}} all requests as numbered streams over a single [[tcp|TCP]] connection." } }, @@ -228,7 +228,7 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { steps: { 0: '**{{alpn|ALPN}}** = Application-Layer Protocol Negotiation. Inside the {{tls-handshake|TLS handshake}}, the client lists protocols it supports and the server picks one. **`h2`** = [[http2|HTTP/2]].', 3: 'All three {{http-method|GETs}} go out in parallel as separate {{http2-stream|streams}} (odd-numbered streams are client-initiated). No waiting for the first response. Each [[http2|HTTP/2]] message is carried in {{http2-frame|frames}} like **`HEADERS`** (request/response {{header|headers}}) and **`DATA`** (body).', - 9: '**{{hpack|HPACK}}** compresses repeated {{header|headers}} (common ones become 1-byte indices). **{{server-push|Server push}}** lets the server send resources the client hasn\'t asked for yet β€” deprecated in practice.' + 9: "**{{hpack|HPACK}}** compresses repeated {{header|headers}} (common ones become 1-byte indices). **{{server-push|Server push}}** lets the server send resources the client hasn't asked for yet β€” deprecated in practice." } }, @@ -253,10 +253,10 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { caption: '**[[http3|HTTP/3]]** = {{http-method|HTTP}} over **[[quic|QUIC]]** (which runs on [[udp|UDP]]). Same {{multiplexing|multiplexing}} as [[http2|HTTP/2]], but streams are independent at the *transport* layer too β€” a lost packet on one stream cannot block others ([[rfc:9114|RFC 9114]]).', steps: { - 0: '**`h3`** = [[http3|HTTP/3]] identifier negotiated via {{alpn|ALPN}} inside [[quic|QUIC]]\'s combined {{tls-handshake|TLS handshake}}. [[http3|HTTP/3]] uses {{qpack|QPACK}} instead of {{hpack|HPACK}} for {{header|header}} compression β€” redesigned so streams arriving out of order don\'t stall decoding.', - 1: '[[quic|QUIC]]\'s {{handshake|handshake}} setup + crypto in one {{rtt|round trip}}. Returning clients can do **{{zero-rtt|0-RTT}}**.', - 7: '{{stream|Stream}} 2 loses a {{packet|packet}}. [[http2|HTTP/2]] over [[tcp|TCP]] would block all streams here β€” [[tcp|TCP]]\'s ordered-byte abstraction means stream 1 and 3 wait too.', - 8: 'But [[http3|HTTP/3]]\'s streams are independent at the [[quic|QUIC]] layer, so {{stream|Stream}} 3 delivers immediately. {{stream|Stream}} 2 {{retransmission|retransmits}} in the background. The headline win over [[http2|HTTP/2]].' + 0: "**`h3`** = [[http3|HTTP/3]] identifier negotiated via {{alpn|ALPN}} inside [[quic|QUIC]]'s combined {{tls-handshake|TLS handshake}}. [[http3|HTTP/3]] uses {{qpack|QPACK}} instead of {{hpack|HPACK}} for {{header|header}} compression β€” redesigned so streams arriving out of order don't stall decoding.", + 1: "[[quic|QUIC]]'s {{handshake|handshake}} setup + crypto in one {{rtt|round trip}}. Returning clients can do **{{zero-rtt|0-RTT}}**.", + 7: "{{stream|Stream}} 2 loses a {{packet|packet}}. [[http2|HTTP/2]] over [[tcp|TCP]] would block all streams here β€” [[tcp|TCP]]'s ordered-byte abstraction means stream 1 and 3 wait too.", + 8: "But [[http3|HTTP/3]]'s streams are independent at the [[quic|QUIC]] layer, so {{stream|Stream}} 3 delivers immediately. {{stream|Stream}} 2 {{retransmission|retransmits}} in the background. The headline win over [[http2|HTTP/2]]." } }, @@ -298,10 +298,10 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { S->>C: Bidirectional stream Note over C,S: Code generated from .proto service definitions`, caption: - '**[[grpc|gRPC]]** = {{google|Google}}\'s high-performance **{{rpc|RPC}}** framework (2015). Methods defined in `.proto` files become typed client and server stubs in 11+ languages; messages travel as compact **Protobuf** {{binary-framing|binary}} over [[http2|HTTP/2]] with {{hpack|HPACK}}-compressed headers and [[tls|TLS]] by default. Four call patterns: unary {{request-response|request-response}}, server-stream, client-stream, bidirectional-stream.', + "**[[grpc|gRPC]]** = {{google|Google}}'s high-performance **{{rpc|RPC}}** framework (2015). Methods defined in `.proto` files become typed client and server stubs in 11+ languages; messages travel as compact **Protobuf** {{binary-framing|binary}} over [[http2|HTTP/2]] with {{hpack|HPACK}}-compressed headers and [[tls|TLS]] by default. Four call patterns: unary {{request-response|request-response}}, server-stream, client-stream, bidirectional-stream.", steps: { 0: '**{{rpc|RPC}}** = Remote Procedure Call. Looks like a function call but actually crosses the network. The strong typing comes from the **`.proto`** schema both sides share.', - 1: 'Method invocation. Note this isn\'t {{json|JSON}} β€” **{{protocol-buffers|Protobuf}}** {{serialization|serializes}} the call by field-number, omitting names and types from the wire format.', + 1: "Method invocation. Note this isn't {{json|JSON}} β€” **{{protocol-buffers|Protobuf}}** {{serialization|serializes}} the call by field-number, omitting names and types from the wire format.", 3: '[[grpc|gRPC]] has four call shapes: unary (oneβ†’one), client streaming (manyβ†’one), server streaming (oneβ†’many), and bidirectional (many↔many) β€” all on a single [[http2|HTTP/2]] connection.', 8: 'Run **{{protoc|`protoc`}}** against your `.proto` file and you get type-safe client + server code in C++, Go, Java, Python, Rust, etc. The schema is the source of truth.' } @@ -373,11 +373,11 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { '**[[json-rpc|JSON-RPC]]** = a tiny {{rpc|RPC}} protocol where every message is a {{json|JSON}} object. Calls have an `id` and get a result; notifications omit `id` and get nothing back. Used by Bitcoin, Ethereum, [[mcp|MCP]], and the {{lsp|Language Server Protocol}} (jsonrpc.org 2.0).', steps: { 0: 'A call: includes `method` name, `params` array or object, and an `id`. The id pairs the eventual response with this request.', - 1: 'Response with the matching `id` and a `result` field. Calls and responses don\'t have to arrive in order β€” the id is what matches them.', + 1: "Response with the matching `id` and a `result` field. Calls and responses don't have to arrive in order β€” the id is what matches them.", 2: 'A **{{notification|notification}}**: no `id`, so no response will come back. Used for fire-and-forget events (logging, telemetry).', 5: 'Multiple calls can be sent as a {{json|JSON}} array β€” saves {{rtt|round trips}}. Mix of calls and {{notification|notifications}} is fine.', - 6: 'Server returns an array of responses (skipping {{notification|notifications}}). Order isn\'t guaranteed β€” match by `id`.', - 7: '[[json-rpc|JSON-RPC]] is just a message format β€” it doesn\'t care how the bytes get there. Common transports: [[http1|HTTP]] `POST`, {{websocket-frame|WebSocket frames}}, {{stdio|stdio}} (used by [[mcp|MCP]] and {{lsp|LSP}}), raw [[tcp|TCP]].', + 6: "Server returns an array of responses (skipping {{notification|notifications}}). Order isn't guaranteed β€” match by `id`.", + 7: "[[json-rpc|JSON-RPC]] is just a message format β€” it doesn't care how the bytes get there. Common transports: [[http1|HTTP]] `POST`, {{websocket-frame|WebSocket frames}}, {{stdio|stdio}} (used by [[mcp|MCP]] and {{lsp|LSP}}), raw [[tcp|TCP]].", 9: 'Errors return a structured `error` object with a numeric code (here **`-32601`** = method not found). Code ranges are reserved by the spec.' } }, @@ -406,11 +406,11 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { 1: '{{mcp-host|Host}} opens with **`initialize`** β€” sends its protocol version, capabilities (e.g., supports streaming?), and basic info about itself.', 2: 'Server replies with its capabilities (which categories of {{mcp-tool|tools}}/{{mcp-resource|resources}} it provides) and version {{handshake|negotiation}}.', 3: '**`{{notification|notifications}}/initialized`** confirms the {{mcp-host|host}} is ready. Note the `notifications/` prefix β€” no `id`, no response expected.', - 4: 'Now the {{mcp-host|host}} learns what\'s available. The server doesn\'t send everything upfront β€” the host queries lazily.', + 4: "Now the {{mcp-host|host}} learns what's available. The server doesn't send everything upfront β€” the host queries lazily.", 5: '**`tools/list`** asks for callable {{mcp-tool|tools}}. Each tool has a name, description, and a {{json-schema|JSON Schema}} for its inputs (so the LLM knows how to call it).', 7: '**`resources/list`** asks for readable data sources. {{mcp-resource|Resources}} are addressed by URI β€” files, database records, API endpoints β€” and can be subscribed to for change {{notification|notifications}}.', 10: '**`tools/call`** is the actual invocation. The LLM (via the {{mcp-host|host}}) chose to call `weather` with `{city: "NYC"}` β€” the server runs whatever code is behind it.', - 11: 'Result comes back as a content array (text, images, embedded {{mcp-resource|resources}}). The {{mcp-host|host}} feeds this into the LLM\'s next turn.' + 11: "Result comes back as a content array (text, images, embedded {{mcp-resource|resources}}). The {{mcp-host|host}} feeds this into the LLM's next turn." } }, @@ -435,14 +435,14 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { '**[[a2a|A2A]]** = Agent-to-Agent. The standard for one {{ai|AI}} agent to **discover** and **delegate work** to another over [[http1|HTTP]]. Built on [[json-rpc|JSON-RPC]] 2.0 with optional [[sse|Server-Sent Events]] streams. Tasks have an explicit lifecycle (`submitted` β†’ `working` β†’ `completed`/`failed`), and agents {{mqtt-publish|publish}} their skills in a public {{agent-card|Agent Card}} at `/.well-known/agent.{{json|json}}` (a2a-protocol.org).', steps: { 1: 'Discovery is just a **{{well-known-uri|well-known URL}}** β€” `/.well-known/agent.json`. Anyone can fetch it without authentication to learn what an agent does.', - 2: 'The **{{agent-card|Agent Card}}** is the agent\'s public profile: name, what it can do (skills), what it accepts (input schemas, often {{json-schema|JSON Schema}}), how to authenticate, and the API endpoint.', + 2: "The **{{agent-card|Agent Card}}** is the agent's public profile: name, what it can do (skills), what it accepts (input schemas, often {{json-schema|JSON Schema}}), how to authenticate, and the API endpoint.", 4: 'Client agent sends a **`message/send`** β€” natural-language task plus structured params. The remote agent decides how to break it down.', 5: '**{{task-lifecycle-a2a|Tasks}}** have an explicit state machine: `submitted` β†’ `working` β†’ (`input-required` or `completed` or `failed`).', 6: 'Agent reports progress while working. The client can poll, subscribe via [[sse|SSE]], or simply wait.', 7: '**`completed` state carries artifacts** β€” the actual deliverables (text, files, structured data). Tasks can produce multiple artifacts.', 9: 'Same `message/send` semantics, but the client opens an **[[sse|SSE]]** stream to receive real-time updates instead of polling.', 10: '**`TaskStatusUpdate`** events stream the {{task-lifecycle-a2a|state transitions}} and intermediate messages.', - 11: '**`TaskArtifactUpdate`** events stream artifacts as they\'re produced β€” useful for long-running jobs.' + 11: "**`TaskArtifactUpdate`** events stream artifacts as they're produced β€” useful for long-running jobs." } }, @@ -467,7 +467,7 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { 2: '**`POST` = create. Not {{idempotent|idempotent}} β€” calling twice creates two resources. Returns `201 Created`** with a `Location` {{header|header}} pointing to the new URL.', 4: '**`PUT`** = replace. {{idempotent|Idempotent}}: PUTting the same body twice has the same effect as once. Sends the *full* representation; **`PATCH`** is the partial-update cousin.', 6: '**`DELETE`** = remove. {{idempotent|Idempotent}} β€” once gone, repeated deletes still return success.', - 7: '**`204 No Content`** is the conventional success {{status-code|status code}} when there\'s nothing meaningful to return β€” typical for `DELETE` and `PUT`.', + 7: "**`204 No Content`** is the conventional success {{status-code|status code}} when there's nothing meaningful to return β€” typical for `DELETE` and `PUT`.", 8: '**{{stateless|Stateless}}** means every request carries everything the server needs β€” auth tokens, {{cookie|cookies}}, query params. Lets any server in a {{load-balancing|load-balancer}} pool handle any request.' } }, @@ -520,10 +520,10 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { caption: '**[[amqp|AMQP]]** = Advanced Message Queuing Protocol. Producers send to an **{{exchange|exchange}}**, which uses **binding rules** to route into named **queues**. Consumers acknowledge each message β€” failures can be redirected to a {{dead-letter-queue|dead-letter queue}} ([[amqp|AMQP]] 0-9-1).', steps: { - 0: 'Publisher targets an **{{exchange|exchange}}** with a **{{routing-key|routing key}}** (here `order.new`). Unlike [[mqtt|MQTT]], producers don\'t pick the queue β€” the {{exchange|exchange}} decides.', + 0: "Publisher targets an **{{exchange|exchange}}** with a **{{routing-key|routing key}}** (here `order.new`). Unlike [[mqtt|MQTT]], producers don't pick the queue β€” the {{exchange|exchange}} decides.", 1: '{{exchange|Exchange}} types: {{direct-exchange|direct}} (exact key match), **{{topic-exchange|topic}}** (wildcard match), {{fanout-exchange|fanout}} ({{broadcast|broadcast}} to all bound queues), {{headers-exchange|headers}} (match on header dict). Picking the right type is the design choice.', 4: '**{{ack|ACK}}** tells the {{broker|broker}} *I have safely processed this; you can drop it from the queue.* Until {{ack|ACK}}, the {{broker|broker}} keeps the message and may {{retransmission|redeliver}}.', - 7: '**{{nack|NACK}}** = negative acknowledgement. The consumer couldn\'t process this message β€” {{broker|broker}} treats it as failed.', + 7: "**{{nack|NACK}}** = negative acknowledgement. The consumer couldn't process this message β€” {{broker|broker}} treats it as failed.", 8: 'Failed messages can be routed to a {{dead-letter-queue|dead-letter exchange}} for inspection or retry. Critical pattern for production reliability.', 9: '{{durable-queue|Durable queues}} + persistent messages survive a {{broker|broker}} crash. Trades throughput for safety; usually worth it.' } @@ -546,10 +546,10 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { '**[[stomp|STOMP]]** = Simple Text Oriented Messaging Protocol. Plain-text frames you can type by hand β€” `COMMAND` + headers + body + `\\0` β€” modeled on [[http1|HTTP]]. Built into many message {{broker|brokers}} (RabbitMQ, ActiveMQ) as a friendlier alternative to [[amqp|AMQP]] and a wire format for browser-side messaging libraries via [[websockets|WebSockets]].', steps: { 0: '**`CONNECT`** opens the session. Like an [[http1|HTTP]] {{handshake|handshake}} but the body is a {{stomp-frame|STOMP frame}}, and headers carry credentials.', - 2: '**`SUBSCRIBE`** registers interest in a destination (queue or {{topic|topic}}). The `id` is the client\'s local handle for this subscription.', + 2: "**`SUBSCRIBE`** registers interest in a destination (queue or {{topic|topic}}). The `id` is the client's local handle for this subscription.", 3: '**`RECEIPT`** is the optional {{ack|acknowledgement}} of any {{stomp-frame|frame}} the client asked the server to confirm β€” gives {{at-least-once-delivery|at-least-once}} semantics over [[stomp|STOMP]] itself.', 5: '**`MESSAGE`** is the server delivering content to a subscriber. Subscription id matches what the client gave in `SUBSCRIBE`.', - 8: 'Each {{stomp-frame|frame}} is {{plaintext|plaintext}}, line-delimited, terminated by a `\\0` (null) byte. You can debug it with `telnet`. That readability is [[stomp|STOMP]]\'s whole pitch.' + 8: "Each {{stomp-frame|frame}} is {{plaintext|plaintext}}, line-delimited, terminated by a `\\0` (null) byte. You can debug it with `telnet`. That readability is [[stomp|STOMP]]'s whole pitch." } }, @@ -567,11 +567,11 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { S->>C: 2.05 Content: 24.8C (observe seq 3) Note over C,S: No polling β€” server notifies on change`, caption: - '**[[coap|CoAP]]** = Constrained Application Protocol. {{http-method|HTTP}}\'s design, shrunk for tiny IoT devices: 4-byte header, runs over **[[udp|UDP]]**, optional reliability per message. Same [[rest|REST]] verbs and status codes ([[rfc:7252|RFC 7252]]).', + "**[[coap|CoAP]]** = Constrained Application Protocol. {{http-method|HTTP}}'s design, shrunk for tiny IoT devices: 4-byte header, runs over **[[udp|UDP]]**, optional reliability per message. Same [[rest|REST]] verbs and status codes ([[rfc:7252|RFC 7252]]).", steps: { 0: '**`CON` = {{coap-confirmable|Confirmable}}.** The request asks for an explicit **{{ack|ACK}}** back. The cheap counterpart is **{{coap-confirmable|`NON`}}** (non-confirmable, fire-and-forget).', - 1: '[[http1|HTTP]]\'s {{header|headers}} can run hundreds of bytes; [[coap|CoAP]] packs everything into 4 bytes plus compact options. Critical for battery-powered radios.', - 2: '**`2.05 Content`** is [[coap|CoAP]]\'s `200 OK` ({{status-code|codes}} are class.detail format, e.g. `4.04` = Not Found).', + 1: "[[http1|HTTP]]'s {{header|headers}} can run hundreds of bytes; [[coap|CoAP]] packs everything into 4 bytes plus compact options. Critical for battery-powered radios.", + 2: "**`2.05 Content`** is [[coap|CoAP]]'s `200 OK` ({{status-code|codes}} are class.detail format, e.g. `4.04` = Not Found).", 4: '**{{coap-observe|Observe}}** registers the client as interested in changes to this resource β€” the request stays open conceptually.', 5: 'Server pushes a new representation whenever the value changes, with an incrementing {{coap-observe|observe}} {{sequence-number|sequence number}}. Detect lost {{notification|notifications}} by gaps in the sequence.', 8: 'Polling burns radio time and battery. **{{coap-observe|Observe}}** lets devices sleep until the server has something new to say.' @@ -599,12 +599,12 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { caption: '**[[xmpp|XMPP]]** = Extensible Messaging and Presence Protocol. Originally **Jabber** (1999). An open {{xmpp-stream|XML stream}} over [[tcp|TCP]] with **federated** routing β€” different domains relay to each other like email. Hardened over the decades into the substrate of {{google|Google}} Talk, the original WhatsApp, and the {{matter|Matter}}-adjacent OMA-LwM2M IoT stack. Encrypted via {{starttls|STARTTLS}}; modern {{encryption|end-to-end}} uses {{omemo|OMEMO}} ([[rfc:6120|RFC 6120]]).', steps: { - 0: 'Client opens a [[tcp|TCP]] {{socket|socket}} and sends `<stream:stream>` β€” an {{xml|XML}} element that won\'t be closed until the session ends. The whole conversation is one continuous {{xmpp-stream|XML stream}}.', - 1: 'Server replies with **`<stream:features>`** advertising what\'s available β€” [[tls|TLS]], {{sasl|SASL}} mechanisms, optional extensions.', + 0: "Client opens a [[tcp|TCP]] {{socket|socket}} and sends `<stream:stream>` β€” an {{xml|XML}} element that won't be closed until the session ends. The whole conversation is one continuous {{xmpp-stream|XML stream}}.", + 1: "Server replies with **`<stream:features>`** advertising what's available β€” [[tls|TLS]], {{sasl|SASL}} mechanisms, optional extensions.", 2: '**{{starttls|`STARTTLS`}}** upgrades the {{plaintext|plaintext}} stream to [[tls|TLS]]. After this, the {{xmpp-stream|XML stream}} restarts inside the encrypted {{tunnel|tunnel}}.', 3: '**{{sasl|SASL}}** = Simple Authentication and Security Layer. **{{scram|SCRAM}}** lets the server store hashed passwords (not {{plaintext|plaintext}}) while still proving knowledge β€” modern best practice.', - 5: '**{{xmpp-resource|Resource binding}}** = the user\'s address gets a per-device suffix (`alice@example.com/phone` vs `/laptop`). Lets messages route to the right device.', - 7: '**{{xmpp-presence|`<presence/>`}}** = *I\'m online and available*. Other contacts subscribed to your {{xmpp-presence|presence}} get {{notification|notified}} β€” the basis for buddy lists.', + 5: "**{{xmpp-resource|Resource binding}}** = the user's address gets a per-device suffix (`alice@example.com/phone` vs `/laptop`). Lets messages route to the right device.", + 7: "**{{xmpp-presence|`<presence/>`}}** = *I'm online and available*. Other contacts subscribed to your {{xmpp-presence|presence}} get {{notification|notified}} β€” the basis for buddy lists.", 9: 'If `bob@serverb.com` is on a different server, this server connects to {{port|port}} 5269 ({{federation|server-to-server}}) and relays the message β€” same as [[smtp|SMTP]] relay between {{mta|mail servers}}.' } }, @@ -663,10 +663,10 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { caption: '**[[webrtc|WebRTC]]** = real-time video, audio, and data **directly between browsers**. The server only helps peers find each other ({{signaling|signaling}}) β€” once connected, **media flows {{peer-to-peer|peer-to-peer}}** with no hop through your servers ({{w3c|W3C}} / {{ietf|IETF}}).', steps: { - 0: '**[[sdp|SDP]]** = Session Description Protocol. Peer A\'s offer lists the {{codec|codecs}} it supports, {{port|ports}}, {{encryption|encryption}} keys, and {{ice-candidate|ICE candidates}}.', - 1: 'Browsers can\'t talk directly until they know each other\'s addresses. Your {{signaling|signaling}} server (any transport β€” [[websockets|WebSocket]] is typical) just forwards messages between them.', + 0: "**[[sdp|SDP]]** = Session Description Protocol. Peer A's offer lists the {{codec|codecs}} it supports, {{port|ports}}, {{encryption|encryption}} keys, and {{ice-candidate|ICE candidates}}.", + 1: "Browsers can't talk directly until they know each other's addresses. Your {{signaling|signaling}} server (any transport β€” [[websockets|WebSocket]] is typical) just forwards messages between them.", 2: 'Peer B picks {{codec|codecs}} both sides support and replies with its own [[sdp|SDP]].', - 4: '**{{ice|ICE}}** = Interactive Connectivity Establishment. Each peer asks a **{{stun|STUN}}** server *what\'s my {{public-ip-address|public IP}} and {{port|port}}?* β€” needed to traverse home-router {{nat|NAT}}.', + 4: "**{{ice|ICE}}** = Interactive Connectivity Establishment. Each peer asks a **{{stun|STUN}}** server *what's my {{public-ip-address|public IP}} and {{port|port}}?* β€” needed to traverse home-router {{nat|NAT}}.", 5: 'Each {{ice-candidate|candidate}} is a possible address pair (host, server-reflexive, or {{turn|relayed}}). Both peers exchange them and try every combination, picking the one that works.', 7: 'Once a {{ice-candidate|candidate}} pair succeeds, the connection is direct between the browsers β€” no media touches the server.', 8: '**{{srtp|SRTP}}** = Secure [[rtp|RTP]]. Audio and video frames flow with {{encryption|end-to-end encryption}}. Whether the server is online or not no longer matters.' @@ -720,11 +720,11 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { caption: '**[[sip|SIP]]** = Session Initiation Protocol. The {{signaling|signaling}} that sets up {{voip|VoIP}} calls β€” sounds like {{http-method|HTTP}}, looks like email addresses (`sip:bob@example.com`). Once a call is established, the actual audio/video flows separately over **[[rtp|RTP]]** ([[rfc:3261|RFC 3261]]).', steps: { - 0: '{{sip-register|REGISTER}} maps a [[sip|SIP]] address (`bob@example.com`) to the device\'s current {{ip-address|IP}}. The {{sip-registrar|registrar}} is how the {{sip-proxy|proxy}} knows where to ring Bob.', + 0: "{{sip-register|REGISTER}} maps a [[sip|SIP]] address (`bob@example.com`) to the device's current {{ip-address|IP}}. The {{sip-registrar|registrar}} is how the {{sip-proxy|proxy}} knows where to ring Bob.", 2: '{{sip-invite|INVITE}} is the call request. Body carries an [[sdp|SDP]] offer describing what audio/video the caller can send.', - 3: '{{sip-proxy|Proxy}} forwards to all of Bob\'s registered devices ({{sip-forking|*forking*}}) so every phone he owns can ring at once.', + 3: "{{sip-proxy|Proxy}} forwards to all of Bob's registered devices ({{sip-forking|*forking*}}) so every phone he owns can ring at once.", 4: '**{{sip-180-ringing|`180 Ringing`}}** = {{sip-provisional-response|provisional response}}: I got the {{sip-invite|INVITE}}, the user is being alerted. May arrive multiple times.', - 6: 'Bob picks up. **{{sip-200-ok|`200 OK`}} carries Bob\'s [[sdp|SDP]] answer**, completing the {{codec|codec}}/{{port|port}} negotiation.', + 6: "Bob picks up. **{{sip-200-ok|`200 OK`}} carries Bob's [[sdp|SDP]] answer**, completing the {{codec|codec}}/{{port|port}} negotiation.", 8: '**{{sip-ack|ACK}}** confirms the {{sip-200-ok|200}} was received. [[sip|SIP]] is {{request-response|request-response}} *except* for {{sip-invite|INVITE}}, which uses this {{three-way-handshake|3-way pattern}} to be safe over [[udp|UDP]].', 9: 'Now that {{signaling|signaling}} has agreed on {{codec|codecs}} and {{ip-address|IPs}}, media bypasses the {{sip-proxy|SIP proxy}} and flows phone-to-phone (typically as [[rtp|RTP]]).', 10: 'Either side sends {{sip-bye|BYE}} to hang up. Tears down the call cleanly.' @@ -753,7 +753,7 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { 1: '**`.m3u8`** is a plain text playlist (the *master {{manifest|manifest}}*). Lists the variant playlists for each quality level.', 2: 'Player picks a starting quality based on initial {{bandwidth|bandwidth}} estimate.', 3: '**`.ts`** = {{mpeg-ts|MPEG-2 Transport Stream}} segment, ~6 seconds of video. Each is a standalone {{http-method|HTTP GET}} β€” cacheable by any {{cdn|CDN}}.', - 7: 'Network slows down. The player measures throughput on each segment and notices it can\'t keep up at 1080p.', + 7: "Network slows down. The player measures throughput on each segment and notices it can't keep up at 1080p.", 8: 'Player switches to 720p for the *next* segment without breaking playback. Switches happen at {{abr-segment-switch|segment boundaries}}, so no buffer disruption.' } }, @@ -810,11 +810,11 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { B->>A: Media streams (RTP) begin Note over A,B: SDP negotiated codecs, ports, encryption`, caption: - '**[[sdp|SDP]]** = Session Description Protocol. A plain-text format that describes a media session β€” codecs, ports, IPs, {{encryption|encryption}} keys. Used inside [[sip|SIP]] and [[webrtc|WebRTC]] to negotiate *what\'s about to be streamed* ([[rfc:8866|RFC 8866]]).', + "**[[sdp|SDP]]** = Session Description Protocol. A plain-text format that describes a media session β€” codecs, ports, IPs, {{encryption|encryption}} keys. Used inside [[sip|SIP]] and [[webrtc|WebRTC]] to negotiate *what's about to be streamed* ([[rfc:8866|RFC 8866]]).", steps: { 1: 'Each line is `key=value`: **`v=0` ({{protocol|protocol}} version), `m=` (media: audio or video, {{port|port}}, {{codec|codec}} list), `c=`** (connection {{ip-address|IP}}), plus {{codec|codec}} parameters and {{encryption|crypto}}.', - 3: '[[sdp|SDP]] is transport-agnostic β€” it doesn\'t carry itself, it rides inside something else ([[sip|SIP]] {{sip-invite|INVITE}} body, [[webrtc|WebRTC]] {{signaling|signaling}} channel).', - 5: '{{sdp-offer-answer|Offer/answer pattern}}: B picks {{codec|codecs}} from A\'s offer and returns only what both support. Negotiation is one {{rtt|round trip}}, no haggling.', + 3: "[[sdp|SDP]] is transport-agnostic β€” it doesn't carry itself, it rides inside something else ([[sip|SIP]] {{sip-invite|INVITE}} body, [[webrtc|WebRTC]] {{signaling|signaling}} channel).", + 5: "{{sdp-offer-answer|Offer/answer pattern}}: B picks {{codec|codecs}} from A's offer and returns only what both support. Negotiation is one {{rtt|round trip}}, no haggling.", 10: 'Once [[sdp|SDP]] negotiation completes, both sides know which {{codec|codecs}} to use and where to send the bytes β€” [[rtp|RTP]] {{packet|packets}} start flowing.' } }, @@ -841,7 +841,7 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { '**[[dash|DASH]]** = Dynamic Adaptive Streaming over {{http-method|HTTP}} ({{mpeg-org|MPEG}}, {{iso|ISO}} 23009-1). Same idea as [[hls|HLS]] β€” segmented video at multiple bitrates over plain {{http-method|HTTP}} β€” but **{{codec|codec}}-agnostic** and an open standard.', steps: { 0: '**`.mpd`** = {{mpd|Media Presentation Description}}, an [[xml|XML]] {{manifest|manifest}} describing the whole presentation hierarchy.', - 1: 'Hierarchy: {{dash-period|Period}} (a chapter) β†’ {{dash-adaptation-set|AdaptationSet}} (a track: video, audio, subtitle) β†’ {{dash-representation|Representation}} (a quality variant). Cleaner abstraction than [[hls|HLS]]\'s nested playlists.', + 1: "Hierarchy: {{dash-period|Period}} (a chapter) β†’ {{dash-adaptation-set|AdaptationSet}} (a track: video, audio, subtitle) β†’ {{dash-representation|Representation}} (a quality variant). Cleaner abstraction than [[hls|HLS]]'s nested playlists.", 3: '**`.m4s`** = {{fragmented-mp4|fragmented MP4}} segment. Standard {{isobmff|ISOBMFF}} container β€” works with any {{codec|codec}} ({{h264|H.264}}, {{h265|H.265}}, {{vp9|VP9}}, {{av1|AV1}}).', 7: 'Player measures {{bandwidth|bandwidth}} on each segment download. Decision logic varies β€” *throughput-based*, *buffer-based*, or hybrid ({{abr-bola|BOLA}}, dash.js default).', 11: '{{bandwidth|Bandwidth}} recovered β†’ switch back up. Switches happen at {{abr-segment-switch|segment boundaries}}; the buffer continues seamlessly.' @@ -872,11 +872,11 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { steps: { 0: 'Client asks its configured {{recursive-resolver|resolver}} (typically your ISP or a public one like `1.1.1.1` or `8.8.8.8`).', 1: 'First, the {{recursive-resolver|resolver}} checks its cache. Roughly 80% of real-world queries are answered here without a single network packet.', - 2: '{{iterative-resolution|Iterative resolution}}: the {{recursive-resolver|resolver}} walks the tree itself. Each {{nameserver|nameserver}} answers *go ask this other server*, not *here\'s the final answer*.', - 3: '{{root-server|Root servers}} don\'t know `example.com` β€” they only know which servers run `.com`. Returns the {{ip-address|IP}} of a {{tld|TLD}} {{nameserver|nameserver}}.', - 5: '{{tld|TLD}} doesn\'t know the records either, just who\'s {{authoritative-nameserver|authoritative}} for `example.com` (set by the registrar at registration time).', + 2: "{{iterative-resolution|Iterative resolution}}: the {{recursive-resolver|resolver}} walks the tree itself. Each {{nameserver|nameserver}} answers *go ask this other server*, not *here's the final answer*.", + 3: "{{root-server|Root servers}} don't know `example.com` β€” they only know which servers run `.com`. Returns the {{ip-address|IP}} of a {{tld|TLD}} {{nameserver|nameserver}}.", + 5: "{{tld|TLD}} doesn't know the records either, just who's {{authoritative-nameserver|authoritative}} for `example.com` (set by the registrar at registration time).", 7: '{{a-record|A record}} = the IPv4 address. Other {{dns-record-types|record types}}: {{aaaa-record|AAAA}} ([[ipv6|IPv6]]), {{mx-record|MX}} (mail), {{cname-record|CNAME}} (alias), {{txt-record|TXT}} (verification, SPF), {{ns-record|NS}} (delegation).', - 8: '{{recursive-resolver|Resolver}} caches the answer for the record\'s **{{ttl|TTL}}** (Time To Live). Subsequent queries for `example.com` return instantly.' + 8: "{{recursive-resolver|Resolver}} caches the answer for the record's **{{ttl|TTL}}** (Time To Live). Subsequent queries for `example.com` return instantly." } }, @@ -899,7 +899,7 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { steps: { 1: '**{{client-hello|ClientHello}}** lists the {{cipher-suite|cipher suites}} the client supports plus a key share (its half of a {{diffie-hellman|Diffie-Hellman}} exchange). The keyshare bit is the [[tls|TLS]] 1.3 trick that saves a {{rtt|round trip}}.', 2: '**{{server-hello|ServerHello}}** picks one {{cipher-suite|cipher}} and sends its own key share. After this exchange, both sides can derive the shared secret β€” the {{tls-handshake|handshake}} itself is now {{encryption|encrypted}}.', - 3: '**{{certificate|Certificate}}** proves the server is who it claims to be (signed by a trusted {{certificate-authority|CA}}). {{tls-certificate-verify|CertificateVerify}} signs the {{tls-handshake|handshake transcript}} with the cert\'s {{private-key|private key}} β€” proves the server actually owns it.', + 3: "**{{certificate|Certificate}}** proves the server is who it claims to be (signed by a trusted {{certificate-authority|CA}}). {{tls-certificate-verify|CertificateVerify}} signs the {{tls-handshake|handshake transcript}} with the cert's {{private-key|private key}} β€” proves the server actually owns it.", 4: '{{tls-finished|Finished}} is a {{hmac|MAC}} over the entire {{tls-handshake|handshake}} β€” confirms nothing in the negotiation was tampered with.', 9: 'On reconnect, **{{zero-rtt|0-RTT}}** lets the client send data in its first {{packet|packet}} using a key derived from a previous {{session-resumption|session}}. Trades {{replay-attack|replay-attack}} resistance for one less {{rtt|round trip}}.' } @@ -925,10 +925,10 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { caption: '**[[ssh|SSH]]** = Secure Shell. Encrypted remote shell, file transfer, and tunneling (Tatu YlΓΆnen, 1995). **Diffie-Hellman key {{exchange|exchange}}** establishes a shared secret over an open network, **host key verification** stops {{man-in-the-middle|MITM}}, then user auth (public-key or password) grants access. Modern {{aead|AEAD}} ciphers ({{chacha20-poly1305|ChaCha20-Poly1305}}, {{aes-gcm|AES-GCM}}) protect every byte ([[rfc:4253|RFC 4253]]).', steps: { - 0: 'Both sides advertise their version string in {{plaintext|plaintext}}. Used to negotiate features and as input to the {{handshake|handshake}}\'s {{hmac|MAC}}.', + 0: "Both sides advertise their version string in {{plaintext|plaintext}}. Used to negotiate features and as input to the {{handshake|handshake}}'s {{hmac|MAC}}.", 3: '{{ssh-kex-init|KEX_INIT}} lists the algorithms each side supports for {{ssh-key-exchange|key exchange}}, {{ssh-host-key|host-key}}, {{encryption|encryption}}, {{hmac|MAC}}, and compression. Both sides pick the strongest mutual choice.', - 5: '{{diffie-hellman|Diffie-Hellman}} lets both sides derive a shared session key without ever sending it. An eavesdropper can\'t recover it even with the full transcript.', - 6: 'Server\'s {{ssh-host-key|host key}} identifies *this server* across reboots. The user\'s `known_hosts` file pins it β€” that\'s the {{ssh-tofu|TOFU}} (trust on first use) prompt the first time you connect.', + 5: "{{diffie-hellman|Diffie-Hellman}} lets both sides derive a shared session key without ever sending it. An eavesdropper can't recover it even with the full transcript.", + 6: "Server's {{ssh-host-key|host key}} identifies *this server* across reboots. The user's `known_hosts` file pins it β€” that's the {{ssh-tofu|TOFU}} (trust on first use) prompt the first time you connect.", 8: 'Authentication is separate from {{ssh-key-exchange|key exchange}}. Common methods: {{ssh-publickey-auth|`publickey`}} (your local [[ssh|SSH]] key), `password`, {{ssh-keyboard-interactive|`keyboard-interactive`}} (2FA prompts).', 11: '{{ssh-channels|Channels}} {{multiplexing|multiplex}} multiple sessions inside one [[ssh|SSH]] connection β€” interactive shell, file transfer ({{sftp|SFTP}}), {{port-forwarding|port forwarding}}, all on the same [[tcp|TCP]] {{socket|socket}}.' } @@ -948,10 +948,10 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { caption: '**[[dhcp|DHCP]]** = Dynamic Host Configuration Protocol. Plug a device into a network, it gets an {{ip-address|IP address}}, gateway, [[dns|DNS]], and {{subnet|subnet}} mask without manual config. The four messages spell **{{dora|DORA}}**: Discover, Offer, Request, Ack ([[rfc:2131|RFC 2131]]).', steps: { - 0: 'The device has no {{ip-address|IP}}, no gateway, no [[dns|DNS]] β€” it can\'t even ask a specific server for help. The only thing it can do is **{{broadcast|broadcast}}**.', + 0: "The device has no {{ip-address|IP}}, no gateway, no [[dns|DNS]] β€” it can't even ask a specific server for help. The only thing it can do is **{{broadcast|broadcast}}**.", 1: '{{dhcp-discover|DISCOVER}} is a {{broadcast|broadcast}} (`255.255.255.255` from `0.0.0.0`). Every [[dhcp|DHCP]] server on the {{lan|LAN}} can hear it; usually only one responds.', 2: 'Server {{dhcp-offer|OFFERs}} a specific {{ip-address|IP}} from its pool, with a {{dhcp-lease|lease}} duration. Multiple servers might offer β€” the device picks one.', - 3: '{{dhcp-request|REQUEST}} confirms which {{dhcp-offer|offer}} the device accepted (also {{broadcast|broadcast}}, so other servers know to release their offers). Includes the chosen server\'s identifier.', + 3: "{{dhcp-request|REQUEST}} confirms which {{dhcp-offer|offer}} the device accepted (also {{broadcast|broadcast}}, so other servers know to release their offers). Includes the chosen server's identifier.", 4: '**{{dhcp-ack|ACK}}** confirms the {{dhcp-lease|lease}} and includes the network config: {{subnet|subnet}} mask, {{default-gateway|default gateway}}, [[dns|DNS]] servers, lease time. Device is now on the network.', 6: 'Devices try to renew at the halfway point (`T1`). If renewal fails, they try again at `T2` (~87.5%). If still nothing, they {{dhcp-discover|DISCOVER}} again before the {{dhcp-lease|lease}} expires.' } @@ -971,14 +971,14 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { Note over C,S: Offset = ((T2-T1)+(T3-T4))/2 Note over C,S: Multiple samples β€” accuracy within 1-10ms`, caption: - '**[[ntp|NTP]]** = Network Time Protocol ([[pioneer:david-mills|David L. Mills]], 1985). Keeps every device\'s clock within milliseconds of true time β€” the foundation of logs, [[tls|TLS]] {{certificate|certificates}}, and distributed systems. The trick is **four timestamps per {{exchange|exchange}}** (T1/T2/T3/T4) which cancel out network {{latency|latency}} and recover the one-way {{offset|offset}}. Runs over [[udp|UDP]]/123; modern hardening via **{{nts|NTS}}** (Network Time Security, [[rfc:8915|RFC 8915]]).', + "**[[ntp|NTP]]** = Network Time Protocol ([[pioneer:david-mills|David L. Mills]], 1985). Keeps every device's clock within milliseconds of true time β€” the foundation of logs, [[tls|TLS]] {{certificate|certificates}}, and distributed systems. The trick is **four timestamps per {{exchange|exchange}}** (T1/T2/T3/T4) which cancel out network {{latency|latency}} and recover the one-way {{offset|offset}}. Runs over [[udp|UDP]]/123; modern hardening via **{{nts|NTS}}** (Network Time Security, [[rfc:8915|RFC 8915]]).", steps: { - 0: 'Crystal oscillators {{clock-drift|drift}} β€” even good ones gain or lose seconds per day. Without [[ntp|NTP]], your machine\'s clock would be hours off after a few months.', + 0: "Crystal oscillators {{clock-drift|drift}} β€” even good ones gain or lose seconds per day. Without [[ntp|NTP]], your machine's clock would be hours off after a few months.", 1: 'Client records **`T1`** when it sends the request. T1 travels in the packet.', 2: 'Server stamps **`T2` when the request arrives, then `T3`** when the reply leaves.', 3: 'Reply carries all three timestamps. Client records **`T4`** on receive.', 7: '{{offset|Offset}} = ((T2βˆ’T1) + (T3βˆ’T4)) / 2. The math cancels out one-way network {{latency|latency}} on the assumption that send and receive paths take roughly equal time.', - 8: 'Several samples are gathered. {{marzullos-algorithm|Marzullo\'s algorithm}} discards outliers and picks the most accurate β€” typical accuracy is 1–10 ms on a {{lan|LAN}}.' + 8: "Several samples are gathered. {{marzullos-algorithm|Marzullo's algorithm}} discards outliers and picks the most accurate β€” typical accuracy is 1–10 ms on a {{lan|LAN}}." } }, @@ -1001,7 +1001,7 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { 0: '**{{ehlo|EHLO}}** = Extended HELLO (introduces the client). **{{starttls|STARTTLS}}** upgrades the {{plaintext|plaintext}} connection to [[tls|TLS]] β€” modern {{mta|MTAs}} require it.', 1: 'Server replies with the capabilities it supports ({{pipelining|PIPELINING}}, AUTH methods, max message size, etc.) β€” discovered, not assumed.', 2: 'Three commands send the {{smtp-envelope|envelope}}: **`MAIL FROM` (sender), `RCPT TO` (recipient), `DATA`** (the actual message body, ending with a `.` on its own line).', - 4: 'Sender\'s {{mta|MTA}} looks up the recipient domain\'s **{{mx-record|MX record}}** in [[dns|DNS]] β€” the address of the receiving {{mta|MTA}}. *That\'s how mail finds its destination.*', + 4: "Sender's {{mta|MTA}} looks up the recipient domain's **{{mx-record|MX record}}** in [[dns|DNS]] β€” the address of the receiving {{mta|MTA}}. *That's how mail finds its destination.*", 5: 'Same {{ehlo|EHLO}}/MAIL/RCPT/DATA dance, just {{mta|MTA}}-to-{{mta|MTA}}. The message can {{hop|hop}} through several relays before reaching the final mailbox.', 6: '[[smtp|SMTP]] only delivers. To *read* the mail, the recipient uses **[[imap|IMAP]]** or **{{pop3|POP3}}** (or a webmail UI on top).', 7: '**{{store-and-forward|Store-and-forward}}** means each {{mta|MTA}} accepts full responsibility for the message β€” if the next {{hop|hop}} is down, it queues and retries.' @@ -1084,8 +1084,8 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { caption: '**[[bgp|BGP]]** = Border Gateway Protocol ([[pioneer:yakov-rekhter|Yakov Rekhter]] et al., 1989). The protocol that holds the internet together β€” routers in different **{{autonomous-system|Autonomous Systems}}** (ISPs, big companies) tell each other which {{ip-address|IP}} ranges they can reach. Path-vector design: every advertisement carries the {{as-path|AS_PATH}} for loop detection and policy. Crypto-secured by {{rpki|RPKI}} since 2008 ([[rfc:4271|RFC 4271]]).', steps: { - 0: 'Runs over [[tcp|TCP]] port 179 between two router neighbors that have been manually configured to {{peering|peer}} with each other. There\'s no auto-discovery on the public internet.', - 1: '{{autonomous-system|AS = Autonomous System}}: one organization\'s network, identified by a number ({{asn|ASN}}). {{bgp-open|OPEN}} carries this AS number plus a {{hold-timer|hold timer}} β€” how long to wait without a {{bgp-keepalive|keepalive}} before declaring the peer dead.', + 0: "Runs over [[tcp|TCP]] port 179 between two router neighbors that have been manually configured to {{peering|peer}} with each other. There's no auto-discovery on the public internet.", + 1: "{{autonomous-system|AS = Autonomous System}}: one organization's network, identified by a number ({{asn|ASN}}). {{bgp-open|OPEN}} carries this AS number plus a {{hold-timer|hold timer}} β€” how long to wait without a {{bgp-keepalive|keepalive}} before declaring the peer dead.", 3: '{{bgp-keepalive|KEEPALIVE}} is a tiny heartbeat β€” proves the peer is alive even when nothing is changing.', 6: '{{bgp-update|UPDATE}} announces a route: *I can reach `192.168.0.0/16` β€” send packets to me.* Includes the {{as-path|AS_PATH}} showing every {{autonomous-system|AS}} the announcement traveled through (loop prevention).', 9: 'Quiet links still need {{bgp-keepalive|keepalives}} every ~30s so peers know each other are alive.', @@ -1110,14 +1110,14 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { T->>S: Echo Reply β€” destination reached Note over S,T: Each hop revealed by TTL expiry`, caption: - '**[[icmp|ICMP]]** = Internet Control Message Protocol ([[pioneer:jon-postel|Jon Postel]], 1981). The internet\'s diagnostic and error-reporting layer, riding directly on [[ip|IP]] (protocol 1). **`{{ping|ping}}`** measures {{rtt|round-trip time}} via {{echo-request|Echo Request}} / {{echo-reply|Echo Reply}}; **`{{traceroute|traceroute}}`** maps the path by sending packets with increasing **{{ttl|TTL}}** and reading the Time-Exceeded replies from each {{hop|hop}}. {{path-mtu-discovery|PMTUD}} uses {{fragmentation|Fragmentation}}-Needed [[icmp|ICMP]] to negotiate the path {{mtu|MTU}} ([[rfc:792|RFC 792]]).', + "**[[icmp|ICMP]]** = Internet Control Message Protocol ([[pioneer:jon-postel|Jon Postel]], 1981). The internet's diagnostic and error-reporting layer, riding directly on [[ip|IP]] (protocol 1). **`{{ping|ping}}`** measures {{rtt|round-trip time}} via {{echo-request|Echo Request}} / {{echo-reply|Echo Reply}}; **`{{traceroute|traceroute}}`** maps the path by sending packets with increasing **{{ttl|TTL}}** and reading the Time-Exceeded replies from each {{hop|hop}}. {{path-mtu-discovery|PMTUD}} uses {{fragmentation|Fragmentation}}-Needed [[icmp|ICMP]] to negotiate the path {{mtu|MTU}} ([[rfc:792|RFC 792]]).", steps: { 1: '{{echo-request|Echo Request}} = {{ping|ping}}. Type 8, identifier + {{sequence-number|sequence number}}, optional payload (helpful to detect {{mtu|MTU}} issues if you fill it with bytes).', - 2: '{{echo-reply|Echo Reply}} = pong. Type 0, copies the request\'s identifier and seq back so you can pair them. The time difference is your {{rtt|round-trip time}}.', + 2: "{{echo-reply|Echo Reply}} = pong. Type 0, copies the request's identifier and seq back so you can pair them. The time difference is your {{rtt|round-trip time}}.", 6: '**{{ttl|TTL}}** = Time To Live. Decrements by 1 at every router. Setting TTL=1 guarantees the very first router will drop the packet.', - 7: 'When {{ttl|TTL}} hits 0, the dropping router sends back an [[icmp|ICMP]] {{time-exceeded|Time Exceeded}} with its own {{ip-address|IP}}. Now you know {{hop|hop}} #1\'s address.', - 8: 'Increment {{ttl|TTL}} β†’ next {{hop|hop}} drops it β†’ next hop\'s address revealed. Walk all the way to the destination this way.', - 9: 'Eventually {{ttl|TTL}} is high enough to reach the target β€” you get an {{echo-reply|Echo Reply}} instead of {{time-exceeded|Time Exceeded}}. That\'s how {{traceroute|traceroute}} knows it\'s done.' + 7: "When {{ttl|TTL}} hits 0, the dropping router sends back an [[icmp|ICMP]] {{time-exceeded|Time Exceeded}} with its own {{ip-address|IP}}. Now you know {{hop|hop}} #1's address.", + 8: "Increment {{ttl|TTL}} β†’ next {{hop|hop}} drops it β†’ next hop's address revealed. Walk all the way to the destination this way.", + 9: "Eventually {{ttl|TTL}} is high enough to reach the target β€” you get an {{echo-reply|Echo Reply}} instead of {{time-exceeded|Time Exceeded}}. That's how {{traceroute|traceroute}} knows it's done." } }, @@ -1147,11 +1147,11 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { steps: { 1: '**[[arp|ARP]]** asks *who has {{ip-address|IP}} `192.168.1.50`?* β€” sent as an [[ethernet|Ethernet]] {{broadcast|broadcast}} (destination {{mac-address|MAC}} `FF:FF:FF:FF:FF:FF`).', 2: 'Switch floods {{broadcast|broadcasts}} to every port β€” it has no choice; the destination {{mac-address|MAC}} is unknown and the request must reach everyone.', - 3: 'Host B replies with its {{mac-address|MAC}} (`00:1B:2C:3D:4E:5F`). The reply is {{unicast|unicast}} β€” it has Host A\'s {{mac-address|MAC}} from the request.', - 4: 'Switch sees this reply pass through and learns: Host B\'s {{mac-address|MAC}} is on Port 3. From now on, {{frame|frames}} to that {{mac-address|MAC}} don\'t need flooding.', + 3: "Host B replies with its {{mac-address|MAC}} (`00:1B:2C:3D:4E:5F`). The reply is {{unicast|unicast}} β€” it has Host A's {{mac-address|MAC}} from the request.", + 4: "Switch sees this reply pass through and learns: Host B's {{mac-address|MAC}} is on Port 3. From now on, {{frame|frames}} to that {{mac-address|MAC}} don't need flooding.", 5: '{{mac-table|MAC table}}: a per-port mapping of source {{mac-address|MACs}} the switch has observed. Entries time out after a few minutes if unused.', - 7: 'Host A sends an [[ethernet|Ethernet]] {{frame|frame}} addressed to Host B\'s {{mac-address|MAC}}. The {{ip-address|IP}} packet is the *{{payload|payload}}*.', - 8: 'Switch checks its {{mac-table|MAC table}} β†’ Port 3 β†’ forwards only to Port 3. Other ports never see this {{frame|frame}}. That\'s the difference between a switch and a hub.' + 7: "Host A sends an [[ethernet|Ethernet]] {{frame|frame}} addressed to Host B's {{mac-address|MAC}}. The {{ip-address|IP}} packet is the *{{payload|payload}}*.", + 8: "Switch checks its {{mac-table|MAC table}} β†’ Port 3 β†’ forwards only to Port 3. Other ports never see this {{frame|frame}}. That's the difference between a switch and a hub." } }, @@ -1179,10 +1179,10 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { caption: '**WiFi** = wireless [[ethernet|Ethernet]] ({{ieee-802-15-4|IEEE}} [[wifi|802.11]]). After discovering the network, the device authenticates and associates, then runs the **{{wpa2|WPA2}} 4-way {{handshake|handshake}}** to derive {{encryption|encryption}} keys. Wireless frames are then bridged to the wired {{lan|LAN}} by the **{{ap-access-point|AP}}** ({{access-point|Access Point}}).', steps: { - 1: '{{beacon|Beacon}} = the {{access-point|AP}}\'s {{broadcast|broadcast}} announcement, ~10Γ— per second. Carries the {{ssid|SSID}} (network name), supported rates, security mode, and capabilities.', - 2: '{{authentication-frame|Legacy step}} (predates {{wpa2|WPA}}): used to allow shared-key auth in WEP. Today it\'s just a formality β€” security happens in the {{wpa2-handshake|4-way handshake}}.', + 1: "{{beacon|Beacon}} = the {{access-point|AP}}'s {{broadcast|broadcast}} announcement, ~10Γ— per second. Carries the {{ssid|SSID}} (network name), supported rates, security mode, and capabilities.", + 2: "{{authentication-frame|Legacy step}} (predates {{wpa2|WPA}}): used to allow shared-key auth in WEP. Today it's just a formality β€” security happens in the {{wpa2-handshake|4-way handshake}}.", 4: '{{association-request|Association}} is the actual *I want to use this network* request. {{access-point|AP}} assigns the device an **{{aid|AID}}** (Association ID, 1–2007).', - 7: '{{anonce|ANonce}} = the {{access-point|AP}}\'s random {{nonce|number}}. Combined with both {{mac-address|MAC addresses}} + the pre-shared key (passphrase, {{pmk|PMK}}), it generates the session key.', + 7: "{{anonce|ANonce}} = the {{access-point|AP}}'s random {{nonce|number}}. Combined with both {{mac-address|MAC addresses}} + the pre-shared key (passphrase, {{pmk|PMK}}), it generates the session key.", 8: 'Client picks its own {{snonce|SNonce}} and computes the session key (**{{ptk|PTK}}**). {{mic|MIC}} (Message Integrity Code) over the message proves it knew the passphrase.', 9: '{{access-point|AP}} shares the **{{gtk|GTK}}** = Group Temporal Key, used for encrypting {{broadcast|broadcast}}/{{multicast|multicast}} {{frame|frames}} so all clients can decrypt them.', 12: '{{frame|Frames}} between client and {{access-point|AP}} are now {{encryption|encrypted}} with the {{ptk|PTK}}. Anyone listening on the air sees only ciphertext.', @@ -1211,8 +1211,8 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { steps: { 1: '{{arp-cache|ARP cache}} stores recent {{ip-address|IP}}β†’{{mac-address|MAC}} mappings. A miss means we have to ask the network.', 2: 'Sent as a **{{broadcast|broadcast}}** β€” destination {{mac-address|MAC}} `FF:FF:FF:FF:FF:FF`. Every device on the {{lan|LAN}} receives and processes it.', - 5: 'Only the matching host replies, **{{unicast|unicast}}** to the asker\'s {{mac-address|MAC}}. {{arp-reply|Reply}} carries the answer in the sender hardware/protocol fields.', - 8: 'Now Host A wraps its {{ip-address|IP}} packet in an [[ethernet|Ethernet]] {{frame|frame}} addressed to Host B\'s {{mac-address|MAC}}. The two hosts can finally exchange real data.', + 5: "Only the matching host replies, **{{unicast|unicast}}** to the asker's {{mac-address|MAC}}. {{arp-reply|Reply}} carries the answer in the sender hardware/protocol fields.", + 8: "Now Host A wraps its {{ip-address|IP}} packet in an [[ethernet|Ethernet]] {{frame|frame}} addressed to Host B's {{mac-address|MAC}}. The two hosts can finally exchange real data.", 11: '{{arp-cache|ARP entries}} time out in 1–5 minutes (OS-dependent) so {{mac-address|MAC-address}} changes (new NIC, {{ip-address|IP}} reassigned) get re-learned.' } }, @@ -1235,7 +1235,7 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { caption: '**[[ip|IP]]** = Internet Protocol ([[pioneer:vint-cerf|Vint Cerf]] + [[pioneer:bob-kahn|Bob Kahn]], 1974; [[pioneer:jon-postel|Jon Postel]] editor). Routes packets across networks, {{hop|hop}} by {{hop|hop}}, with a 32-bit address space and best-effort delivery β€” every higher-layer reliability ([[tcp|TCP]], [[quic|QUIC]], [[sctp|SCTP]]) is built on top. The crucial insight: **{{ip-address|IP source/destination}} stay the same end-to-end**, while **{{mac-address|MAC addresses}} change at every router** ([[rfc:791|RFC 791]]).', steps: { - 1: 'Source sends to its **{{default-gateway|default gateway}}** (the router). Destination {{mac-address|MAC}} is the router\'s MAC; destination {{ip-address|IP}} is the *final* destination.', + 1: "Source sends to its **{{default-gateway|default gateway}}** (the router). Destination {{mac-address|MAC}} is the router's MAC; destination {{ip-address|IP}} is the *final* destination.", 2: 'Router looks at the {{ip-address|IP}} destination, checks its **{{routing-table|routing table}}** β€” *which interface goes toward `93.184.216.34`?*', 3: '**{{ttl|TTL}}** decrements by 1 at every router. Hits 0 β†’ packet dropped, [[icmp|ICMP]] {{time-exceeded|Time Exceeded}} sent back. Stops infinite loops.', 5: 'Same packet leaves the router with new {{mac-address|MAC addresses}} for the next link, but same {{ip-address|IP addresses}} for the original endpoints.', @@ -1292,10 +1292,10 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { '**[[ipv6|IPv6]]** = the next-generation {{ip-address|IP}}. **128-bit addresses** (so many that {{nat|NAT}} becomes unnecessary), a fixed 40-byte header, and built-in autoconfiguration. {{ndp|NDP}} replaces [[arp|ARP]] using [[ipv6|IPv6]] {{multicast|multicast}} ([[rfc:8200|RFC 8200]]).', steps: { 1: '{{router-solicitation|Router Solicitation}} asks any router on the link to advertise itself. {{icmpv6|ICMPv6}} type 133, sent to the all-routers {{multicast|multicast}} address (`ff02::2`).', - 2: '{{router-advertisement|Router Advertisement}} carries the network\'s `/64` prefix. The host builds its own address by combining the prefix with its {{interface-id|interface ID}} β€” no [[dhcp|DHCP]] needed (**{{slaac|SLAAC}}**).', - 4: '**{{ndp|NDP}}** = Neighbor Discovery Protocol. Instead of [[arp|ARP]]\'s full {{broadcast|broadcast}}, {{ndp|NDP}} uses {{solicited-node-multicast|solicited-node multicast}} β€” only hosts whose {{ip-address|IP}} ends in `::1ff00:1` listen, dramatically reducing noise.', - 6: '[[ipv6|IPv6]]\'s header is fixed at 40 bytes with optional extension headers. [[ip|IPv4]]\'s variable header forced every router to do header parsing β€” [[ipv6|IPv6]] is faster on average.', - 7: '**`{{hop-limit|Hop Limit}}` is [[ipv6|IPv6]]\'s {{ttl|TTL}} (decrements per router). `Next Header` chains optional extensions and identifies the upper protocol. No header {{checksum|checksum}}** β€” [[udp|UDP]]/[[tcp|TCP]]/L2 already check, so no need.', + 2: "{{router-advertisement|Router Advertisement}} carries the network's `/64` prefix. The host builds its own address by combining the prefix with its {{interface-id|interface ID}} β€” no [[dhcp|DHCP]] needed (**{{slaac|SLAAC}}**).", + 4: "**{{ndp|NDP}}** = Neighbor Discovery Protocol. Instead of [[arp|ARP]]'s full {{broadcast|broadcast}}, {{ndp|NDP}} uses {{solicited-node-multicast|solicited-node multicast}} β€” only hosts whose {{ip-address|IP}} ends in `::1ff00:1` listen, dramatically reducing noise.", + 6: "[[ipv6|IPv6]]'s header is fixed at 40 bytes with optional extension headers. [[ip|IPv4]]'s variable header forced every router to do header parsing β€” [[ipv6|IPv6]] is faster on average.", + 7: "**`{{hop-limit|Hop Limit}}` is [[ipv6|IPv6]]'s {{ttl|TTL}} (decrements per router). `Next Header` chains optional extensions and identifies the upper protocol. No header {{checksum|checksum}}** β€” [[udp|UDP]]/[[tcp|TCP]]/L2 already check, so no need.", 9: 'Same {{ip-address|IP}} packet, new {{mac-address|MACs}} at every {{hop|hop}} β€” same hop-by-hop pattern as [[ip|IPv4]].', 12: '`2^128` β‰ˆ 340 undecillion addresses. Enough that every device gets a globally unique {{ip-address|address}} β€” **{{nat|NAT}}** becomes a security choice, not a necessity.' } @@ -1354,12 +1354,12 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { caption: '**[[kerberos|Kerberos]]** = three-headed dog: Client, **{{kerberos-kdc|KDC}}** (Key Distribution Center, split into AS + TGS), and Service. Two {{encryption|encrypted}} blobs per ticket, **zero passwords on the wire**. Time-bounded **{{kerberos-tgt|TGT}}** (Ticket Granting Ticket) gates further service tickets so the password is only used once per session. Designed at {{mit|MIT}} Project Athena (1983–1991), [[rfc:4120|RFC 4120]] (2005). Powers every {{microsoft|Active Directory}} domain on Earth.', steps: { - 0: 'Alice wants to log in. She sends an {{kerberos-as-req|AS-REQ}} to the {{kerberos-kdc|Key Distribution Center}}\'s Authentication Service with her {{kerberos-principal|principal}} name and a {{kerberos-pa-enc-timestamp|PA-ENC-TIMESTAMP}} β€” a fresh timestamp {{encryption|encrypted}} under her long-term key β€” proving she knows the password before the {{kerberos-kdc|KDC}} bothers responding.', - 1: '{{kerberos-as-rep|AS-REP}} carries two things: a {{kerberos-tgt|Ticket Granting Ticket}} {{encryption|encrypted}} under the {{kerberos-krbtgt|krbtgt}} {{kerberos-principal|principal}}\'s key (only the {{kerberos-kdc|KDC}} can decrypt it later), and the session key encrypted under Alice\'s long-term key (only Alice can decrypt). Alice never sends her password.', - 3: 'For each service Alice wants to use, she sends a {{kerberos-tgs-req|TGS-REQ}} to the {{kerberos-kdc|KDC}}\'s {{kerberos-tgs|Ticket Granting Service}}: her {{kerberos-tgt|TGT}} (proves who she is) + a fresh {{kerberos-authenticator|authenticator}} {{encryption|encrypted}} under her {{kerberos-tgt|TGT}}\'s session key (proves she just got it).', - 4: '{{kerberos-tgs-rep|TGS-REP}} returns a {{kerberos-service-ticket|service ticket}} {{encryption|encrypted}} under web1\'s long-term key (so only web1 can decrypt it), plus the new client↔service session key encrypted under the {{kerberos-tgt|TGT}}\'s session key (so only Alice can decrypt it).', - 6: '{{kerberos-ap-req|AP-REQ}} β€” Alice connects to web1 and presents the {{kerberos-service-ticket|service ticket}} plus a fresh {{kerberos-authenticator|authenticator}}. The service ticket carries Alice\'s identity inside the {{encryption|encrypted}} blob; web1 doesn\'t need to talk to the {{kerberos-kdc|KDC}} to verify.', - 7: 'web1 decrypts the ticket with its {{kerberos-keytab|keytab}} key, extracts K_svc, decrypts the {{kerberos-authenticator|authenticator}}. If `ctime` is within Β±5 minutes of web1\'s clock and the authenticator hasn\'t been seen before, Alice is authenticated.', + 0: "Alice wants to log in. She sends an {{kerberos-as-req|AS-REQ}} to the {{kerberos-kdc|Key Distribution Center}}'s Authentication Service with her {{kerberos-principal|principal}} name and a {{kerberos-pa-enc-timestamp|PA-ENC-TIMESTAMP}} β€” a fresh timestamp {{encryption|encrypted}} under her long-term key β€” proving she knows the password before the {{kerberos-kdc|KDC}} bothers responding.", + 1: "{{kerberos-as-rep|AS-REP}} carries two things: a {{kerberos-tgt|Ticket Granting Ticket}} {{encryption|encrypted}} under the {{kerberos-krbtgt|krbtgt}} {{kerberos-principal|principal}}'s key (only the {{kerberos-kdc|KDC}} can decrypt it later), and the session key encrypted under Alice's long-term key (only Alice can decrypt). Alice never sends her password.", + 3: "For each service Alice wants to use, she sends a {{kerberos-tgs-req|TGS-REQ}} to the {{kerberos-kdc|KDC}}'s {{kerberos-tgs|Ticket Granting Service}}: her {{kerberos-tgt|TGT}} (proves who she is) + a fresh {{kerberos-authenticator|authenticator}} {{encryption|encrypted}} under her {{kerberos-tgt|TGT}}'s session key (proves she just got it).", + 4: "{{kerberos-tgs-rep|TGS-REP}} returns a {{kerberos-service-ticket|service ticket}} {{encryption|encrypted}} under web1's long-term key (so only web1 can decrypt it), plus the new client↔service session key encrypted under the {{kerberos-tgt|TGT}}'s session key (so only Alice can decrypt it).", + 6: "{{kerberos-ap-req|AP-REQ}} β€” Alice connects to web1 and presents the {{kerberos-service-ticket|service ticket}} plus a fresh {{kerberos-authenticator|authenticator}}. The service ticket carries Alice's identity inside the {{encryption|encrypted}} blob; web1 doesn't need to talk to the {{kerberos-kdc|KDC}} to verify.", + 7: "web1 decrypts the ticket with its {{kerberos-keytab|keytab}} key, extracts K_svc, decrypts the {{kerberos-authenticator|authenticator}}. If `ctime` is within Β±5 minutes of web1's clock and the authenticator hasn't been seen before, Alice is authenticated.", 8: '{{kerberos-ap-rep|AP-REP}} β€” web1 returns an {{encryption|encrypted}} timestamp proving it also knows K_svc. This is {{mtls|mutual authentication}}: Alice now knows web1 is real (not an impostor with a stolen {{kerberos-tgt|TGT}}).' } }, @@ -1400,8 +1400,8 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { steps: { 0: 'Random Access β€” {{ue|UE}} chose a cell from {{ssb|SSB}} measurements, sent a {{prach|PRACH}} preamble (Msg1). {{gnb|Base station}} replied with a Random Access Response (Msg2) carrying timing advance and a temporary identifier ({{c-rnti|C-RNTI}}).', 2: '{{ue|UE}} sends RRCSetupRequest with an establishment cause. {{gnb|Base station}} responds with RRCSetup. UE now has SRB1 (signalling radio bearer) but no security yet β€” {{rrc|RRC}} signalling is established but unprotected.', - 4: 'Registration Request carries the {{suci|SUCI}} β€” the [[ip|IP]] address of every cell phone\'s long-term identity ({{supi|SUPI}}), encrypted with the home network\'s public key (ECIES Profile A on Curve25519 β€” never sent in clear).', - 6: '{{5g-aka|5G-AKA}} β€” {{amf|AMF}} asks {{ausf|AUSF}}, AUSF asks {{udm|UDM}}. The UDM\'s SIDF decrypts {{suci|SUCI}} β†’ {{supi|SUPI}}, generates an authentication vector. RAND/AUTN traverse all the way down to the {{ue|UE}}. The {{sim-usim|USIM}} checks AUTN.MAC against `f1(K, SQN, RAND)`, computes RES* via `KDF(CK || IK)`. AUSF compares RES* to HRES*. Mutual authentication achieved.', + 4: "Registration Request carries the {{suci|SUCI}} β€” the [[ip|IP]] address of every cell phone's long-term identity ({{supi|SUPI}}), encrypted with the home network's public key (ECIES Profile A on Curve25519 β€” never sent in clear).", + 6: "{{5g-aka|5G-AKA}} β€” {{amf|AMF}} asks {{ausf|AUSF}}, AUSF asks {{udm|UDM}}. The UDM's SIDF decrypts {{suci|SUCI}} β†’ {{supi|SUPI}}, generates an authentication vector. RAND/AUTN traverse all the way down to the {{ue|UE}}. The {{sim-usim|USIM}} checks AUTN.MAC against `f1(K, SQN, RAND)`, computes RES* via `KDF(CK || IK)`. AUSF compares RES* to HRES*. Mutual authentication achieved.", 8: '{{nas|NAS}} Security Mode β€” {{amf|AMF}} picks ciphering (typically 128-NEA2 = AES-CTR) and integrity (128-NIA2 = AES-CMAC). From here every NAS message is integrity-protected and ciphered with K_NASint / K_NASenc.', 10: 'Registration Accept carries the assigned {{guti|5G-GUTI}} (the temporary identity the {{ue|UE}} will use until next rekey) and the allowed {{nssai|NSSAI}} (network slices).', 12: '{{ue|UE}} requests a {{pdu-session|PDU Session}} β€” what the rest of the world would call "give me an [[ip|IP]] address." {{dnn|DNN}} ("internet"), session type (IPv4v6), requested {{nssai|S-NSSAI}}.', @@ -1463,9 +1463,9 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { caption: '**[[wireguard|WireGuard]]** = one round-trip Noise_IKpsk2 {{handshake|handshake}} β†’ encrypted [[ip|IP]] packets over [[udp|UDP]]. Exactly four message types, exactly one ciphersuite (`Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s`). Designed by [[pioneer:jason-donenfeld|Jason Donenfeld]] (2015–2016), mainlined in {{linux|Linux}} 5.6 (29 March 2020).', steps: { - 0: 'Before any traffic flows, each {{peer|peer}} already knows the other\'s 32-byte {{curve25519|Curve25519}} {{public-key|public key}}. There is no {{certificate|certificate}} exchange, no {{pki|PKI}}, no negotiation. The {{public-key|public key}} *is* the identity.', - 1: '{{wg-handshake-initiation|Handshake Initiation}} (type=1) β€” 148 bytes. Carries the initiator\'s {{wg-ephemeral-key|ephemeral pubkey}}, an {{aead|AEAD}}-{{encryption|encrypted}} copy of its static {{public-key|pubkey}} (hides sender identity from passive observers), and a {{wg-tai64n|TAI64N}} timestamp. {{wg-mac1|`MAC1`}} proves the initiator knows the responder\'s {{public-key|pubkey}} (anti-amplification). {{wg-mac2|`MAC2`}} is a cookie under DoS load.', - 3: '{{wg-handshake-response|Handshake Response}} (type=2) β€” 92 bytes. The responder\'s {{wg-ephemeral-key|ephemeral pubkey}}, an {{aead|AEAD}}-{{encryption|encrypted}} empty payload (proves key agreement), and the same {{wg-mac1|MAC1}}/{{wg-mac2|MAC2}} pair. Completes the four-{{diffie-hellman|DH}} {{noise-ik|Noise_IK}} pattern (plus optional {{psk|PSK}} mix).', + 0: "Before any traffic flows, each {{peer|peer}} already knows the other's 32-byte {{curve25519|Curve25519}} {{public-key|public key}}. There is no {{certificate|certificate}} exchange, no {{pki|PKI}}, no negotiation. The {{public-key|public key}} *is* the identity.", + 1: "{{wg-handshake-initiation|Handshake Initiation}} (type=1) β€” 148 bytes. Carries the initiator's {{wg-ephemeral-key|ephemeral pubkey}}, an {{aead|AEAD}}-{{encryption|encrypted}} copy of its static {{public-key|pubkey}} (hides sender identity from passive observers), and a {{wg-tai64n|TAI64N}} timestamp. {{wg-mac1|`MAC1`}} proves the initiator knows the responder's {{public-key|pubkey}} (anti-amplification). {{wg-mac2|`MAC2`}} is a cookie under DoS load.", + 3: "{{wg-handshake-response|Handshake Response}} (type=2) β€” 92 bytes. The responder's {{wg-ephemeral-key|ephemeral pubkey}}, an {{aead|AEAD}}-{{encryption|encrypted}} empty payload (proves key agreement), and the same {{wg-mac1|MAC1}}/{{wg-mac2|MAC2}} pair. Completes the four-{{diffie-hellman|DH}} {{noise-ik|Noise_IK}} pattern (plus optional {{psk|PSK}} mix).", 4: 'Both sides now hold matching **{{chacha20-poly1305|ChaCha20-Poly1305}}** sending and receiving keys, derived from a chaining key via {{kdf|HKDF}}. The chaining key is wiped from memory β€” there is no "session state" beyond the {{symmetric-encryption|symmetric keys}}.', 5: '{{wg-transport-data|Transport Data}} (type=4) β€” every inner [[ip|IP]] {{packet|packet}} is wrapped in a 16-byte [[wireguard|WireGuard]] {{header|header}} (type, receiver-index, 64-bit counter) plus the {{aead|AEAD}} ciphertext + 16-byte {{poly1305|Poly1305}} tag. The counter doubles as the {{aead|AEAD}} {{nonce|nonce}} *and* the {{anti-replay|anti-replay}} {{sequence-number|sequence number}}.', 7: '**`REKEY_AFTER_TIME` = 120 s forces a fresh {{handshake|handshake}}. Old keys are wiped. Per-message {{forward-secrecy|forward secrecy}} within a session, per-handshake {{forward-secrecy|forward secrecy}}** across sessions. Silent {{peer|peers}} are torn down at `REJECT_AFTER_TIME = 180 s`.', @@ -1495,7 +1495,7 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { caption: '**[[ipsec|IPsec]]** = network-layer cryptographic envelope. **{{ikev2|IKEv2}}** negotiates keys ([[rfc:7296|RFC 7296]]); **{{esp|ESP}}** carries encrypted/authenticated [[ip|IP]] packets ([[rfc:4303|RFC 4303]]). Two round trips bring a tunnel up; **{{ipsec-create-child-sa|CREATE_CHILD_SA}}** rekeys before the lifetime expires.', steps: { - 0: '{{ipsec-ike-sa-init|IKE_SA_INIT}} is the first exchange β€” no {{encryption|encryption}} yet because keys don\'t exist. The initiator proposes a {{cipher-suite|cipher suite}}, sends its {{diffie-hellman|Diffie-Hellman}} / {{ecdh|ECDH}} / {{ml-kem|ML-KEM}} {{public-key|public key}}, a random {{nonce|Nonce}}, and {{ipsec-nat-detection|NAT_DETECTION}} hashes that detect whether either {{peer|peer}} is behind {{nat|NAT}}.', + 0: "{{ipsec-ike-sa-init|IKE_SA_INIT}} is the first exchange β€” no {{encryption|encryption}} yet because keys don't exist. The initiator proposes a {{cipher-suite|cipher suite}}, sends its {{diffie-hellman|Diffie-Hellman}} / {{ecdh|ECDH}} / {{ml-kem|ML-KEM}} {{public-key|public key}}, a random {{nonce|Nonce}}, and {{ipsec-nat-detection|NAT_DETECTION}} hashes that detect whether either {{peer|peer}} is behind {{nat|NAT}}.", 1: 'Responder picks one proposal from `SAi1`, replies with its own KE / {{nonce|Nonce}}, and optionally requests a {{certificate|certificate}} (`CERT_REQ`). After this exchange both sides derive {{ipsec-skeyseed|SKEYSEED}} and the {{ike-sa|IKE SA}} key material β€” every subsequent exchange is {{ike|IKE}}-{{encryption|encrypted}}.', 3: '{{ipsec-ike-intermediate|IKE_INTERMEDIATE}} ([[rfc:9242|RFC 9242]]) was added because {{post-quantum|post-quantum}} {{public-key|public keys}} ({{ml-kem|ML-KEM-1024}} = 1,568 bytes) overflow common [[udp|UDP]] {{mtu|MTUs}} if shipped in {{ipsec-ike-sa-init|IKE_SA_INIT}}. It runs *inside* the {{ike-sa|IKE SA}}, before identity is revealed, and can chain additional {{kem|KEMs}} per [[rfc:9370|RFC 9370]].', 5: '{{ipsec-ike-auth|IKE_AUTH}} carries the identity (`IDi`, `IDr`) and authenticates the {{ipsec-ike-sa-init|IKE_SA_INIT}} exchange β€” usually with an {{rsa|RSA}} / {{ecdsa|ECDSA}} {{certificate|certificate}} (`CERT` + `AUTH`), sometimes with a {{psk|PSK}} or {{eap|EAP}} method. The first **{{child-sa|Child SA}}** (an {{esp|ESP}} one-direction key) is negotiated in the same exchange via `SAi2` / `TSi` / `TSr`.', @@ -1563,11 +1563,11 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { '**[[ospf|OSPF]]** = Open Shortest Path First. Two routers walk the eight-state {{adjacency|adjacency}} machine β€” **Down β†’ Init β†’ 2-Way β†’ ExStart β†’ {{exchange|Exchange}} β†’ Loading β†’ Full** β€” synchronise an identical link-state database, then independently run [[pioneer:edsger-dijkstra|Dijkstra]] ([[rfc:2328|RFC 2328]] / STD 54).', steps: { 0: '{{ospf-hello|Hello}} packets are {{multicast|multicast}} to `224.0.0.5` ([[ipv6|IPv6]]: `FF02::5`) every 10 s on point-to-point links. They carry the {{router-id|router ID}}, the neighbours it currently sees, and the HelloInterval / DeadInterval that the other side must match exactly.', - 1: 'R1 sees the {{ospf-hello|Hello}} but R2 isn\'t listed in its neighbours field yet β€” {{adjacency|adjacency}} is one-way. State: `Init`.', - 3: 'Once both {{ospf-hello|Hellos}} list each other (`Nbrs=[2.2.2.2]` ↔ `Nbrs=[1.1.1.1]`), the {{adjacency|adjacency}} goes **`2-Way`** β€” both sides agree they\'re talking.', + 1: "R1 sees the {{ospf-hello|Hello}} but R2 isn't listed in its neighbours field yet β€” {{adjacency|adjacency}} is one-way. State: `Init`.", + 3: "Once both {{ospf-hello|Hellos}} list each other (`Nbrs=[2.2.2.2]` ↔ `Nbrs=[1.1.1.1]`), the {{adjacency|adjacency}} goes **`2-Way`** β€” both sides agree they're talking.", 5: '{{dbd|DBD = Database Description}}. The `MS` bit elects master/slave (higher {{router-id|RID}} wins); `I` is the init bit; `M` says more {{dbd|DBDs}} follow. Master controls the {{sequence-number|sequence number}}.', 7: 'Subsequent {{dbd|DBDs}} carry {{lsa|LSA}} headers β€” just sequence/age/{{checksum|checksum}}, not the full {{lsa|LSA}}. Each side learns which {{lsa|LSAs}} the *other* has.', - 9: '{{lsr|LSR = Link State Request}}. R1 asks for the {{lsa|LSAs}} it doesn\'t have or whose copies are older.', + 9: "{{lsr|LSR = Link State Request}}. R1 asks for the {{lsa|LSAs}} it doesn't have or whose copies are older.", 10: '{{lsu|LSU = Link State Update}}. R2 sends the actual {{lsa|LSAs}}. Every {{lsa|LSA}} is {{checksum|checksummed}}, age-stamped, and sequence-numbered.', 11: '{{lsack|LSAck}} is mandatory β€” [[ospf|OSPF]] implements reliable delivery on top of raw [[ip|IP]] (protocol 89), without [[tcp|TCP]]. Unacked {{lsa|LSAs}} are {{retransmission|retransmitted}} every RxmtInterval (5 s default).', 12: 'State **`Full`. Both routers have identical {{lsdb|LSDBs}}. Each independently runs [[pioneer:edsger-dijkstra|Dijkstra]]** on the topology graph, installs the resulting tree into its {{fib|FIB}}, and starts forwarding.' @@ -1599,7 +1599,7 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { steps: { 0: 'Before any check fires, each peer enumerates every address it might be reachable on: local {{lan|LAN}} interfaces (host), the {{public-ip-address|public address}} it reaches the world through (server-reflexive via {{stun|STUN}}), and a {{turn|TURN}}-allocated public relay (relayed).', 1: '{{binding-request|STUN Binding Request}} β€” 20-byte header, magic cookie `0x2112A442`, random 96-bit transaction ID, zero attributes. The smallest useful packet on the modern internet.', - 2: 'The {{stun|STUN}} server replies with **`{{xor-mapped-address|XOR-MAPPED-ADDRESS}}`** β€” the source `ip:port` it observed, XORed against the magic cookie so middleboxes can\'t rewrite it. That\'s your *server-reflexive {{ice-candidate|candidate}}*.', + 2: "The {{stun|STUN}} server replies with **`{{xor-mapped-address|XOR-MAPPED-ADDRESS}}`** β€” the source `ip:port` it observed, XORed against the magic cookie so middleboxes can't rewrite it. That's your *server-reflexive {{ice-candidate|candidate}}*.", 3: '**{{turn|TURN}} `Allocate`** request reserves a public `ip:port` on the relay. The client authenticates with long-term creds (username/realm/{{nonce|nonce}}/{{hmac|HMAC-SHA256}}). Default lifetime: 600 s.', 4: 'The relay returns **`{{xor-relayed-address|XOR-RELAYED-ADDRESS}}`** β€” a public {{socket|socket}} Bob can hit. This is the fallback path when nothing direct works.', 5: 'Trickle {{ice|ICE}} ([[rfc:8838|RFC 8838]]): {{ice-candidate|candidates}} are signalled as they appear, not after all gathering finishes. Cuts call-setup time by hundreds of milliseconds.', @@ -1632,7 +1632,7 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { 0: 'The new bulb has no parent. It {{broadcast|broadcasts}} a {{beacon-frame|Beacon Request}} (MAC Cmd 0x07) on the chosen channel. Pick 15, 20, 25, or 26 to avoid [[wifi|Wi-Fi]] channels 1/6/11.', 1: 'Every {{zigbee-router|router}} and the {{zigbee-coordinator|Coordinator}} that permits joining replies with a {{beacon-frame|Beacon}} advertising the {{pan-id|PAN ID}}, the Coordinator {{short-address|short address}} (0x0000), Stack Profile (Zigbee PRO), and the Permit-Joining flag. The {{zigbee-joiner|joiner}} picks by {{rssi|RSSI}} + LQI + capability.', 2: 'Association Request β€” the {{zigbee-joiner|joiner}} asks for a {{short-address|short address}}. Capability byte 0x8E = {{ffd|FFD}}, mains-powered, security-capable, allocate-short.', - 3: 'The {{zigbee-coordinator|Coordinator}} allocates a 16-bit {{short-address|short}} (here 0x3F4E) β€” much cheaper than the 8-byte {{eui-64|EUI-64}} on every {{frame|frame}} for the rest of the device\'s life on this network.', + 3: "The {{zigbee-coordinator|Coordinator}} allocates a 16-bit {{short-address|short}} (here 0x3F4E) β€” much cheaper than the 8-byte {{eui-64|EUI-64}} on every {{frame|frame}} for the rest of the device's life on this network.", 5: '{{aps-layer|APS}} Transport-Key (cmd 0x05) delivers the {{network-key|network key}}, encrypted under the pre-configured link key. With an {{install-code|install code}}, an eavesdropper at join cannot decrypt this; with default *ZigBeeAlliance09*, they can β€” the canonical [[zigbee|Zigbee]] sniffer-at-join attack.', 6: 'Device Announce ({{zigbee-zdo|ZDO}} cluster 0x0013) β€” the {{zigbee-joiner|joiner}} {{broadcast|broadcasts}} its arrival so every {{zigbee-router|router}} can add it to {{routing-table|routing}} and binding tables. From here it is on the {{mesh-network|mesh}}.', 7: '{{zcl|ZCL}} OnOff Toggle (cluster 0x0006, command 0x02) β€” the canonical first command. The whole on-the-wire payload, including all {{ieee-802-15-4|802.15.4}} + {{zigbee-nwk|NWK}} + {{aps-layer|APS}} + {{zcl|ZCL}} headers, fits in ~40 bytes.' @@ -1654,16 +1654,16 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { Note over A: Compute ToF via DS-TWR cross-product<br/>distance β‰ˆ 1.41 m A->>P: BLE: distance + bearing β†’ Unlock`, caption: - "**[[uwb|UWB]] {{ds-twr|DS-TWR}}** = the secure ranging flow under AirTag Precision Finding, BMW Digital Key, and {{aliro|Aliro}} hands-free unlock. [[bluetooth|BLE]] does the bootstrap (auth + STS_KEY transport); [[uwb|UWB]] does the three-message ranging {{exchange|exchange}}; the cross-product cancels {{clock-drift|clock drift}}; **{{sts|STS}}** is the {{aes|AES}}-CTR-generated pulse pattern that makes the distance measurement unforgeable.", + '**[[uwb|UWB]] {{ds-twr|DS-TWR}}** = the secure ranging flow under AirTag Precision Finding, BMW Digital Key, and {{aliro|Aliro}} hands-free unlock. [[bluetooth|BLE]] does the bootstrap (auth + STS_KEY transport); [[uwb|UWB]] does the three-message ranging {{exchange|exchange}}; the cross-product cancels {{clock-drift|clock drift}}; **{{sts|STS}}** is the {{aes|AES}}-CTR-generated pulse pattern that makes the distance measurement unforgeable.', steps: { 0: 'Every consumer [[uwb|UWB]] session starts on [[bluetooth|BLE]]. The anchor advertises its service UUID; the phone discovers it. UWB is not yet powered β€” saves battery.', - 1: '[[bluetooth|BLE]] {{gatt|GATT}} pairing + application-specific authentication. SPAKE2+/{{pake|PAKE}} for {{ccc-digital-key|CCC Digital Key}}; {{apple|Apple}}\'s proprietary {{handshake|handshake}} for Find My; ECDSA {{mtls|mutual auth}} for {{aliro|Aliro 1.0}}.', + 1: "[[bluetooth|BLE]] {{gatt|GATT}} pairing + application-specific authentication. SPAKE2+/{{pake|PAKE}} for {{ccc-digital-key|CCC Digital Key}}; {{apple|Apple}}'s proprietary {{handshake|handshake}} for Find My; ECDSA {{mtls|mutual auth}} for {{aliro|Aliro 1.0}}.", 2: 'The STS_KEY (128-bit {{aes-gcm|AES}} key) and ranging schedule are transferred over the [[bluetooth|BLE]] {{encryption|encrypted}} channel. Without this key, the [[uwb|UWB]] ranging frames look like noise to any other receiver.', 3: 'Poll β€” Phone fires [[uwb|UWB]] on Channel 9 (7987.2 MHz, 499.2 MHz BW). The 32-chip {{sts|STS}} segment is the AES-CTR-generated pulse pattern that defeats the distance-decrease attack. The phone records `t1 = TX timestamp` at the {{sfd|SFD}} (~15 ps resolution).', 4: 'Response β€” Anchor RX-timestamps the Poll at t2, deliberately delays by T_reply1 (~200 Β΅s), then transmits Response carrying t2, t3. Phone records `t4 = RX timestamp`.', 5: 'Final β€” Phone delays by T_reply2 and transmits Final carrying t1, t4, t5. Anchor records `t6 = RX`. All six timestamps now exist.', 6: 'The {{ds-twr|DS-TWR}} cross-product cancels relative clock drift to first order. {{tof-ranging|ToF}} resolved to ~1 ns β‰ˆ 30 cm; with multipath and {{sts|STS}} valid, real-world DS-TWR achieves 10–30 cm distance accuracy and ~5 cm standard deviation.', - 8: 'Distance + bearing returned over [[bluetooth|BLE]]. {{apple|Apple}}\'s {{nearby-interaction|Nearby Interaction}} framework refreshes at ~10 Hz; the haptic + display guide the user. For {{ccc-digital-key|Digital Key}}, distance ≀ threshold + valid credential β†’ Unlock.' + 8: "Distance + bearing returned over [[bluetooth|BLE]]. {{apple|Apple}}'s {{nearby-interaction|Nearby Interaction}} framework refreshes at ~10 Hz; the haptic + display guide the user. For {{ccc-digital-key|Digital Key}}, distance ≀ threshold + valid credential β†’ Unlock." } }, @@ -1690,7 +1690,7 @@ export const diagramDefinitions: Record<string, DiagramDefinition> = { P->>T: ARQC + ATC + IAD Note over T,P: Terminal β†’ acquirer β†’ issuer β†’ ARPC: APPROVED`, caption: - "**[[nfc|NFC]]** = Near Field Communication. The same nine beats β€” {{anti-collision|anti-collision}} β†’ {{rats|RATS}}/{{ats-nfc|ATS}} β†’ {{imap-select|SELECT}} {{ppse|PPSE}} β†’ {{select-aid|SELECT AID}} β†’ {{gpo|GPO}} β†’ {{read-record|READ RECORD}} β†’ {{generate-ac|GENERATE AC}} β€” that every {{apple|Apple}} Pay, {{google|Google}} Wallet, {{transit|transit}} gate, and plastic contactless card runs through in under half a second ({{iso-iec|ISO/IEC}} 14443 + {{iso-iec|ISO/IEC}} 7816-4 + EMVCo Contactless Book C-2).", + '**[[nfc|NFC]]** = Near Field Communication. The same nine beats β€” {{anti-collision|anti-collision}} β†’ {{rats|RATS}}/{{ats-nfc|ATS}} β†’ {{imap-select|SELECT}} {{ppse|PPSE}} β†’ {{select-aid|SELECT AID}} β†’ {{gpo|GPO}} β†’ {{read-record|READ RECORD}} β†’ {{generate-ac|GENERATE AC}} β€” that every {{apple|Apple}} Pay, {{google|Google}} Wallet, {{transit|transit}} gate, and plastic contactless card runs through in under half a second ({{iso-iec|ISO/IEC}} 14443 + {{iso-iec|ISO/IEC}} 7816-4 + EMVCo Contactless Book C-2).', steps: { 0: 'The terminal energises the 13.56 MHz magnetic carrier continuously. When the phone is within ~4 cm, the {{ese|eSE}} harvests power inductively and wakes β€” no battery contribution needed.', 1: '{{reqa|REQA}} = `0x26`, a 7-bit short {{frame|frame}}. Any IDLE Type A {{picc|PICC}} in the field transitions to READY.', diff --git a/src/lib/data/frontier.ts b/src/lib/data/frontier.ts index c99a5fa..888c104 100644 --- a/src/lib/data/frontier.ts +++ b/src/lib/data/frontier.ts @@ -65,14 +65,20 @@ export const frontierEntries: FrontierEntry[] = [ The economics that finally tipped it: {{aws|AWS}} started charging $0.005/hour per public [[ip|IPv4]] address in February 2024, making [[ipv6|IPv6]]-only architectures financially compelling at scale. Combined with {{four-six-four-xlat|464XLAT}} being a first-class citizen in modern {{android|Android}}, iOS 9+, macOS 13+, and Windows 11, [[ipv6|IPv6]]-only access networks now Just Work for [[ip|IPv4]] applications too.`, metrics: [ - { label: "Google peak", value: '50.1%', date: '2026-03-28' }, + { label: 'Google peak', value: '50.1%', date: '2026-03-28' }, { label: 'Cloudflare HTTP', value: '40%', date: '2026-04' }, { label: 'APNIC capable', value: '43.13%', date: '2026-04' }, { label: 'US mobile avg', value: '~87%' } ], sources: [ - { url: 'https://www.google.com/intl/en/ipv6/statistics.html', label: 'Google IPv6 statistics' }, - { url: 'https://blog.apnic.net/2026/04/28/google-hits-50-ipv6/', label: 'APNIC β€” Google hits 50% IPv6' } + { + url: 'https://www.google.com/intl/en/ipv6/statistics.html', + label: 'Google IPv6 statistics' + }, + { + url: 'https://blog.apnic.net/2026/04/28/google-hits-50-ipv6/', + label: 'APNIC β€” Google hits 50% IPv6' + } ] }, { @@ -115,7 +121,10 @@ The economics that finally tipped it: {{aws|AWS}} started charging $0.005/hour p ], sources: [ { url: 'https://github.com/google/bbr', label: 'google/bbr GitHub repo' }, - { url: 'https://datatracker.ietf.org/doc/draft-ietf-ccwg-bbr/', label: 'IETF β€” draft-ietf-ccwg-bbr' } + { + url: 'https://datatracker.ietf.org/doc/draft-ietf-ccwg-bbr/', + label: 'IETF β€” draft-ietf-ccwg-bbr' + } ] }, { @@ -131,7 +140,10 @@ The economics that finally tipped it: {{aws|AWS}} started charging $0.005/hour p The mechanism: cooperating senders mark packets {{ecn|ECN}}-Capable; routers running the DualQ Coupled {{aqm|AQM}} mark instead of dropping when congestion is incipient; senders react to marks like minor losses without backing off as hard. The result is {{bufferbloat|bufferbloat}} avoided in real time: {{latency|latency}}-sensitive apps (cloud gaming, video calls) get the headroom they need without starving classic [[tcp|TCP]]. {{apple|Apple}} shipped {{l4s|L4S}} support in iOS 17, iPadOS 17, macOS Sonoma and tvOS 17 in 2023, on by default for [[quic|QUIC]] in newer releases.`, sources: [ - { url: 'https://www.rcrwireless.com/20250129/uncategorized/comcast-l4s', label: 'RCR Wireless β€” Comcast L4S launch' }, + { + url: 'https://www.rcrwireless.com/20250129/uncategorized/comcast-l4s', + label: 'RCR Wireless β€” Comcast L4S launch' + }, { url: 'https://www.nokia.com/bell-labs/research/l4s/', label: 'Nokia Bell Labs β€” L4S' } ] }, @@ -148,8 +160,14 @@ The mechanism: cooperating senders mark packets {{ecn|ECN}}-Capable; routers run {{cloudflare|Cloudflare}} deploys {{ech|ECH}} for ~70% of websites it fronts; Chrome and Firefox both support it. The architecture: the server publishes an ECHConfig in [[dns|DNS]] (HTTPS RR); the client encrypts the inner {{client-hello|ClientHello}} to that key and wraps it in an outer {{client-hello|ClientHello}} that uses a generic "{{cloudflare|cloudflare}}-ech.com" {{sni|SNI}}. From the network's perspective, every fronted site looks the same.`, sources: [ - { url: 'https://www.feistyduck.com/newsletter/issue_127_encrypted_client_hello_approved_for_publication.html', label: 'Feisty Duck β€” ECH approved for publication' }, - { url: 'https://www.cisecurity.org/insights/blog/security-control-changes-due-to-tls-encrypted-clienthello', label: 'CISecurity β€” security control changes due to ECH' } + { + url: 'https://www.feistyduck.com/newsletter/issue_127_encrypted_client_hello_approved_for_publication.html', + label: 'Feisty Duck β€” ECH approved for publication' + }, + { + url: 'https://www.cisecurity.org/insights/blog/security-control-changes-due-to-tls-encrypted-clienthello', + label: 'CISecurity β€” security control changes due to ECH' + } ] }, { @@ -169,7 +187,10 @@ The mechanism: cooperating senders mark packets {{ecn|ECN}}-Capable; routers run { label: 'Traffic bound for RPKI-secured destinations', value: '~75%', date: '2024' } ], sources: [ - { url: 'https://manrs.org/2024/05/rpki-rov-deployment-reaches-major-milestone/', label: 'MANRS β€” RPKI ROV milestone' }, + { + url: 'https://manrs.org/2024/05/rpki-rov-deployment-reaches-major-milestone/', + label: 'MANRS β€” RPKI ROV milestone' + }, { url: 'https://blog.cloudflare.com/rpki-updates-data/', label: 'Cloudflare β€” RPKI Updates' } ] }, @@ -208,7 +229,10 @@ The [[wifi|Wi-Fi]] Alliance opened certification on 8 January 2024. As of late A {{ai|AI}} training fabrics are the demand engine. "Lossless [[ethernet|Ethernet]]" with RoCEv2 β€” [[ethernet|Ethernet]] plus PFC + DCQCN for losslessness β€” is replacing InfiniBand in many large {{gpu|GPU}} clusters because the operational tooling, vendor diversity, and per-port economics are all better. The Ultra [[ethernet|Ethernet]] Consortium's {{uec|UEC}} 1.0 spec (June 2025) is the next step: a new transport for {{ai|AI}}/HPC scale-out built on plain [[ethernet|Ethernet]]+[[ip|IP]] that explicitly competes with InfiniBand and RoCEv2.`, sources: [ { url: 'https://www.ieee802.org/3/dj/index.html', label: 'IEEE P802.3dj task force' }, - { url: 'https://en.wikipedia.org/wiki/Terabit_Ethernet', label: 'Wikipedia β€” Terabit Ethernet' } + { + url: 'https://en.wikipedia.org/wiki/Terabit_Ethernet', + label: 'Wikipedia β€” Terabit Ethernet' + } ] }, { @@ -225,7 +249,10 @@ The [[wifi|Wi-Fi]] Alliance opened certification on 8 January 2024. As of late A AMD's Pensando Pollara 400 is the first shipping {{nic|NIC}}. The likely RoCEv2 successor for the next generation of {{gpu|GPU}} clusters β€” at the scale of 100K+ accelerators training a single model, the assumptions baked into RoCEv2 (single-path, lossless via PFC, no out-of-order) become liabilities.`, sources: [ { url: 'https://ultraethernet.org/', label: 'Ultra Ethernet Consortium' }, - { url: 'https://arxiv.org/html/2508.08906v1', label: 'Hoefler et al. β€” Ultra Ethernet design principles' } + { + url: 'https://arxiv.org/html/2508.08906v1', + label: 'Hoefler et al. β€” Ultra Ethernet design principles' + } ] }, { @@ -241,7 +268,10 @@ AMD's Pensando Pollara 400 is the first shipping {{nic|NIC}}. The likely RoCEv2 Use cases: aggregating [[wifi|Wi-Fi]] and cellular {{bandwidth|bandwidth}} on a phone ({{apple|Apple}} already does this with [[mptcp|MPTCP]] for Siri), seamless network handover when the user changes interfaces, reaching a multi-homed server through whichever path is fastest. The {{3gpp|3GPP}} ATSSS standard for 5G already specifies [[mptcp|MPTCP]] and MPQUIC for traffic steering between cellular and [[wifi|Wi-Fi]].`, sources: [ - { url: 'https://datatracker.ietf.org/doc/html/draft-ietf-quic-multipath', label: 'IETF β€” draft-ietf-quic-multipath' } + { + url: 'https://datatracker.ietf.org/doc/html/draft-ietf-quic-multipath', + label: 'IETF β€” draft-ietf-quic-multipath' + } ] }, { @@ -257,7 +287,10 @@ Use cases: aggregating [[wifi|Wi-Fi]] and cellular {{bandwidth|bandwidth}} on a The architecture: publishers send named objects to MoQ relays; subscribers {{imap-fetch|fetch}} named objects from the nearest relay, with hop-by-hop [[quic|QUIC]]. Object naming + [[quic|QUIC]] stream {{multiplexing|multiplexing}} mean a relay can drop objects under congestion (preserve key frames over delta frames) without the publisher coordinating. [[webrtc|WebRTC]]'s lunch may finally be eaten for one-to-many use cases.`, sources: [ - { url: 'https://datatracker.ietf.org/doc/draft-ietf-moq-transport/', label: 'IETF β€” draft-ietf-moq-transport' }, + { + url: 'https://datatracker.ietf.org/doc/draft-ietf-moq-transport/', + label: 'IETF β€” draft-ietf-moq-transport' + }, { url: 'https://blog.cloudflare.com/moq/', label: 'Cloudflare β€” MoQ' } ] }, @@ -274,15 +307,21 @@ The architecture: publishers send named objects to MoQ relays; subscribers {{ima Streamable {{http-method|HTTP}} is one HTTP endpoint that can return either a single [[json-rpc|JSON-RPC]] response or upgrade to [[sse|SSE]] for streaming. Single channel, simpler proxy story, easier to deploy on serverless. Combined with the 2025-03-26 spec adding [[oauth2|OAuth]] 2.1 with {{pkce|PKCE}} and dynamic client registration plus Resource Indicators ({{rfc-doc|RFC}} 8707) for token scoping, [[mcp|MCP]] is now a real internet protocol β€” not just a local {{stdio|stdio}} convention.`, sources: [ - { url: 'https://modelcontextprotocol.io/specification/2025-11-25/basic/transports', label: 'MCP spec β€” transports' }, - { url: 'https://stackoverflow.blog/2026/01/21/is-that-allowed-authentication-and-authorization-in-model-context-protocol/', label: 'Stack Overflow blog β€” MCP auth' } + { + url: 'https://modelcontextprotocol.io/specification/2025-11-25/basic/transports', + label: 'MCP spec β€” transports' + }, + { + url: 'https://stackoverflow.blog/2026/01/21/is-that-allowed-authentication-and-authorization-in-model-context-protocol/', + label: 'Stack Overflow blog β€” MCP auth' + } ] }, { id: 'a2a-linux-foundation', title: 'A2A Donated to the Linux Foundation', oneLiner: - '{{google|Google}}\'s Agent2Agent protocol joins [[mcp|MCP]] under open governance β€” the second {{ai|AI}}-agent protocol to find a foundation home.', + "{{google|Google}}'s Agent2Agent protocol joins [[mcp|MCP]] under open governance β€” the second {{ai|AI}}-agent protocol to find a foundation home.", topic: 'ai-agents', status: 'shipped', date: '2025-06', @@ -291,7 +330,10 @@ Streamable {{http-method|HTTP}} is one HTTP endpoint that can return either a si In December 2025 {{anthropic|Anthropic}} donated [[mcp|MCP]] to the Agentic {{ai|AI}} Foundation (AAIF), a {{linux|Linux}} Foundation directed fund co-founded by {{anthropic|Anthropic}}, Block, and OpenAI. [[mcp|MCP]] and [[a2a|A2A]] are now under the same umbrella. Mid-2026 industry analyses report [[mcp|MCP]] at ~78% enterprise adoption vs [[a2a|A2A]] at ~23% β€” the boundary between "agent" and "tool" remains fuzzy and the multi-agent collaboration use cases are still emerging.`, sources: [ - { url: 'https://www.linuxfoundation.org/press/linux-foundation-launches-the-agent2agent-protocol-project-to-enable-secure-intelligent-communication-between-ai-agents', label: 'Linux Foundation β€” A2A project' }, + { + url: 'https://www.linuxfoundation.org/press/linux-foundation-launches-the-agent2agent-protocol-project-to-enable-secure-intelligent-communication-between-ai-agents', + label: 'Linux Foundation β€” A2A project' + }, { url: 'https://en.wikipedia.org/wiki/Model_Context_Protocol', label: 'Wikipedia β€” MCP' } ] } diff --git a/src/lib/data/journeys.ts b/src/lib/data/journeys.ts index ce87ab3..a4d3aeb 100644 --- a/src/lib/data/journeys.ts +++ b/src/lib/data/journeys.ts @@ -30,22 +30,25 @@ export const journeys: Journey[] = [ protocolId: 'dns', title: 'DNS Resolution', description: - 'Before your browser can reach {{google|google}}.com, it needs an actual address β€” like needing a street address before you can mail a letter. Your device sends a [[dns|DNS]] query to a {{recursive-resolver|recursive resolver}}, which walks the [[dns|DNS]] hierarchy: root servers, then .com {{tld|TLD}} servers, then {{google|google}}.com\'s {{authoritative-nameserver|authoritative nameserver}}. The answer (e.g., 142.250.80.46) is cached locally so future requests skip this entire chain. Without [[dns|DNS]], you would have to memorize raw [[ip|IP]] addresses for every website you visit.', - transition: 'The browser now knows WHERE the server lives β€” but packets on the internet can be lost, reordered, or duplicated. Before sending any real data, it needs to negotiate a reliable channel...' + "Before your browser can reach {{google|google}}.com, it needs an actual address β€” like needing a street address before you can mail a letter. Your device sends a [[dns|DNS]] query to a {{recursive-resolver|recursive resolver}}, which walks the [[dns|DNS]] hierarchy: root servers, then .com {{tld|TLD}} servers, then {{google|google}}.com's {{authoritative-nameserver|authoritative nameserver}}. The answer (e.g., 142.250.80.46) is cached locally so future requests skip this entire chain. Without [[dns|DNS]], you would have to memorize raw [[ip|IP]] addresses for every website you visit.", + transition: + 'The browser now knows WHERE the server lives β€” but packets on the internet can be lost, reordered, or duplicated. Before sending any real data, it needs to negotiate a reliable channel...' }, { protocolId: 'tcp', title: 'TCP Handshake', description: 'The internet is inherently unreliable β€” packets can vanish, arrive out of order, or show up twice. [[tcp|TCP]] solves this with a {{three-way-handshake|three-way handshake}} ({{syn-cookies|SYN}}, {{syn-cookies|SYN}}-{{ack|ACK}}, {{ack|ACK}}) that synchronizes sequence numbers between your browser and the server, creating a reliable ordered channel. This {{handshake|handshake}} also negotiates window sizes for {{flow-control|flow control}}, ensuring neither side overwhelms the other. It costs one round trip of {{latency|latency}}, but without it every application would need to implement its own reliability logic.', - transition: 'A reliable pipe now connects your browser to the server β€” but anyone sitting on the network path (your {{isp|ISP}}, a coffee shop router, a government {{firewall|firewall}}) can read every byte in plaintext. The data needs {{encryption|encryption}}...' + transition: + 'A reliable pipe now connects your browser to the server β€” but anyone sitting on the network path (your {{isp|ISP}}, a coffee shop router, a government {{firewall|firewall}}) can read every byte in plaintext. The data needs {{encryption|encryption}}...' }, { protocolId: 'tls', title: 'TLS Negotiation', description: '[[tls|TLS]] is where trust is established. The server presents a {{certificate|certificate}} proving it really is {{google|google}}.com (signed by a trusted {{certificate-authority|certificate authority}}), and both sides negotiate which {{cipher-suite|cipher suite}} to use. They then perform a key {{exchange|exchange}} (typically {{ecdhe|ECDHE}}) to derive shared session keys that only they know β€” even if someone recorded the entire {{handshake|handshake}}. [[tls|TLS]] 1.3 collapses this to a single round trip, and on repeat visits, {{zero-rtt|0-RTT}} resumption can send encrypted data immediately.', - transition: 'The connection is now both reliable and encrypted β€” no eavesdropper can read or tamper with the data. Everything is ready to speak the language of the web...' + transition: + 'The connection is now both reliable and encrypted β€” no eavesdropper can read or tamper with the data. Everything is ready to speak the language of the web...' }, { protocolId: 'http1', @@ -68,28 +71,32 @@ export const journeys: Journey[] = [ title: 'Ethernet Frame', description: 'Every piece of data on a local network travels as an [[ethernet|Ethernet]] frame β€” a precisely structured envelope containing source and destination {{mac-address|MAC}} addresses (48-bit hardware identifiers burned into every network card), a type field that indicates what protocol lives inside ([[ip|IPv4]], [[ipv6|IPv6]], [[arp|ARP]]), and a Frame Check Sequence for error detection. The frame is the physical currency of LANs: switches read the destination {{mac-address|MAC}} to forward it to the correct port. Without this framing, raw electrical signals on the wire would be meaningless noise.', - transition: 'The [[ethernet|Ethernet]] frame needs a destination {{mac-address|MAC address}} β€” but your application only knows an {{ip-address|IP address}}. Something has to bridge the gap between Layer 3 ([[ip|IP]]) and Layer 2 ([[ethernet|Ethernet]])...' + transition: + 'The [[ethernet|Ethernet]] frame needs a destination {{mac-address|MAC address}} β€” but your application only knows an {{ip-address|IP address}}. Something has to bridge the gap between Layer 3 ([[ip|IP]]) and Layer 2 ([[ethernet|Ethernet]])...' }, { protocolId: 'arp', title: 'ARP Resolution', description: '[[arp|ARP]] is the glue between [[ip|IP]] addresses and physical hardware. When your machine needs to reach 192.168.1.1 but only knows its [[ip|IP]], it broadcasts an [[arp|ARP]] request to every device on the {{lan|LAN}}: "Who has 192.168.1.1? Tell me your {{mac-address|MAC address}}." The target replies directly with its {{mac-address|MAC}}, and the result is cached in an [[arp|ARP]] table so future packets skip the {{broadcast|broadcast}}. This is why the first packet to a new host on your {{lan|LAN}} is slightly slower β€” [[arp|ARP]] has to resolve the address first.', - transition: 'With the destination {{mac-address|MAC}} resolved and the [[ethernet|Ethernet]] frame ready, the packet can now be addressed for its journey beyond the local network. The [[ip|IP]] layer takes over to handle global addressing and routing...' + transition: + 'With the destination {{mac-address|MAC}} resolved and the [[ethernet|Ethernet]] frame ready, the packet can now be addressed for its journey beyond the local network. The [[ip|IP]] layer takes over to handle global addressing and routing...' }, { protocolId: 'ip', title: 'IP Routing', description: '[[ip|IP]] is the postal service of the internet β€” it stamps each packet with a source and destination address, then forwards it hop by hop toward its target. Each router along the path examines the destination [[ip|IP]], consults its {{routing-table|routing table}}, decrements the {{ttl|TTL}} ({{ttl|Time To Live}}) by one, and forwards the packet to the next hop. If {{ttl|TTL}} reaches zero, the packet is discarded and an [[icmp|ICMP]] "{{time-exceeded|Time Exceeded}}" is sent back β€” this is how {{traceroute|traceroute}} works. [[ip|IP]] makes no guarantees about delivery order or reliability; it simply does its best to get each packet to the right machine.', - transition: '[[ip|IP]] delivered the packet to the correct machine β€” but a server might be running dozens of applications simultaneously. A web server on port 80, an [[ssh|SSH]] daemon on port 22, a database on port 5432. Something has to deliver the data to the right process...' + transition: + '[[ip|IP]] delivered the packet to the correct machine β€” but a server might be running dozens of applications simultaneously. A web server on port 80, an [[ssh|SSH]] daemon on port 22, a database on port 5432. Something has to deliver the data to the right process...' }, { protocolId: 'tcp', title: 'TCP Delivery', description: '[[tcp|TCP]] is the reliability layer that [[ip|IP]] lacks. It uses 16-bit port numbers (0-65535) to multiplex multiple conversations on the same {{ip-address|IP address}}, delivering each segment to the correct application. Beyond addressing, [[tcp|TCP]] guarantees that data arrives complete, in order, and without duplication β€” it retransmits lost segments, resequences out-of-order arrivals, and uses {{sliding-window|sliding window}} {{flow-control|flow control}} to prevent a fast sender from overwhelming a slow receiver. This reliability is why the web, email, and file transfer all run on [[tcp|TCP]].', - transition: 'The data has been reliably delivered to the correct process on the correct machine. Now the application can finally interpret the bytes using its own protocol semantics...' + transition: + 'The data has been reliably delivered to the correct process on the correct machine. Now the application can finally interpret the bytes using its own protocol semantics...' }, { protocolId: 'http1', @@ -102,7 +109,8 @@ export const journeys: Journey[] = [ { id: 'transport-blocks', title: 'Building Blocks of Transport', - description: 'From raw datagrams to reliable streams β€” the foundational transport protocols and their evolution.', + description: + 'From raw datagrams to reliable streams β€” the foundational transport protocols and their evolution.', color: '#39FF14', scope: 'global', steps: [ @@ -111,27 +119,30 @@ export const journeys: Journey[] = [ title: 'UDP: The Simple Datagram', description: '[[udp|UDP]] is the bare minimum of transport β€” it adds just 8 bytes of overhead (source port, destination port, length, {{checksum|checksum}}) and fires your data into the network with no {{handshake|handshake}}, no acknowledgments, and no ordering guarantees. This makes it blazing fast and perfect for scenarios where speed matters more than perfection: [[dns|DNS]] queries, live video, gaming, and voice calls. If a packet is lost, the application decides whether to care β€” a missing video frame is better than waiting 200ms for a {{retransmission|retransmission}} that arrives too late to display.', - transition: '[[udp|UDP]] gives you raw speed, but many applications cannot tolerate missing or reordered data. A web page with a missing {{css|CSS}} file, a bank transfer with lost bytes, or a file download with gaps β€” these need every byte in the right order. The internet needed a more disciplined transport...' + transition: + '[[udp|UDP]] gives you raw speed, but many applications cannot tolerate missing or reordered data. A web page with a missing {{css|CSS}} file, a bank transfer with lost bytes, or a file download with gaps β€” these need every byte in the right order. The internet needed a more disciplined transport...' }, { protocolId: 'tcp', title: 'TCP: Reliable Streams', description: '[[tcp|TCP]] transforms the unreliable internet into a dependable byte stream. It establishes connections with a {{three-way-handshake|three-way handshake}}, assigns sequence numbers to every byte, requires acknowledgments for received data, and retransmits anything that goes missing. Its {{congestion-control|congestion control}} algorithms (Reno, {{cubic|CUBIC}}, {{bbr|BBR}}) actively probe the network to find the maximum safe sending rate without causing collapse. [[tcp|TCP]] has been the backbone of the internet for over 40 years β€” {{http-method|HTTP}}, email, [[ssh|SSH]], and file transfer all depend on it. The tradeoff is {{latency|latency}}: the {{handshake|handshake}}, acknowledgment delays, and {{head-of-line-blocking|head-of-line blocking}} (one lost packet stalls everything behind it) add up.', - transition: '[[tcp|TCP]] proved that reliability works, but its single-stream design means one lost packet blocks all data behind it β€” even unrelated requests. And its {{handshake|handshake}} adds a full round trip before any data flows. Engineers began asking: can we keep the reliability but eliminate these bottlenecks?' + transition: + '[[tcp|TCP]] proved that reliability works, but its single-stream design means one lost packet blocks all data behind it β€” even unrelated requests. And its {{handshake|handshake}} adds a full round trip before any data flows. Engineers began asking: can we keep the reliability but eliminate these bottlenecks?' }, { protocolId: 'quic', title: 'QUIC: The Modern Fusion', description: '[[quic|QUIC]] is what happens when you redesign transport from scratch with modern needs in mind. It runs on top of [[udp|UDP]] (so it passes through existing firewalls and NATs), but implements its own reliability, ordering, and {{congestion-control|congestion control}} internally. Crucially, [[quic|QUIC]] supports multiplexed independent streams β€” so a lost packet on stream 3 does not block streams 1, 2, or 4. It also bakes in [[tls|TLS]] 1.3 {{encryption|encryption}} from the start, merging the transport and security handshakes into a single round trip. On repeat connections, {{zero-rtt|0-RTT}} resumption lets you send data immediately. [[quic|QUIC]] powers [[http3|HTTP/3]] and is rapidly becoming the new default transport for the web.', - transition: '[[quic|QUIC]] solves {{head-of-line-blocking|head-of-line blocking}} and connection setup {{latency|latency}} brilliantly, but it assumes a single network path. What happens when a device has multiple network interfaces β€” [[wifi|WiFi]] and cellular, two [[ethernet|Ethernet]] ports, or a wired and wireless backup link? There is a transport designed for exactly that scenario...' + transition: + '[[quic|QUIC]] solves {{head-of-line-blocking|head-of-line blocking}} and connection setup {{latency|latency}} brilliantly, but it assumes a single network path. What happens when a device has multiple network interfaces β€” [[wifi|WiFi]] and cellular, two [[ethernet|Ethernet]] ports, or a wired and wireless backup link? There is a transport designed for exactly that scenario...' }, { protocolId: 'sctp', title: 'SCTP: Multi-Stream Transport', description: - '[[sctp|SCTP]] (Stream Control Transmission Protocol) introduced two ideas ahead of their time: multiple independent message streams within a single association, and {{multi-homing|multi-homing}} β€” the ability to bind to multiple [[ip|IP]] addresses simultaneously and fail over between them without dropping the connection. If one network interface goes down, [[sctp|SCTP]] seamlessly switches to another. Originally designed for telecom {{signaling|signaling}} (carrying phone call setup messages between switches), it also supports message boundaries natively (unlike [[tcp|TCP]]\'s raw byte stream). While [[sctp|SCTP]] never gained widespread web adoption due to {{nat|NAT}} traversal issues, its concepts directly influenced [[quic|QUIC]]\'s stream {{multiplexing|multiplexing}} design.' + "[[sctp|SCTP]] (Stream Control Transmission Protocol) introduced two ideas ahead of their time: multiple independent message streams within a single association, and {{multi-homing|multi-homing}} β€” the ability to bind to multiple [[ip|IP]] addresses simultaneously and fail over between them without dropping the connection. If one network interface goes down, [[sctp|SCTP]] seamlessly switches to another. Originally designed for telecom {{signaling|signaling}} (carrying phone call setup messages between switches), it also supports message boundaries natively (unlike [[tcp|TCP]]'s raw byte stream). While [[sctp|SCTP]] never gained widespread web adoption due to {{nat|NAT}} traversal issues, its concepts directly influenced [[quic|QUIC]]'s stream {{multiplexing|multiplexing}} design." } ] }, @@ -147,14 +158,16 @@ export const journeys: Journey[] = [ title: 'TLS: The Encryption Layer', description: 'In the early internet, everything traveled in plaintext β€” passwords, credit cards, personal emails, all visible to anyone on the network path. [[tls|TLS]] changed everything by wrapping [[tcp|TCP]] connections in {{encryption|encryption}}. During the {{handshake|handshake}}, the server proves its identity with a {{certificate|certificate}} signed by a trusted authority, both sides agree on cipher suites, and an {{wg-ephemeral-key|ephemeral key}} {{exchange|exchange}} ({{ecdhe|ECDHE}}) creates shared session keys that even a passive observer who recorded every byte cannot derive. [[tls|TLS]] 1.3 stripped out legacy cruft, removing insecure algorithms and reducing the {{handshake|handshake}} to a single round trip. Today, over 95% of web traffic runs through [[tls|TLS]].', - transition: '[[tls|TLS]] secures client-to-server connections beautifully, but system administrators need more than encrypted web traffic β€” they need to log into remote servers, transfer files, and tunnel network connections, all securely. A different protocol emerged for this exact purpose...' + transition: + '[[tls|TLS]] secures client-to-server connections beautifully, but system administrators need more than encrypted web traffic β€” they need to log into remote servers, transfer files, and tunnel network connections, all securely. A different protocol emerged for this exact purpose...' }, { protocolId: 'ssh', title: 'SSH: Secure Shell', description: 'Before [[ssh|SSH]], administrators used Telnet to manage remote servers β€” sending passwords and commands in cleartext. [[ssh|SSH]] replaced it with a fully encrypted channel that supports public-key authentication (no passwords to steal), secure file transfer ({{scp-copy|SCP}} and {{sftp|SFTP}}), and {{port-forwarding|port forwarding}} that can tunnel any [[tcp|TCP]] connection through the encrypted link. [[ssh|SSH]] uses its own key {{exchange|exchange}} and {{encryption|encryption}} layer independent of [[tls|TLS]], and its agent forwarding feature lets you chain [[ssh|SSH]] connections through jump {{hosts-bare|hosts}} without exposing your {{private-key|private key}}. It became the universal tool for server management, Git operations, and secure automation.', - transition: 'With [[tls|TLS]] protecting web connections and [[ssh|SSH]] securing server access, the foundations of internet security were in place. But there was still a problem: {{http-method|HTTP}} {{encryption|encryption}} was optional, and most sites did not bother. The web needed a forcing function to make {{encryption|encryption}} the default, not the exception...' + transition: + 'With [[tls|TLS]] protecting web connections and [[ssh|SSH]] securing server access, the foundations of internet security were in place. But there was still a problem: {{http-method|HTTP}} {{encryption|encryption}} was optional, and most sites did not bother. The web needed a forcing function to make {{encryption|encryption}} the default, not the exception...' }, { protocolId: 'http2', @@ -169,7 +182,8 @@ export const journeys: Journey[] = [ { id: 'packet-journey', title: 'Journey of a Packet', - description: 'Follow a single packet from creation to delivery on a local network, including diagnostics.', + description: + 'Follow a single packet from creation to delivery on a local network, including diagnostics.', color: '#F472B6', scope: 'network-foundations', steps: [ @@ -177,22 +191,25 @@ export const journeys: Journey[] = [ protocolId: 'ethernet', title: 'Ethernet Framing', description: - 'Every packet\'s journey begins at the network interface card ({{nic|NIC}}), which constructs an [[ethernet|Ethernet]] frame. The {{nic|NIC}} stamps on its own 48-bit {{mac-address|MAC address}} as the source, adds the destination {{mac-address|MAC}}, a type field (0x0800 for [[ip|IPv4]], 0x0806 for [[arp|ARP]]), the {{payload|payload}}, and a 4-byte Frame Check Sequence ({{crc|CRC}}-32) that lets the receiver detect bit errors caused by electrical interference. If any bits are corrupted in {{transit|transit}}, the {{fcs|FCS}} check fails and the frame is silently discarded β€” no correction, just detection. This is the foundation of all local network communication.', - transition: 'The [[ethernet|Ethernet]] frame is ready to send, but there is a chicken-and-egg problem: your application knows the destination {{ip-address|IP address}} (192.168.1.100), not the destination {{mac-address|MAC address}}. You cannot build an [[ethernet|Ethernet]] frame without a {{mac-address|MAC}}. The network needs a way to translate between these two addressing systems...' + "Every packet's journey begins at the network interface card ({{nic|NIC}}), which constructs an [[ethernet|Ethernet]] frame. The {{nic|NIC}} stamps on its own 48-bit {{mac-address|MAC address}} as the source, adds the destination {{mac-address|MAC}}, a type field (0x0800 for [[ip|IPv4]], 0x0806 for [[arp|ARP]]), the {{payload|payload}}, and a 4-byte Frame Check Sequence ({{crc|CRC}}-32) that lets the receiver detect bit errors caused by electrical interference. If any bits are corrupted in {{transit|transit}}, the {{fcs|FCS}} check fails and the frame is silently discarded β€” no correction, just detection. This is the foundation of all local network communication.", + transition: + 'The [[ethernet|Ethernet]] frame is ready to send, but there is a chicken-and-egg problem: your application knows the destination {{ip-address|IP address}} (192.168.1.100), not the destination {{mac-address|MAC address}}. You cannot build an [[ethernet|Ethernet]] frame without a {{mac-address|MAC}}. The network needs a way to translate between these two addressing systems...' }, { protocolId: 'arp', title: 'ARP Resolution', description: '[[arp|ARP]] solves the [[ip|IP]]-to-{{mac-address|MAC}} translation with an elegant {{broadcast|broadcast}} mechanism. Your machine sends an [[arp|ARP]] request to the {{broadcast|broadcast}} address (FF:FF:FF:FF:FF:FF) asking "Who has 192.168.1.100? Tell 192.168.1.1." Every device on the {{lan|LAN}} segment hears this, but only the owner of that [[ip|IP]] replies with its {{mac-address|MAC address}}. The mapping is cached in your [[arp|ARP]] table (typically for 20 minutes) so subsequent packets skip the {{broadcast|broadcast}} entirely. You can see your own [[arp|ARP]] cache by running "arp -a" in a terminal. [[arp|ARP]] {{spoofing|spoofing}} β€” where an attacker sends fake [[arp|ARP]] replies to redirect traffic β€” is why network security often relies on higher-layer {{encryption|encryption}}.', - transition: 'With the destination {{mac-address|MAC}} resolved, the [[ethernet|Ethernet]] frame can be properly addressed for the local segment. Now the [[ip|IP]] layer needs to make a critical decision: is this packet destined for a machine on the same local network, or does it need to be forwarded to the {{gateway|default gateway}} for routing across the internet?' + transition: + 'With the destination {{mac-address|MAC}} resolved, the [[ethernet|Ethernet]] frame can be properly addressed for the local segment. Now the [[ip|IP]] layer needs to make a critical decision: is this packet destined for a machine on the same local network, or does it need to be forwarded to the {{gateway|default gateway}} for routing across the internet?' }, { protocolId: 'ip', title: 'IP Addressing & Routing', description: - 'The [[ip|IP]] layer makes the key routing decision. It compares the destination [[ip|IP]] against the {{subnet|subnet}} mask to determine if the target is local or remote. If local, [[arp|ARP]] resolves the target\'s {{mac-address|MAC}} directly. If remote, the packet is sent to the {{gateway|default gateway}} (your router), which consults its {{routing-table|routing table}} and forwards it toward the destination, hop by hop. Each router decrements the {{ttl|TTL}} ({{ttl|Time To Live}}, typically starting at 64) by one β€” when it reaches zero, the packet is discarded to prevent infinite routing loops. The [[ip|IP]] header also includes a header {{checksum|checksum}}, protocol field (6 for [[tcp|TCP]], 17 for [[udp|UDP]]), and {{fragmentation|fragmentation}} controls for packets that exceed a link\'s {{mtu|MTU}}.', - transition: 'The packet has been delivered successfully β€” but networks are not always healthy. Links go down, routes change, {{hosts-bare|hosts}} become unreachable, and packets get dropped. How does a network administrator diagnose problems and verify that everything is working correctly?' + "The [[ip|IP]] layer makes the key routing decision. It compares the destination [[ip|IP]] against the {{subnet|subnet}} mask to determine if the target is local or remote. If local, [[arp|ARP]] resolves the target's {{mac-address|MAC}} directly. If remote, the packet is sent to the {{gateway|default gateway}} (your router), which consults its {{routing-table|routing table}} and forwards it toward the destination, hop by hop. Each router decrements the {{ttl|TTL}} ({{ttl|Time To Live}}, typically starting at 64) by one β€” when it reaches zero, the packet is discarded to prevent infinite routing loops. The [[ip|IP]] header also includes a header {{checksum|checksum}}, protocol field (6 for [[tcp|TCP]], 17 for [[udp|UDP]]), and {{fragmentation|fragmentation}} controls for packets that exceed a link's {{mtu|MTU}}.", + transition: + 'The packet has been delivered successfully β€” but networks are not always healthy. Links go down, routes change, {{hosts-bare|hosts}} become unreachable, and packets get dropped. How does a network administrator diagnose problems and verify that everything is working correctly?' }, { protocolId: 'icmp', @@ -215,20 +232,22 @@ export const journeys: Journey[] = [ title: 'IPv4: The Original Addressing', description: '[[ip|IPv4]], designed in 1981, gives every device a 32-bit address (like 192.168.1.1) and defines how packets are forwarded hop-by-hop through routers. It was brilliantly simple and powered the explosive growth of the internet β€” but its designers never imagined billions of smartphones, IoT sensors, and cloud instances. With only 4.3 billion possible addresses, [[ip|IPv4]] exhaustion became inevitable. {{nat|NAT}} ({{nat|Network Address Translation}}) bought time by hiding entire private networks behind a single public [[ip|IP]], but it breaks end-to-end connectivity and complicates protocols that embed [[ip|IP]] addresses in their payloads.', - transition: '{{iana|IANA}} allocated the last [[ip|IPv4]] address blocks in 2011. The stopgap of {{nat|NAT}} created a fragile internet where devices could not directly reach each other. A fundamental redesign had been in the works since the 1990s, and the world is finally adopting it...' + transition: + '{{iana|IANA}} allocated the last [[ip|IPv4]] address blocks in 2011. The stopgap of {{nat|NAT}} created a fragile internet where devices could not directly reach each other. A fundamental redesign had been in the works since the 1990s, and the world is finally adopting it...' }, { protocolId: 'ipv6', title: 'IPv6: The Next Generation', description: - '[[ipv6|IPv6]] expands the address space from 32 bits to 128 bits β€” enough for 340 undecillion addresses (3.4 x 10^38), roughly 100 addresses per atom on Earth\'s surface. But [[ipv6|IPv6]] is not just bigger addresses: it simplifies the packet header (no more header checksums or {{fragmentation|fragmentation}} at intermediate routers), introduces {{slaac|SLAAC}} ({{stateless|Stateless}} Address Auto-Configuration) so devices can {{generate-ac|generate}} their own addresses without [[dhcp|DHCP]], and replaces [[arp|ARP]] with {{ndp|NDP}} ({{ndp|Neighbor Discovery Protocol}}). Most importantly, it restores true end-to-end connectivity β€” every device gets a globally routable address, eliminating the need for {{nat|NAT}}. The dual-stack transition (running [[ip|IPv4]] and [[ipv6|IPv6]] simultaneously) is well underway: on 28 March 2026 [[ipv6|IPv6]] carried 50.1% of {{google|Google}}\'s traffic for the first time, with US mobile carriers averaging ~87%.', - transition: 'Individual devices now have addresses, but the internet is composed of over 70,000 autonomous systems ({{autonomous-system|AS}}) β€” independent networks run by ISPs, cloud providers, universities, and enterprises. These networks need a way to discover each other and calculate paths across this vast interconnected mesh...' + "[[ipv6|IPv6]] expands the address space from 32 bits to 128 bits β€” enough for 340 undecillion addresses (3.4 x 10^38), roughly 100 addresses per atom on Earth's surface. But [[ipv6|IPv6]] is not just bigger addresses: it simplifies the packet header (no more header checksums or {{fragmentation|fragmentation}} at intermediate routers), introduces {{slaac|SLAAC}} ({{stateless|Stateless}} Address Auto-Configuration) so devices can {{generate-ac|generate}} their own addresses without [[dhcp|DHCP]], and replaces [[arp|ARP]] with {{ndp|NDP}} ({{ndp|Neighbor Discovery Protocol}}). Most importantly, it restores true end-to-end connectivity β€” every device gets a globally routable address, eliminating the need for {{nat|NAT}}. The dual-stack transition (running [[ip|IPv4]] and [[ipv6|IPv6]] simultaneously) is well underway: on 28 March 2026 [[ipv6|IPv6]] carried 50.1% of {{google|Google}}'s traffic for the first time, with US mobile carriers averaging ~87%.", + transition: + 'Individual devices now have addresses, but the internet is composed of over 70,000 autonomous systems ({{autonomous-system|AS}}) β€” independent networks run by ISPs, cloud providers, universities, and enterprises. These networks need a way to discover each other and calculate paths across this vast interconnected mesh...' }, { protocolId: 'bgp', - title: 'BGP: The Internet\'s Routing Protocol', + title: "BGP: The Internet's Routing Protocol", description: - '[[bgp|BGP]] (Border Gateway Protocol) is the protocol that literally holds the internet together. Each {{autonomous-system|autonomous system}} uses [[bgp|BGP]] to announce which [[ip|IP]] prefixes it owns and which paths it can reach. [[bgp|BGP]] routers at network borders {{exchange|exchange}} these announcements with their peers, building a global map of reachability. Path selection is policy-driven β€” an {{isp|ISP}} might prefer cheaper {{transit|transit}} providers, avoid routes through certain countries, or favor shorter {{autonomous-system|AS}} paths. When a [[bgp|BGP]] misconfiguration happens (like Pakistan accidentally hijacking YouTube\'s prefix in 2008), large portions of the internet can go dark. Despite carrying the {{routing-table|routing table}} for the entire internet (nearly 1 million [[ip|IPv4]] prefixes), [[bgp|BGP]] runs on surprisingly modest hardware and converges within minutes after topology changes.' + "[[bgp|BGP]] (Border Gateway Protocol) is the protocol that literally holds the internet together. Each {{autonomous-system|autonomous system}} uses [[bgp|BGP]] to announce which [[ip|IP]] prefixes it owns and which paths it can reach. [[bgp|BGP]] routers at network borders {{exchange|exchange}} these announcements with their peers, building a global map of reachability. Path selection is policy-driven β€” an {{isp|ISP}} might prefer cheaper {{transit|transit}} providers, avoid routes through certain countries, or favor shorter {{autonomous-system|AS}} paths. When a [[bgp|BGP]] misconfiguration happens (like Pakistan accidentally hijacking YouTube's prefix in 2008), large portions of the internet can go dark. Despite carrying the {{routing-table|routing table}} for the entire internet (nearly 1 million [[ip|IPv4]] prefixes), [[bgp|BGP]] runs on surprisingly modest hardware and converges within minutes after topology changes." } ] }, @@ -247,21 +266,24 @@ export const journeys: Journey[] = [ title: 'TCP: The Original', description: '[[tcp|TCP]] has been the workhorse of reliable internet communication since 1981 β€” it guarantees that every byte arrives, in order, without duplication. Underneath, it uses sequence numbers, acknowledgments, {{retransmission|retransmission}} timers, and sophisticated {{congestion-control|congestion control}} (algorithms like Reno, {{cubic|CUBIC}}, and {{bbr|BBR}} that probe the network to find the optimal sending rate). But [[tcp|TCP]] has a fundamental limitation: it provides a single ordered byte stream. When [[http2|HTTP/2]] multiplexes dozens of requests over one [[tcp|TCP]] connection, a single lost packet blocks ALL streams until it is retransmitted. This {{head-of-line-blocking|head-of-line blocking}} problem becomes increasingly painful as connections carry more concurrent data.', - transition: '[[tcp|TCP]]\'s single-stream design meant that loss in one logical conversation blocked every other conversation sharing the same connection. The telecom industry, which needed to carry multiple independent {{signaling|signaling}} messages simultaneously, developed a different approach...' + transition: + "[[tcp|TCP]]'s single-stream design meant that loss in one logical conversation blocked every other conversation sharing the same connection. The telecom industry, which needed to carry multiple independent {{signaling|signaling}} messages simultaneously, developed a different approach..." }, { protocolId: 'sctp', title: 'SCTP: Multi-Streaming', description: - '[[sctp|SCTP]] was the first transport protocol to tackle {{head-of-line-blocking|head-of-line blocking}} directly. It introduced independent streams within a single association β€” a lost packet on stream 5 does not stall streams 1 through 4. It also pioneered {{multi-homing|multi-homing}}: an [[sctp|SCTP]] association can span multiple [[ip|IP]] addresses on each endpoint, providing automatic {{failover|failover}} if a network interface goes down. Additionally, [[sctp|SCTP]] preserves message boundaries natively (unlike [[tcp|TCP]]\'s raw byte stream), making it ideal for structured messages like telephony {{signaling|signaling}} ({{ss7|SS7}} over [[ip|IP]]). While it never achieved broad web adoption because most NATs and firewalls do not understand [[sctp|SCTP]] packets, its ideas proved prescient.', - transition: '[[sctp|SCTP]] proved that independent streams eliminate {{head-of-line-blocking|head-of-line blocking}}, and {{multi-homing|multi-homing}} provides resilience. But what if you want to go further β€” not just failing over between network paths, but actively using multiple paths simultaneously to aggregate {{bandwidth|bandwidth}}?' + "[[sctp|SCTP]] was the first transport protocol to tackle {{head-of-line-blocking|head-of-line blocking}} directly. It introduced independent streams within a single association β€” a lost packet on stream 5 does not stall streams 1 through 4. It also pioneered {{multi-homing|multi-homing}}: an [[sctp|SCTP]] association can span multiple [[ip|IP]] addresses on each endpoint, providing automatic {{failover|failover}} if a network interface goes down. Additionally, [[sctp|SCTP]] preserves message boundaries natively (unlike [[tcp|TCP]]'s raw byte stream), making it ideal for structured messages like telephony {{signaling|signaling}} ({{ss7|SS7}} over [[ip|IP]]). While it never achieved broad web adoption because most NATs and firewalls do not understand [[sctp|SCTP]] packets, its ideas proved prescient.", + transition: + '[[sctp|SCTP]] proved that independent streams eliminate {{head-of-line-blocking|head-of-line blocking}}, and {{multi-homing|multi-homing}} provides resilience. But what if you want to go further β€” not just failing over between network paths, but actively using multiple paths simultaneously to aggregate {{bandwidth|bandwidth}}?' }, { protocolId: 'mptcp', title: 'MPTCP: Multiple Paths', description: '{{multipath|Multipath}} [[tcp|TCP]] extends standard [[tcp|TCP]] to use multiple network interfaces simultaneously. Your phone can send data over both [[wifi|WiFi]] and cellular at the same time, aggregating their {{bandwidth|bandwidth}}. If you walk out of [[wifi|WiFi]] range, the cellular {{subflow|subflow}} keeps going seamlessly β€” no connection drop, no reconnection delay. [[mptcp|MPTCP]] works by establishing multiple [[tcp|TCP]] subflows and distributing data across them using a coupled {{congestion-control|congestion control}} algorithm that balances load fairly. {{apple|Apple}} uses [[mptcp|MPTCP]] in iOS for Siri and Maps, and it powers the seamless [[wifi|WiFi]]-to-cellular transitions you experience daily without noticing. The tradeoff is complexity: schedulers must decide which path gets which data, and reordering at the receiver adds {{latency|latency}}.', - transition: '[[mptcp|MPTCP]] showed the power of using multiple paths, but it still inherits [[tcp|TCP]]\'s fundamental constraints β€” the {{three-way-handshake|three-way handshake}}, the kernel implementation that is hard to {{bgp-update|update}}, and middlebox interference. A completely new transport protocol, designed with all these lessons in mind, would soon arrive...' + transition: + "[[mptcp|MPTCP]] showed the power of using multiple paths, but it still inherits [[tcp|TCP]]'s fundamental constraints β€” the {{three-way-handshake|three-way handshake}}, the kernel implementation that is hard to {{bgp-update|update}}, and middlebox interference. A completely new transport protocol, designed with all these lessons in mind, would soon arrive..." }, { protocolId: 'quic', @@ -284,28 +306,31 @@ export const journeys: Journey[] = [ protocolId: 'tcp', title: 'TCP + TLS: The Old Way', description: - 'To load a web page over HTTPS, a browser traditionally needs three sequential round trips before any page data flows: one for the [[tcp|TCP]] {{handshake|handshake}} ({{syn-cookies|SYN}}, {{syn-cookies|SYN}}-{{ack|ACK}}, {{ack|ACK}}), one or two more for [[tls|TLS]] (exchanging cipher suites, certificates, and key material). On a connection with 100ms {{latency|latency}}, that is 200-300ms of pure {{handshake|handshake}} overhead before a single byte of {{html|HTML}} arrives. Even worse, [[http2|HTTP/2]] multiplexes all its streams over a single [[tcp|TCP]] connection, so when one packet is lost, [[tcp|TCP]]\'s {{head-of-line-blocking|head-of-line blocking}} stalls every request β€” even though the lost data might belong to an unrelated resource like a tiny favicon.', - transition: '{{google|Google}} measured this cost at scale across billions of Chrome connections and realized the overhead was enormous. They wanted {{one-rtt|1-RTT}} connections, {{encryption|encryption}} by default, and no {{head-of-line-blocking|head-of-line blocking}}. But deploying a new transport protocol through the existing internet β€” full of NATs, firewalls, and middleboxes that drop anything that is not [[tcp|TCP]] or [[udp|UDP]] β€” seemed impossible. Unless they built on top of something that already works everywhere...' + "To load a web page over HTTPS, a browser traditionally needs three sequential round trips before any page data flows: one for the [[tcp|TCP]] {{handshake|handshake}} ({{syn-cookies|SYN}}, {{syn-cookies|SYN}}-{{ack|ACK}}, {{ack|ACK}}), one or two more for [[tls|TLS]] (exchanging cipher suites, certificates, and key material). On a connection with 100ms {{latency|latency}}, that is 200-300ms of pure {{handshake|handshake}} overhead before a single byte of {{html|HTML}} arrives. Even worse, [[http2|HTTP/2]] multiplexes all its streams over a single [[tcp|TCP]] connection, so when one packet is lost, [[tcp|TCP]]'s {{head-of-line-blocking|head-of-line blocking}} stalls every request β€” even though the lost data might belong to an unrelated resource like a tiny favicon.", + transition: + '{{google|Google}} measured this cost at scale across billions of Chrome connections and realized the overhead was enormous. They wanted {{one-rtt|1-RTT}} connections, {{encryption|encryption}} by default, and no {{head-of-line-blocking|head-of-line blocking}}. But deploying a new transport protocol through the existing internet β€” full of NATs, firewalls, and middleboxes that drop anything that is not [[tcp|TCP]] or [[udp|UDP]] β€” seemed impossible. Unless they built on top of something that already works everywhere...' }, { protocolId: 'udp', title: 'UDP: The Foundation', description: 'The key insight was that [[udp|UDP]] passes through virtually every middlebox on the internet. NATs translate [[udp|UDP]] ports, firewalls allow it, and {{isp|ISP}} equipment does not inspect it. By layering a new protocol on top of [[udp|UDP]], {{google|Google}} could deploy revolutionary transport features without waiting for routers and operating systems to be updated β€” a process that historically takes decades. [[udp|UDP]] itself adds almost nothing (just 8 bytes of header with ports and a {{checksum|checksum}}), giving [[quic|QUIC]] a blank canvas to build its own reliability, {{encryption|encryption}}, and stream management entirely in userspace. This also means [[quic|QUIC]] can be updated with a browser release, not an {{os|OS}} kernel {{bgp-update|update}}.', - transition: 'With [[udp|UDP]] providing universal reachability through the existing internet infrastructure, the [[quic|QUIC]] engineering team had the foundation they needed. Now they could design the actual transport protocol β€” combining the reliability lessons of [[tcp|TCP]], the {{encryption|encryption}} of [[tls|TLS]], and the {{multiplexing|multiplexing}} ideas of [[http2|HTTP/2]] into a single, unified protocol...' + transition: + 'With [[udp|UDP]] providing universal reachability through the existing internet infrastructure, the [[quic|QUIC]] engineering team had the foundation they needed. Now they could design the actual transport protocol β€” combining the reliability lessons of [[tcp|TCP]], the {{encryption|encryption}} of [[tls|TLS]], and the {{multiplexing|multiplexing}} ideas of [[http2|HTTP/2]] into a single, unified protocol...' }, { protocolId: 'quic', title: 'QUIC: The Synthesis', description: - '[[quic|QUIC]] merges transport and security into a single protocol. Its {{handshake|handshake}} combines the connection setup and [[tls|TLS]] 1.3 key {{exchange|exchange}} into one round trip β€” the client sends its cryptographic parameters in the very first packet, and the server\'s first response is already encrypted. Independent streams within a single [[quic|QUIC]] connection mean a lost packet only blocks the stream it belongs to, not all traffic. Connections are identified by a variable-length Connection {{id-identifier|ID}} rather than the [[ip|IP]]/port 4-tuple, so when you switch from [[wifi|WiFi]] to cellular, the connection migrates seamlessly. And because [[quic|QUIC]] runs in userspace, it can be iterated on monthly rather than waiting years for kernel updates.', - transition: 'With [[quic|QUIC]] providing fast, encrypted, multiplexed transport, the final piece was adapting {{http-method|HTTP}} to take advantage of it. [[http3|HTTP/3]] is not just "[[http2|HTTP/2]] on [[quic|QUIC]]" β€” it had to be redesigned because [[quic|QUIC]]\'s streams replaced the stream {{multiplexing|multiplexing}} that [[http2|HTTP/2]] implemented over [[tcp|TCP]]...' + "[[quic|QUIC]] merges transport and security into a single protocol. Its {{handshake|handshake}} combines the connection setup and [[tls|TLS]] 1.3 key {{exchange|exchange}} into one round trip β€” the client sends its cryptographic parameters in the very first packet, and the server's first response is already encrypted. Independent streams within a single [[quic|QUIC]] connection mean a lost packet only blocks the stream it belongs to, not all traffic. Connections are identified by a variable-length Connection {{id-identifier|ID}} rather than the [[ip|IP]]/port 4-tuple, so when you switch from [[wifi|WiFi]] to cellular, the connection migrates seamlessly. And because [[quic|QUIC]] runs in userspace, it can be iterated on monthly rather than waiting years for kernel updates.", + transition: + 'With [[quic|QUIC]] providing fast, encrypted, multiplexed transport, the final piece was adapting {{http-method|HTTP}} to take advantage of it. [[http3|HTTP/3]] is not just "[[http2|HTTP/2]] on [[quic|QUIC]]" β€” it had to be redesigned because [[quic|QUIC]]\'s streams replaced the stream {{multiplexing|multiplexing}} that [[http2|HTTP/2]] implemented over [[tcp|TCP]]...' }, { protocolId: 'http3', title: 'HTTP/3: The Payoff', description: - '[[http3|HTTP/3]] maps one {{http-method|HTTP}} {{request-response|request-response}} to one [[quic|QUIC]] stream, giving each request independent {{flow-control|flow control}} and loss recovery. A lost packet carrying image data does not block the {{css|CSS}} or JavaScript streams. {{qpack|QPACK}} replaces {{hpack|HPACK}} for header compression (adapted for [[quic|QUIC]]\'s out-of-order delivery), and {{zero-rtt|0-RTT}} resumption lets returning visitors send their first {{http-method|HTTP}} request in the very first packet β€” zero round-trip {{latency|latency}} for the initial data. On lossy mobile networks, [[http3|HTTP/3]] delivers pages measurably faster than [[http2|HTTP/2]] over [[tcp|TCP]]. As of 2024, over 30% of global web traffic runs on [[http3|HTTP/3]], and adoption is accelerating as CDNs and cloud providers enable it by default.' + "[[http3|HTTP/3]] maps one {{http-method|HTTP}} {{request-response|request-response}} to one [[quic|QUIC]] stream, giving each request independent {{flow-control|flow control}} and loss recovery. A lost packet carrying image data does not block the {{css|CSS}} or JavaScript streams. {{qpack|QPACK}} replaces {{hpack|HPACK}} for header compression (adapted for [[quic|QUIC]]'s out-of-order delivery), and {{zero-rtt|0-RTT}} resumption lets returning visitors send their first {{http-method|HTTP}} request in the very first packet β€” zero round-trip {{latency|latency}} for the initial data. On lossy mobile networks, [[http3|HTTP/3]] delivers pages measurably faster than [[http2|HTTP/2]] over [[tcp|TCP]]. As of 2024, over 30% of global web traffic runs on [[http3|HTTP/3]], and adoption is accelerating as CDNs and cloud providers enable it by default." } ] }, @@ -314,7 +339,8 @@ export const journeys: Journey[] = [ { id: 'http-timeline', title: 'The HTTP Timeline', - description: 'Three decades of {{http-method|HTTP}} evolution β€” from [[pioneer:tim-berners-lee|Tim Berners-Lee]]\'s hypertext to [[quic|QUIC]]-powered streams.', + description: + "Three decades of {{http-method|HTTP}} evolution β€” from [[pioneer:tim-berners-lee|Tim Berners-Lee]]'s hypertext to [[quic|QUIC]]-powered streams.", color: '#00D4FF', scope: 'web-api', steps: [ @@ -323,27 +349,30 @@ export const journeys: Journey[] = [ title: 'HTTP/1.1: The Foundation', description: '[[http1|HTTP/1.1]] (1997) established the web as we know it. It is entirely text-based β€” you can literally type "GET / [[http1|HTTP/1.1]]" into a telnet session and get a web page back. The {{keep-alive|keep-alive}} header lets a single [[tcp|TCP]] connection serve multiple sequential requests, avoiding the cost of a new {{handshake|handshake}} for each resource. But requests are strictly serialized: the client must wait for each response before sending the next request. Browsers worked around this by opening 6-8 parallel [[tcp|TCP]] connections per domain, and developers invented {{domain-sharding|domain sharding}}, {{css|CSS}} sprites, and resource inlining to reduce the request count. These were hacks born from protocol limitations, and the web was crying out for something better.', - transition: 'By 2015, the average web page required over 100 resources (scripts, stylesheets, images, fonts). Opening 6 connections per domain and serializing requests within each one was an enormous waste of {{bandwidth|bandwidth}} and {{latency|latency}}. The web needed a protocol that could handle many requests simultaneously over a single connection...' + transition: + 'By 2015, the average web page required over 100 resources (scripts, stylesheets, images, fonts). Opening 6 connections per domain and serializing requests within each one was an enormous waste of {{bandwidth|bandwidth}} and {{latency|latency}}. The web needed a protocol that could handle many requests simultaneously over a single connection...' }, { protocolId: 'http2', title: 'HTTP/2: Multiplexed Binary', description: '[[http2|HTTP/2]] (2015) was a ground-up redesign of how {{http-method|HTTP}} frames are encoded and transmitted, while keeping the familiar semantics (GET, POST, headers, status codes) unchanged. It switched from text to a compact {{binary-framing|binary framing}} layer, multiplexes unlimited concurrent streams over a single [[tcp|TCP]] connection, and compresses headers with {{hpack|HPACK}} (using a shared dynamic table that avoids re-sending identical headers like cookies and user-agents). {{server-push|Server push}} lets the server proactively send resources it knows the client will need (like the {{css|CSS}} for a page it just served). All those [[http1|HTTP/1.1]] performance hacks β€” {{domain-sharding|domain sharding}}, spriting, inlining β€” became unnecessary and even counterproductive.', - transition: '[[http2|HTTP/2]] eliminated the {{http-method|HTTP}}-layer {{head-of-line-blocking|head-of-line blocking}}, but it exposed a deeper problem: all those multiplexed streams shared a single [[tcp|TCP]] connection. When one [[tcp|TCP]] packet was lost, [[tcp|TCP]]\'s ordered delivery guarantee stalled ALL streams until the {{retransmission|retransmission}} arrived. The protocol needed a new transport layer that would not punish unrelated streams for one stream\'s lost packet...' + transition: + "[[http2|HTTP/2]] eliminated the {{http-method|HTTP}}-layer {{head-of-line-blocking|head-of-line blocking}}, but it exposed a deeper problem: all those multiplexed streams shared a single [[tcp|TCP]] connection. When one [[tcp|TCP]] packet was lost, [[tcp|TCP]]'s ordered delivery guarantee stalled ALL streams until the {{retransmission|retransmission}} arrived. The protocol needed a new transport layer that would not punish unrelated streams for one stream's lost packet..." }, { protocolId: 'http3', title: 'HTTP/3: QUIC-Powered', description: - '[[http3|HTTP/3]] (2022) runs on [[quic|QUIC]] instead of [[tcp|TCP]], finally eliminating {{head-of-line-blocking|head-of-line blocking}} at every layer. Each {{http-method|HTTP}} stream maps to an independent [[quic|QUIC]] stream with its own loss recovery β€” a dropped packet on one stream cannot block any other. {{qpack|QPACK}} replaces {{hpack|HPACK}} for header compression, adapted for [[quic|QUIC]]\'s potentially out-of-order stream delivery. The integrated [[tls|TLS]] 1.3 {{handshake|handshake}} means a new connection is ready in one round trip, and {{zero-rtt|0-RTT}} resumption for returning visitors means the browser can send its first {{http-method|HTTP}} request instantly. {{connection-migration|Connection migration}} (via [[quic|QUIC]]\'s Connection {{id-identifier|ID}}) means a phone switching from [[wifi|WiFi]] to cellular does not drop the page load. The three decades of {{http-method|HTTP}} evolution culminate here: a fast, encrypted, multiplexed protocol that works well even on lossy mobile networks.' + "[[http3|HTTP/3]] (2022) runs on [[quic|QUIC]] instead of [[tcp|TCP]], finally eliminating {{head-of-line-blocking|head-of-line blocking}} at every layer. Each {{http-method|HTTP}} stream maps to an independent [[quic|QUIC]] stream with its own loss recovery β€” a dropped packet on one stream cannot block any other. {{qpack|QPACK}} replaces {{hpack|HPACK}} for header compression, adapted for [[quic|QUIC]]'s potentially out-of-order stream delivery. The integrated [[tls|TLS]] 1.3 {{handshake|handshake}} means a new connection is ready in one round trip, and {{zero-rtt|0-RTT}} resumption for returning visitors means the browser can send its first {{http-method|HTTP}} request instantly. {{connection-migration|Connection migration}} (via [[quic|QUIC]]'s Connection {{id-identifier|ID}}) means a phone switching from [[wifi|WiFi]] to cellular does not drop the page load. The three decades of {{http-method|HTTP}} evolution culminate here: a fast, encrypted, multiplexed protocol that works well even on lossy mobile networks." } ] }, { id: 'rest-to-realtime', title: 'REST to Real-Time', - description: 'From simple {{request-response|request-response}} to persistent bidirectional communication.', + description: + 'From simple {{request-response|request-response}} to persistent bidirectional communication.', color: '#00D4FF', scope: 'web-api', steps: [ @@ -352,21 +381,24 @@ export const journeys: Journey[] = [ title: 'REST: Request-Response', description: '[[rest|REST]] (Representational State Transfer) models your {{api|API}} as a collection of resources, each identified by a {{url|URL}}, manipulated through standard {{http-method|HTTP}} methods: GET to read, POST to create, PUT to replace, DELETE to remove. Its {{stateless|stateless}} design means every request carries all the context the server needs β€” no session state to manage, trivial to cache, easy to scale behind load balancers. [[rest|REST]] dominates web APIs because of this simplicity. But it has a fundamental limitation: the client must ask for updates. If you want real-time stock prices or live chat messages, you are stuck polling β€” hammering the server with repeated requests, most of which return "nothing new," wasting {{bandwidth|bandwidth}} and battery life.', - transition: 'Polling is like repeatedly calling someone to ask "any news?" β€” wasteful for both parties. What if the server could simply call you back whenever something interesting happens? The web platform introduced a lightweight mechanism for exactly this kind of one-way push...' + transition: + 'Polling is like repeatedly calling someone to ask "any news?" β€” wasteful for both parties. What if the server could simply call you back whenever something interesting happens? The web platform introduced a lightweight mechanism for exactly this kind of one-way push...' }, { protocolId: 'sse', title: 'SSE: Server-Sent Events', description: '[[sse|Server-Sent Events]] flip the [[rest|REST]] model on its head: instead of the client polling, the server holds the connection open and pushes events whenever they occur. It works over plain {{http-method|HTTP}} (so it passes through proxies, load balancers, and CDNs without issues), uses a dead-simple text-based format (just "data:" lines), and the browser\'s {{eventsource|EventSource API}} automatically reconnects if the connection drops β€” even resuming from the last received event {{id-identifier|ID}}. [[sse|SSE]] is perfect for live dashboards, {{notification|notification}} feeds, log tailing, and {{ai|AI}} streaming responses (like ChatGPT\'s token-by-token output). The limitation is that it is one-directional: only the server can push. If the client needs to send messages too, it must use separate {{http-method|HTTP}} requests.', - transition: '[[sse|SSE]] handles server-to-client streaming elegantly, but many applications need truly bidirectional communication β€” chat applications where both users type simultaneously, multiplayer games with constant input and output, collaborative editors where every keystroke must be {{broadcast|broadcast}}. These need a connection where either side can send at any moment...' + transition: + '[[sse|SSE]] handles server-to-client streaming elegantly, but many applications need truly bidirectional communication β€” chat applications where both users type simultaneously, multiplayer games with constant input and output, collaborative editors where every keystroke must be {{broadcast|broadcast}}. These need a connection where either side can send at any moment...' }, { protocolId: 'websockets', title: 'WebSockets: Full Duplex', description: '[[websockets|WebSockets]] upgrade an {{http-method|HTTP}} connection into a persistent, {{full-duplex|full-duplex}} channel where both client and server can send messages independently at any time β€” no request/response pairing required. After the initial {{http-method|HTTP}} upgrade {{handshake|handshake}}, the protocol switches to a lightweight {{binary-framing|binary framing}} format with minimal overhead (as little as 2 bytes per frame). This makes [[websockets|WebSockets]] ideal for chat applications (Slack, Discord), multiplayer gaming (real-time position updates), collaborative editing ({{google|Google}} Docs cursors), and financial trading (live order book updates). The tradeoff is that [[websockets|WebSockets]] are raw pipes β€” they give you a message channel but impose no structure on what flows through it. You must design your own message formats, error handling, and connection management.', - transition: '[[websockets|WebSockets]] provide raw bidirectional messaging, but for microservice architectures and complex distributed systems, developers need more structure: typed message schemas, automatic code generation for multiple languages, streaming in both directions, and efficient binary {{serialization|serialization}}. Enterprise systems need a proper {{rpc|RPC}} framework...' + transition: + '[[websockets|WebSockets]] provide raw bidirectional messaging, but for microservice architectures and complex distributed systems, developers need more structure: typed message schemas, automatic code generation for multiple languages, streaming in both directions, and efficient binary {{serialization|serialization}}. Enterprise systems need a proper {{rpc|RPC}} framework...' }, { protocolId: 'grpc', @@ -390,14 +422,16 @@ export const journeys: Journey[] = [ title: 'MQTT: Lightweight IoT', description: '[[mqtt|MQTT]] was designed for the harshest conditions: sensors on oil rigs with satellite uplinks, medical devices with intermittent cellular, smart home gadgets on flaky [[wifi|WiFi]]. Its binary protocol is extraordinarily compact β€” a minimal {{mqtt-publish|publish}} message is just 2 bytes of overhead. Clients {{mqtt-publish|publish}} to hierarchical topics (like "home/kitchen/temperature") and {{mqtt-subscribe|subscribe}} with wildcards ("home/+/temperature" for all rooms). Three QoS levels let you choose between {{fire-and-forget|fire-and-forget}} (QoS 0), acknowledged delivery (QoS 1), and {{exactly-once-delivery|exactly-once delivery}} (QoS 2). The broker handles all routing: publishers and subscribers never need to know about each other, creating clean decoupling. A "{{last-will|Last Will}}" message is even sent automatically if a device disconnects unexpectedly.', - transition: '[[mqtt|MQTT]] excels at getting small messages from constrained devices to a broker, but enterprise systems need more sophisticated message routing. What if you need to route messages based on content, fan out to multiple queues, implement priority ordering, or guarantee transactional processing with dead-letter handling?' + transition: + '[[mqtt|MQTT]] excels at getting small messages from constrained devices to a broker, but enterprise systems need more sophisticated message routing. What if you need to route messages based on content, fan out to multiple queues, implement priority ordering, or guarantee transactional processing with dead-letter handling?' }, { protocolId: 'amqp', title: 'AMQP: Enterprise Messaging', description: '[[amqp|AMQP]] (Advanced Message Queuing Protocol) is the industrial-strength messaging protocol for enterprise systems. It introduces a powerful routing model: producers send messages to exchanges, which route them to queues based on bindings. Different {{exchange|exchange}} types enable different patterns β€” direct exchanges for point-to-point, fanout for broadcasting to all queues, {{topic|topic}} exchanges for pattern-based routing, and headers exchanges for attribute-based routing. Messages can be persistent (surviving broker restarts), acknowledged (consumers confirm processing), and rejected (dead-lettered for error handling). This architecture powers financial trading systems, healthcare data pipelines, and e-commerce order processing where losing a message could mean losing money or endangering lives.', - transition: '[[amqp|AMQP]] handles complex enterprise routing brilliantly, but what happens when you need to process millions of events per second, replay historical data, and scale horizontally across dozens of servers? Enterprise message brokers were not designed for internet-scale event streaming...' + transition: + '[[amqp|AMQP]] handles complex enterprise routing brilliantly, but what happens when you need to process millions of events per second, replay historical data, and scale horizontally across dozens of servers? Enterprise message brokers were not designed for internet-scale event streaming...' }, { protocolId: 'kafka', @@ -410,8 +444,7 @@ export const journeys: Journey[] = [ { id: 'iot-to-enterprise', title: 'IoT to Enterprise', - description: - 'From constrained sensors to enterprise integrations β€” messaging at every scale.', + description: 'From constrained sensors to enterprise integrations β€” messaging at every scale.', color: '#C084FC', scope: 'async-iot', steps: [ @@ -436,7 +469,8 @@ export const journeys: Journey[] = [ title: 'STOMP: Simple Integration', description: '[[stomp|STOMP]] (Simple Text Oriented Messaging Protocol) is the {{http-method|HTTP}} of messaging β€” entirely text-based and human-readable, making it trivial to debug with basic tools. Commands like {{mqtt-connect|CONNECT}}, {{mqtt-subscribe|SUBSCRIBE}}, SEND, and {{ack|ACK}} are self-explanatory, and any developer who understands {{http-method|HTTP}} can integrate [[stomp|STOMP]] in minutes. Web applications commonly use [[stomp|STOMP]] over [[websockets|WebSockets]], enabling browser-based dashboards to {{mqtt-subscribe|subscribe}} to IoT data feeds in real time. Message brokers like RabbitMQ and ActiveMQ support [[stomp|STOMP]] alongside their native protocols, making it the easiest on-ramp for connecting web frontends to messaging infrastructure. The tradeoff is efficiency: text headers and no compression mean more overhead than binary protocols.', - transition: '[[stomp|STOMP]] makes integration easy, but enterprise data processing demands more β€” content-based routing that sends alerts only to the right team, transactional message handling that guarantees no order is processed twice, dead-letter queues for failed processing, and priority ordering for time-sensitive data. These requirements call for a full-featured enterprise messaging protocol...' + transition: + '[[stomp|STOMP]] makes integration easy, but enterprise data processing demands more β€” content-based routing that sends alerts only to the right team, transactional message handling that guarantees no order is processed twice, dead-letter queues for failed processing, and priority ordering for time-sensitive data. These requirements call for a full-featured enterprise messaging protocol...' }, { protocolId: 'amqp', @@ -451,8 +485,7 @@ export const journeys: Journey[] = [ { id: 'video-call', title: 'Building a Video Call', - description: - 'The protocols that make real-time video communication possible in the browser.', + description: 'The protocols that make real-time video communication possible in the browser.', color: '#FF9F67', scope: 'realtime-av', steps: [ @@ -468,7 +501,7 @@ export const journeys: Journey[] = [ protocolId: 'rtp', title: 'RTP: Media Transport', description: - '[[rtp|RTP]] (Real-time Transport Protocol) is the workhorse that carries the actual audio and video data. Each [[rtp|RTP]] packet includes a timestamp (essential for playing audio and video at the right moment, even if packets arrive out of order), a {{sequence-number|sequence number}} (for detecting lost packets), a {{payload|payload}} type identifier (so the receiver knows which {{codec|codec}} to use for decoding), and synchronization source identifiers (for distinguishing multiple media streams). [[rtp|RTP]] runs over [[udp|UDP]] because real-time media cannot afford [[tcp|TCP]]\'s {{retransmission|retransmission}} delays β€” a 200ms-old video frame is useless, so it is better to skip it and show the next one. Its companion protocol {{rtcp|RTCP}} provides feedback: receiver reports on packet loss and {{jitter|jitter}} help the sender adapt its bitrate in real time.', + "[[rtp|RTP]] (Real-time Transport Protocol) is the workhorse that carries the actual audio and video data. Each [[rtp|RTP]] packet includes a timestamp (essential for playing audio and video at the right moment, even if packets arrive out of order), a {{sequence-number|sequence number}} (for detecting lost packets), a {{payload|payload}} type identifier (so the receiver knows which {{codec|codec}} to use for decoding), and synchronization source identifiers (for distinguishing multiple media streams). [[rtp|RTP]] runs over [[udp|UDP]] because real-time media cannot afford [[tcp|TCP]]'s {{retransmission|retransmission}} delays β€” a 200ms-old video frame is useless, so it is better to skip it and show the next one. Its companion protocol {{rtcp|RTCP}} provides feedback: receiver reports on packet loss and {{jitter|jitter}} help the sender adapt its bitrate in real time.", transition: '[[rtp|RTP]] handles media transport beautifully, but building a video call in a web browser involves much more than just sending packets. Peers are usually behind NATs and firewalls, all media must be encrypted, and browsers need a JavaScript {{api|API}} to access cameras and microphones. A comprehensive framework is needed to tie everything together...' }, @@ -492,9 +525,9 @@ export const journeys: Journey[] = [ protocolId: 'rtmp', title: 'RTMP: Legacy Streaming', description: - '[[rtmp|RTMP]] (Real-Time Messaging Protocol) was developed by Macromedia for Flash Player and became the dominant live streaming protocol for over a decade. It maintains a persistent [[tcp|TCP]] connection and multiplexes audio, video, and data messages into interleaved chunks, achieving low {{latency|latency}} (1-3 seconds) for live broadcasts. [[rtmp|RTMP]] powered early YouTube live, Twitch, and Facebook Live. However, it required specialized streaming servers (like Adobe Media Server or Wowza), could not pass through many firewalls and proxies, and while Flash Player\'s end-of-life in 2020 ended [[rtmp|RTMP]]\'s use for playback, the protocol survives as a widely-used ingest format β€” streamers still use [[rtmp|RTMP]] to send video from OBS to platforms like Twitch, which then transcode and redistribute via modern protocols.', + "[[rtmp|RTMP]] (Real-Time Messaging Protocol) was developed by Macromedia for Flash Player and became the dominant live streaming protocol for over a decade. It maintains a persistent [[tcp|TCP]] connection and multiplexes audio, video, and data messages into interleaved chunks, achieving low {{latency|latency}} (1-3 seconds) for live broadcasts. [[rtmp|RTMP]] powered early YouTube live, Twitch, and Facebook Live. However, it required specialized streaming servers (like Adobe Media Server or Wowza), could not pass through many firewalls and proxies, and while Flash Player's end-of-life in 2020 ended [[rtmp|RTMP]]'s use for playback, the protocol survives as a widely-used ingest format β€” streamers still use [[rtmp|RTMP]] to send video from OBS to platforms like Twitch, which then transcode and redistribute via modern protocols.", transition: - '[[rtmp|RTMP]]\'s dependence on Flash and specialized servers was its downfall. The insight that changed everything was simple: what if you broke video into small files and served them over plain {{http-method|HTTP}}? Suddenly any web server, any {{cdn|CDN}}, and any {{http-method|HTTP}} cache in the world could deliver video without special software...' + "[[rtmp|RTMP]]'s dependence on Flash and specialized servers was its downfall. The insight that changed everything was simple: what if you broke video into small files and served them over plain {{http-method|HTTP}}? Suddenly any web server, any {{cdn|CDN}}, and any {{http-method|HTTP}} cache in the world could deliver video without special software..." }, { protocolId: 'hls', @@ -534,7 +567,7 @@ export const journeys: Journey[] = [ protocolId: 'tls', title: 'TLS: Encryption', description: - '[[tls|TLS]] is the {{encryption|encryption}} layer that makes secure internet communication possible. During the {{handshake|handshake}}, the server presents a {{certificate|certificate}} signed by a trusted {{certificate-authority|Certificate Authority}}, proving it is who it claims to be (authentication). Both sides negotiate a {{cipher-suite|cipher suite}} and perform a key {{exchange|exchange}} (typically {{ecdhe|ECDHE}} β€” Elliptic Curve Diffie-Hellman Ephemeral) to create shared session keys that provide {{forward-secrecy|forward secrecy}}: even if the server\'s long-term {{private-key|private key}} is later compromised, past recorded sessions cannot be decrypted. Every byte of application data is then encrypted (confidentiality) and authenticated with a {{mac-address|MAC}} (integrity). [[tls|TLS]] 1.3 simplified the protocol dramatically, removing insecure legacy algorithms, reducing the {{handshake|handshake}} to one round trip, and making {{zero-rtt|0-RTT}} resumption possible for repeat connections.', + "[[tls|TLS]] is the {{encryption|encryption}} layer that makes secure internet communication possible. During the {{handshake|handshake}}, the server presents a {{certificate|certificate}} signed by a trusted {{certificate-authority|Certificate Authority}}, proving it is who it claims to be (authentication). Both sides negotiate a {{cipher-suite|cipher suite}} and perform a key {{exchange|exchange}} (typically {{ecdhe|ECDHE}} β€” Elliptic Curve Diffie-Hellman Ephemeral) to create shared session keys that provide {{forward-secrecy|forward secrecy}}: even if the server's long-term {{private-key|private key}} is later compromised, past recorded sessions cannot be decrypted. Every byte of application data is then encrypted (confidentiality) and authenticated with a {{mac-address|MAC}} (integrity). [[tls|TLS]] 1.3 simplified the protocol dramatically, removing insecure legacy algorithms, reducing the {{handshake|handshake}} to one round trip, and making {{zero-rtt|0-RTT}} resumption possible for repeat connections.", transition: '[[tls|TLS]] protects the data flowing over network connections, but server administrators need more than encrypted web traffic β€” they need to securely log into remote machines, transfer configuration files, and set up encrypted tunnels. A purpose-built protocol for secure remote access emerged to fill this gap...' }, @@ -549,8 +582,7 @@ export const journeys: Journey[] = [ { id: 'network-bootstrap', title: 'Getting Online', - description: - 'The chain of protocols that runs every time a device connects to a network.', + description: 'The chain of protocols that runs every time a device connects to a network.', color: '#2DD4BF', scope: 'utilities', steps: [ @@ -566,7 +598,7 @@ export const journeys: Journey[] = [ protocolId: 'ntp', title: 'NTP: Sync the Clock', description: - '[[ntp|NTP]] (Network Time Protocol) synchronizes your device\'s clock with atomic time references accurate to billionths of a second. It uses a clever algorithm that sends multiple time-stamped packets to upstream servers, measures the round-trip delay, and calculates the {{offset|offset}} between your clock and the server\'s clock β€” compensating for the asymmetric network {{latency|latency}}. [[ntp|NTP]] organizes time sources in a stratum hierarchy: stratum 0 is the atomic clock itself, stratum 1 servers {{mqtt-connect|connect}} directly to those clocks, stratum 2 servers sync from stratum 1, and so on. Accurate time is not just a convenience β€” [[tls|TLS]] certificates that appear expired due to {{clock-drift|clock drift}} will be rejected, distributed databases use timestamps for conflict resolution, and forensic logging is useless if you cannot trust when events occurred.', + "[[ntp|NTP]] (Network Time Protocol) synchronizes your device's clock with atomic time references accurate to billionths of a second. It uses a clever algorithm that sends multiple time-stamped packets to upstream servers, measures the round-trip delay, and calculates the {{offset|offset}} between your clock and the server's clock β€” compensating for the asymmetric network {{latency|latency}}. [[ntp|NTP]] organizes time sources in a stratum hierarchy: stratum 0 is the atomic clock itself, stratum 1 servers {{mqtt-connect|connect}} directly to those clocks, stratum 2 servers sync from stratum 1, and so on. Accurate time is not just a convenience β€” [[tls|TLS]] certificates that appear expired due to {{clock-drift|clock drift}} will be rejected, distributed databases use timestamps for conflict resolution, and forensic logging is useless if you cannot trust when events occurred.", transition: 'Your device now has a network address ([[dhcp|DHCP]]) and an accurate clock ([[ntp|NTP]]). The infrastructure is ready. But when you type "gmail.com" into a browser, the network needs to translate that human-friendly name into a machine-routable {{ip-address|IP address}}...' }, @@ -599,14 +631,16 @@ export const journeys: Journey[] = [ title: 'REST: Resources and URLs', description: '[[rest|REST]] (Representational State Transfer) models every piece of data as a resource with a unique {{url|URL}}. Clients interact using standard {{http-method|HTTP}} methods: GET to read, POST to create, PUT to replace, DELETE to remove. [[rest|REST]] APIs are {{stateless|stateless}} β€” every request contains all the information needed to process it, making them easy to cache and scale. The trade-off is rigidity: clients get fixed data structures, often leading to {{over-fetching|over-fetching}} (getting fields they do not need) or under-fetching (needing multiple requests to assemble a view). [[rest|REST]] dominates the web because of its simplicity, but complex UIs with deeply nested data often outgrow it.', - transition: '[[rest|REST]] APIs work well for simple {{crud|CRUD}} operations, but mobile and single-page apps often need data from many related resources in a single screen. What if the client could specify exactly the data it needs in one request?' + transition: + '[[rest|REST]] APIs work well for simple {{crud|CRUD}} operations, but mobile and single-page apps often need data from many related resources in a single screen. What if the client could specify exactly the data it needs in one request?' }, { protocolId: 'graphql', title: 'GraphQL: Ask for Exactly What You Need', description: '[[graphql|GraphQL]] lets clients send a query describing exactly the shape of the data they want, and the server returns only that β€” no more, no less. A single query can traverse relationships (user β†’ posts β†’ comments) that would require multiple [[rest|REST]] endpoints. The schema is typed and introspectable, making APIs self-documenting. Mutations handle writes, and subscriptions push real-time updates over [[websockets|WebSockets]]. The trade-off: the server must resolve arbitrary query shapes, making caching harder (no {{url|URL}}-based caching), rate-limiting more complex (a single query can be expensive), and N+1 database problems common without careful DataLoader usage.', - transition: '[[graphql|GraphQL]] gives clients flexibility, but its text-based {{json|JSON}} format adds overhead. For internal microservice communication where both sides are controlled by the same team, is there an even more efficient option?' + transition: + '[[graphql|GraphQL]] gives clients flexibility, but its text-based {{json|JSON}} format adds overhead. For internal microservice communication where both sides are controlled by the same team, is there an even more efficient option?' }, { protocolId: 'grpc', @@ -629,14 +663,16 @@ export const journeys: Journey[] = [ title: 'OAuth 2.0: Delegated Authorization', description: '[[oauth2|OAuth]] 2.0 solves a fundamental problem: how can a third-party app access your data without knowing your password? Instead of sharing credentials, [[oauth2|OAuth]] uses an authorization server as an intermediary. You authenticate directly with the provider ({{google|Google}}, GitHub), approve specific permissions (scopes), and the provider issues a time-limited {{access-token|access token}} to the app. The Authorization Code flow with {{pkce|PKCE}} is the standard for web and mobile apps β€” it uses a code verifier to prevent interception attacks. Refresh tokens allow silent re-authentication without user interaction. [[oauth2|OAuth]] is authorization (what you can access), not authentication (who you are) β€” OpenID {{mqtt-connect|Connect}} adds the identity layer on top.', - transition: '[[oauth2|OAuth]] tokens travel over the network as Bearer tokens in {{http-method|HTTP}} headers. But how are those {{http-method|HTTP}} connections themselves protected from eavesdroppers? The answer is the {{encryption|encryption}} layer that secures virtually all internet traffic...' + transition: + '[[oauth2|OAuth]] tokens travel over the network as Bearer tokens in {{http-method|HTTP}} headers. But how are those {{http-method|HTTP}} connections themselves protected from eavesdroppers? The answer is the {{encryption|encryption}} layer that secures virtually all internet traffic...' }, { protocolId: 'tls', title: 'TLS: Encrypted Channels', description: - '[[tls|TLS]] protects every [[oauth2|OAuth]] token, every {{api|API}} key, and every password in {{transit|transit}}. During the {{handshake|handshake}}, the server proves its identity with a {{certificate|certificate}} signed by a trusted {{certificate-authority|Certificate Authority}}, and both sides negotiate {{encryption|encryption}} parameters. The key {{exchange|exchange}} ({{ecdhe|ECDHE}}) generates ephemeral session keys that provide {{forward-secrecy|forward secrecy}} β€” even if the server\'s {{private-key|private key}} is later compromised, past sessions remain secure. [[tls|TLS]] 1.3 streamlined this to a single round trip and removed all insecure legacy algorithms. Without [[tls|TLS]], [[oauth2|OAuth]] tokens would be visible to anyone on the network path.', - transition: '[[tls|TLS]] secures data in {{transit|transit}} over the network. But system administrators need a different kind of secure access β€” interactive shell sessions, file transfers, and tunnels to remote machines. A purpose-built protocol provides this with a different trust model...' + "[[tls|TLS]] protects every [[oauth2|OAuth]] token, every {{api|API}} key, and every password in {{transit|transit}}. During the {{handshake|handshake}}, the server proves its identity with a {{certificate|certificate}} signed by a trusted {{certificate-authority|Certificate Authority}}, and both sides negotiate {{encryption|encryption}} parameters. The key {{exchange|exchange}} ({{ecdhe|ECDHE}}) generates ephemeral session keys that provide {{forward-secrecy|forward secrecy}} β€” even if the server's {{private-key|private key}} is later compromised, past sessions remain secure. [[tls|TLS]] 1.3 streamlined this to a single round trip and removed all insecure legacy algorithms. Without [[tls|TLS]], [[oauth2|OAuth]] tokens would be visible to anyone on the network path.", + transition: + '[[tls|TLS]] secures data in {{transit|transit}} over the network. But system administrators need a different kind of secure access β€” interactive shell sessions, file transfers, and tunnels to remote machines. A purpose-built protocol provides this with a different trust model...' }, { protocolId: 'ssh', @@ -659,20 +695,22 @@ export const journeys: Journey[] = [ title: 'ICMP: Is It Alive?', description: 'When something goes wrong on a network, [[icmp|ICMP]] is the first tool you reach for. The {{ping|ping}} command sends an [[icmp|ICMP]] {{echo-request|Echo Request}} to a host and measures the time until the {{echo-reply|Echo Reply}} comes back β€” giving you {{rtt|round-trip time}}, packet loss percentage, and basic reachability in one command. {{traceroute|Traceroute}} exploits [[icmp|ICMP]] in a clever way: it sends packets with incrementally increasing {{ttl|TTL}} ({{ttl|Time to Live}}) values. Each router along the path decrements the {{ttl|TTL}}, and when it hits zero, that router sends back an [[icmp|ICMP]] {{time-exceeded|Time Exceeded}} message β€” revealing its identity and distance. This traces the exact path packets take across the internet, exposing where {{latency|latency}} spikes or failures occur.', - transition: '[[icmp|ICMP]] told you whether a host is reachable and traced the network path to get there. But what if the problem is not routing β€” what if the hostname itself is not resolving to the right {{ip-address|IP address}}? [[dns|DNS]] issues are one of the most common causes of "the internet is broken"...' + transition: + '[[icmp|ICMP]] told you whether a host is reachable and traced the network path to get there. But what if the problem is not routing β€” what if the hostname itself is not resolving to the right {{ip-address|IP address}}? [[dns|DNS]] issues are one of the most common causes of "the internet is broken"...' }, { protocolId: 'dns', title: 'DNS: Is It Resolving?', description: '[[dns|DNS]] problems masquerade as total network failures β€” everything seems down, but the real issue is name resolution. The dig command queries [[dns|DNS]] servers directly, showing you exactly which records are returned, which {{nameserver|nameserver}} answered, the {{ttl|TTL}} remaining on cached entries, and the full query chain. You can query specific record types (A, {{aaaa-record|AAAA}}, {{mx-record|MX}}, {{cname-record|CNAME}}, {{ns-record|NS}}) and specific [[dns|DNS]] servers to isolate whether the problem is your local resolver, the authoritative server, or caching. Common issues include stale cached records (wait for {{ttl|TTL}} expiry or flush the cache), misconfigured {{ns-record|NS}} delegations, missing or incorrect A/{{aaaa-record|AAAA}} records, and {{dnssec|DNSSEC}} validation failures.', - transition: '[[dns|DNS]] resolved the hostname to an {{ip-address|IP address}}, and [[icmp|ICMP]] confirmed the host is reachable at the network layer. But on a local network, there is one more address translation that happens invisibly β€” if this layer breaks, devices on the same {{subnet|subnet}} cannot communicate at all...' + transition: + '[[dns|DNS]] resolved the hostname to an {{ip-address|IP address}}, and [[icmp|ICMP]] confirmed the host is reachable at the network layer. But on a local network, there is one more address translation that happens invisibly β€” if this layer breaks, devices on the same {{subnet|subnet}} cannot communicate at all...' }, { protocolId: 'arp', title: 'ARP: Is Layer 2 Working?', description: - '[[arp|ARP]] operates at the boundary between [[ip|IP]] addresses and physical hardware. When your machine knows the [[ip|IP]] of a target on the same {{subnet|subnet}}, it still needs the target\'s {{mac-address|MAC address}} to build an [[ethernet|Ethernet]] frame. [[arp|ARP]] broadcasts a request to the entire {{lan|LAN}}, and the target responds with its {{mac-address|MAC address}}. The arp command shows the local [[arp|ARP]] cache β€” mapping IPs to MACs β€” and can reveal subtle issues: stale entries pointing to decommissioned hardware, duplicate [[ip|IP]] addresses (two MACs responding for the same [[ip|IP]]), or [[arp|ARP]] poisoning attacks where a malicious device claims to be the gateway. On modern networks, [[arp|ARP]] issues are rare but devastating when they occur, often causing intermittent connectivity that is maddeningly difficult to diagnose without checking the [[arp|ARP]] table directly.' + "[[arp|ARP]] operates at the boundary between [[ip|IP]] addresses and physical hardware. When your machine knows the [[ip|IP]] of a target on the same {{subnet|subnet}}, it still needs the target's {{mac-address|MAC address}} to build an [[ethernet|Ethernet]] frame. [[arp|ARP]] broadcasts a request to the entire {{lan|LAN}}, and the target responds with its {{mac-address|MAC address}}. The arp command shows the local [[arp|ARP]] cache β€” mapping IPs to MACs β€” and can reveal subtle issues: stale entries pointing to decommissioned hardware, duplicate [[ip|IP]] addresses (two MACs responding for the same [[ip|IP]]), or [[arp|ARP]] poisoning attacks where a malicious device claims to be the gateway. On modern networks, [[arp|ARP]] issues are rare but devastating when they occur, often causing intermittent connectivity that is maddeningly difficult to diagnose without checking the [[arp|ARP]] table directly." } ] }, @@ -689,14 +727,16 @@ export const journeys: Journey[] = [ title: 'TCP: The Reliable Foundation', description: '[[tcp|TCP]] was designed for fixed networks where connections are stable and endpoints do not move. It binds a connection to a 4-tuple: source [[ip|IP]], source port, destination [[ip|IP]], destination port. This works perfectly on desktops and servers, but on mobile devices it creates a fragile assumption β€” the moment your phone switches from [[wifi|Wi-Fi]] to cellular (or between cell towers), your {{ip-address|IP address}} changes, and every [[tcp|TCP]] connection silently breaks. The application must detect the failure, re-establish the [[tcp|TCP]] {{handshake|handshake}}, re-negotiate [[tls|TLS]], and re-authenticate. For a video call or file download, this means a visible interruption.', - transition: '[[tcp|TCP]] ties connections to [[ip|IP]] addresses, making them fragile on mobile networks. What if a single connection could span multiple network interfaces simultaneously, surviving handoffs without the application even noticing?' + transition: + '[[tcp|TCP]] ties connections to [[ip|IP]] addresses, making them fragile on mobile networks. What if a single connection could span multiple network interfaces simultaneously, surviving handoffs without the application even noticing?' }, { protocolId: 'mptcp', title: 'MPTCP: Multiple Paths', description: '{{multipath|Multipath}} [[tcp|TCP]] extends [[tcp|TCP]] to use multiple network paths simultaneously. A phone can send data over both [[wifi|Wi-Fi]] and cellular at the same time, seamlessly shifting traffic when one path degrades. When you walk out of [[wifi|Wi-Fi]] range, [[mptcp|MPTCP]] gracefully migrates the connection to cellular without dropping a single byte β€” the application sees one uninterrupted [[tcp|TCP]] stream. {{apple|Apple}} has used [[mptcp|MPTCP]] in iOS since 2013 (for Siri and {{apple|Apple}} Maps) and it is enabled system-wide in iOS 17+. [[mptcp|MPTCP]] is backward-compatible: it falls back to regular [[tcp|TCP]] when the other endpoint does not support it. The trade-off is complexity β€” middleboxes (firewalls, NATs) sometimes strip the [[mptcp|MPTCP]] options they do not understand.', - transition: '[[mptcp|MPTCP]] adds resilience to [[tcp|TCP]], but it inherits [[tcp|TCP]]\'s fundamental limitations: {{head-of-line-blocking|head-of-line blocking}}, ossified middleboxes, and a kernel-level implementation that is slow to deploy. A ground-up redesign built on [[udp|UDP]] avoids all of these constraints...' + transition: + "[[mptcp|MPTCP]] adds resilience to [[tcp|TCP]], but it inherits [[tcp|TCP]]'s fundamental limitations: {{head-of-line-blocking|head-of-line blocking}}, ossified middleboxes, and a kernel-level implementation that is slow to deploy. A ground-up redesign built on [[udp|UDP]] avoids all of these constraints..." }, { protocolId: 'quic', @@ -718,17 +758,17 @@ export const journeys: Journey[] = [ protocolId: 'dns', title: 'DNS: Find the Mail Server', description: - 'When you send an email to user@example.com, your mail server does not just look up example.com\'s {{ip-address|IP address}} β€” it queries [[dns|DNS]] for {{mx-record|MX}} (Mail {{exchange|Exchange}}) records, a special record type that specifies which servers accept email for that domain and their priority ordering. A domain might have multiple {{mx-record|MX}} records (mx1.example.com at priority 10, mx2.example.com at priority 20) for redundancy β€” if the primary mail server is down, the sender automatically tries the backup. Your server also checks {{spf|SPF}} records (which IPs are authorized to send for that domain), {{dkim|DKIM}} records (public keys for verifying message signatures), and {{dmarc|DMARC}} records (the domain\'s policy for handling authentication failures). This [[dns|DNS]] step is where email security begins.', + "When you send an email to user@example.com, your mail server does not just look up example.com's {{ip-address|IP address}} β€” it queries [[dns|DNS]] for {{mx-record|MX}} (Mail {{exchange|Exchange}}) records, a special record type that specifies which servers accept email for that domain and their priority ordering. A domain might have multiple {{mx-record|MX}} records (mx1.example.com at priority 10, mx2.example.com at priority 20) for redundancy β€” if the primary mail server is down, the sender automatically tries the backup. Your server also checks {{spf|SPF}} records (which IPs are authorized to send for that domain), {{dkim|DKIM}} records (public keys for verifying message signatures), and {{dmarc|DMARC}} records (the domain's policy for handling authentication failures). This [[dns|DNS]] step is where email security begins.", transition: - 'The [[dns|DNS]] lookup revealed exactly which servers accept mail for the recipient\'s domain, along with their priority ordering. Now your mail server opens a [[tcp|TCP]] connection to the highest-priority {{mx-record|MX}} server and begins the [[smtp|SMTP]] dialogue to deliver the message...' + "The [[dns|DNS]] lookup revealed exactly which servers accept mail for the recipient's domain, along with their priority ordering. Now your mail server opens a [[tcp|TCP]] connection to the highest-priority {{mx-record|MX}} server and begins the [[smtp|SMTP]] dialogue to deliver the message..." }, { protocolId: 'smtp', title: 'SMTP: Send the Email', description: - '[[smtp|SMTP]] is one of the oldest internet protocols still in active use β€” its text-based command dialogue has remained remarkably stable since 1982. Your mail server connects to the recipient\'s {{mx-record|MX}} server and they {{exchange|exchange}} greetings ({{ehlo|EHLO}}, which also advertises supported extensions like {{starttls|STARTTLS}} and SIZE). After upgrading to an encrypted connection via {{starttls|STARTTLS}}, the envelope is defined: {{smtp-mail-from|MAIL FROM}} specifies the bounce address, {{smtp-rcpt-to|RCPT TO}} identifies the recipient(s). Then the {{smtp-data|DATA}} command signals that the message body follows β€” headers (From, To, Subject, Date, Message-{{id-identifier|ID}}), {{mime|MIME}} parts (text/plain, text/html), and base64-encoded attachments, terminated by a lone period on a line. The receiving server may relay the message through additional hops (forwarding, mailing lists) before final delivery to the recipient\'s mailbox.', + "[[smtp|SMTP]] is one of the oldest internet protocols still in active use β€” its text-based command dialogue has remained remarkably stable since 1982. Your mail server connects to the recipient's {{mx-record|MX}} server and they {{exchange|exchange}} greetings ({{ehlo|EHLO}}, which also advertises supported extensions like {{starttls|STARTTLS}} and SIZE). After upgrading to an encrypted connection via {{starttls|STARTTLS}}, the envelope is defined: {{smtp-mail-from|MAIL FROM}} specifies the bounce address, {{smtp-rcpt-to|RCPT TO}} identifies the recipient(s). Then the {{smtp-data|DATA}} command signals that the message body follows β€” headers (From, To, Subject, Date, Message-{{id-identifier|ID}}), {{mime|MIME}} parts (text/plain, text/html), and base64-encoded attachments, terminated by a lone period on a line. The receiving server may relay the message through additional hops (forwarding, mailing lists) before final delivery to the recipient's mailbox.", transition: - 'The email has traversed the internet and landed safely in the recipient\'s mailbox on their mail server. But it is just sitting there as a file on a remote disk β€” the recipient needs a way to discover it, download it, organize it into folders, and keep everything synchronized across their phone, laptop, and web client...' + "The email has traversed the internet and landed safely in the recipient's mailbox on their mail server. But it is just sitting there as a file on a remote disk β€” the recipient needs a way to discover it, download it, organize it into folders, and keep everything synchronized across their phone, laptop, and web client..." }, { protocolId: 'imap', @@ -754,34 +794,38 @@ export const journeys: Journey[] = [ title: 'JSON-RPC: The Wire Format', description: 'Before {{ai|AI}} protocols existed, [[json-rpc|JSON-RPC]] 2.0 was already the wire format of choice for infrastructure β€” Ethereum nodes, Bitcoin Core, and the {{lsp|Language Server Protocol}} in VS Code all spoke [[json-rpc|JSON-RPC]]. Its appeal was radical simplicity: send a {{json|JSON}} object with a method name, params, and an {{id-identifier|ID}}; get back a result or error with the same {{id-identifier|ID}}. No schema files, no code generation, no binary encoding. When {{anthropic|Anthropic}} and {{google|Google}} independently designed their {{ai|AI}} protocols, both chose [[json-rpc|JSON-RPC]] 2.0 as the foundation β€” not because it was trendy, but because it was the simplest thing that could possibly work.', - transition: '[[json-rpc|JSON-RPC]] provides the wire framing, but it says nothing about what methods should exist, what parameters they should take, or how {{ai|AI}} applications should discover tools. A higher-level protocol was needed to define the semantics of {{ai|AI}} tool use...' + transition: + '[[json-rpc|JSON-RPC]] provides the wire framing, but it says nothing about what methods should exist, what parameters they should take, or how {{ai|AI}} applications should discover tools. A higher-level protocol was needed to define the semantics of {{ai|AI}} tool use...' }, { protocolId: 'mcp', title: 'MCP: Connecting Agents to Tools', description: 'The Model Context Protocol solves the NΓ—M integration problem. Before [[mcp|MCP]], connecting Claude to your database required custom code β€” different from connecting it to GitHub, different from Slack. [[mcp|MCP]] provides a universal interface: an [[mcp|MCP]] server exposes tools (actions the {{llm|LLM}} can invoke), resources (data it can read), and prompts (templates it can use). The three-step initialization {{handshake|handshake}} negotiates capabilities, then the {{ai|AI}} host discovers available tools via tools/list and invokes them via tools/call. A single host can {{mqtt-connect|connect}} to dozens of [[mcp|MCP]] servers simultaneously β€” one for your database, one for git, one for Slack β€” all through the same protocol.', - transition: '[[mcp|MCP]] beautifully connects a single agent to its tools. But what happens when the task requires multiple specialized agents β€” a travel agent, a research agent, a booking agent β€” each with their own tools and expertise? A different protocol handles that layer of coordination...' + transition: + '[[mcp|MCP]] beautifully connects a single agent to its tools. But what happens when the task requires multiple specialized agents β€” a travel agent, a research agent, a booking agent β€” each with their own tools and expertise? A different protocol handles that layer of coordination...' }, { protocolId: 'a2a', title: 'A2A: Connecting Agents to Agents', description: - 'The Agent-to-Agent Protocol picks up where [[mcp|MCP]] leaves off. While [[mcp|MCP]] is vertical (agent-to-tools), [[a2a|A2A]] is horizontal (agent-to-agent). Each agent publishes an {{agent-card|Agent Card}} at /.well-known/agent.{{json|json}} describing its skills and capabilities. A coordinator agent discovers specialist agents, delegates tasks via message/send, and receives structured results as Artifacts. Tasks have a full lifecycle β€” submitted, working, input-required, completed β€” with [[sse|SSE]] streaming for real-time progress. The key design insight is {{opacity|opacity}}: you don\'t see another agent\'s internal reasoning or tool usage, only its skills and outputs. This allows agents from different vendors, built with different frameworks, to collaborate seamlessly.', - transition: 'In a production system, [[a2a|A2A]] and [[mcp|MCP]] work together. The coordinator uses [[a2a|A2A]] to delegate to a specialist, and that specialist uses [[mcp|MCP]] internally to access its tools. But both protocols rely on the same real-time streaming mechanism to deliver incremental results...' + "The Agent-to-Agent Protocol picks up where [[mcp|MCP]] leaves off. While [[mcp|MCP]] is vertical (agent-to-tools), [[a2a|A2A]] is horizontal (agent-to-agent). Each agent publishes an {{agent-card|Agent Card}} at /.well-known/agent.{{json|json}} describing its skills and capabilities. A coordinator agent discovers specialist agents, delegates tasks via message/send, and receives structured results as Artifacts. Tasks have a full lifecycle β€” submitted, working, input-required, completed β€” with [[sse|SSE]] streaming for real-time progress. The key design insight is {{opacity|opacity}}: you don't see another agent's internal reasoning or tool usage, only its skills and outputs. This allows agents from different vendors, built with different frameworks, to collaborate seamlessly.", + transition: + 'In a production system, [[a2a|A2A]] and [[mcp|MCP]] work together. The coordinator uses [[a2a|A2A]] to delegate to a specialist, and that specialist uses [[mcp|MCP]] internally to access its tools. But both protocols rely on the same real-time streaming mechanism to deliver incremental results...' }, { protocolId: 'sse', title: 'SSE: Streaming AI Responses', description: - '[[sse|Server-Sent Events]] tie everything together at the transport level. When an [[mcp|MCP]] tool takes time to produce results, the server upgrades its [[http1|HTTP]] response to an [[sse|SSE]] stream, pushing progress {{notification|notifications}} and partial results as events. When an [[a2a|A2A]] agent works on a long task, it streams TaskStatusUpdate and TaskArtifactUpdate events via [[sse|SSE]]. Even the token-by-token streaming you see in chat interfaces is [[sse|SSE]] under the hood. The {{eventsource|EventSource API}}\'s auto-reconnection means that if the connection drops mid-stream, the client reconnects and resumes from the last event {{id-identifier|ID}} β€” no data lost, no user intervention needed.' + "[[sse|Server-Sent Events]] tie everything together at the transport level. When an [[mcp|MCP]] tool takes time to produce results, the server upgrades its [[http1|HTTP]] response to an [[sse|SSE]] stream, pushing progress {{notification|notifications}} and partial results as events. When an [[a2a|A2A]] agent works on a long task, it streams TaskStatusUpdate and TaskArtifactUpdate events via [[sse|SSE]]. Even the token-by-token streaming you see in chat interfaces is [[sse|SSE]] under the hood. The {{eventsource|EventSource API}}'s auto-reconnection means that if the connection drops mid-stream, the client reconnects and resumes from the last event {{id-identifier|ID}} β€” no data lost, no user intervention needed." } ] }, { id: 'api-evolution', title: 'From REST to AI Protocols', - description: 'The evolution of web APIs β€” from resource-oriented [[rest|REST]] to {{ai|AI}}-native protocols.', + description: + 'The evolution of web APIs β€” from resource-oriented [[rest|REST]] to {{ai|AI}}-native protocols.', color: '#00D4FF', scope: 'global', steps: [ @@ -789,35 +833,39 @@ export const journeys: Journey[] = [ protocolId: 'rest', title: 'REST: The Foundation', description: - '[[pioneer:roy-fielding|Roy Fielding]]\'s 2000 dissertation defined [[rest|REST]] as an architectural style: use [[http1|HTTP]] verbs for operations, URLs for resources, and make everything {{stateless|stateless}}. [[rest|REST]] dominated the {{api|API}} landscape for two decades because of its simplicity β€” any language with an [[http1|HTTP]] client could call a [[rest|REST]] {{api|API}}. But [[rest|REST]] was designed for human developers building web applications, not for {{ai|AI}} systems that need to dynamically discover and invoke capabilities. {{over-fetching|Over-fetching}}, under-fetching, and the lack of machine-readable schemas were annoyances for developers but blockers for autonomous agents.', - transition: '[[rest|REST]] served the web brilliantly for human-to-machine communication. But as systems grew more complex, developers needed richer patterns β€” typed contracts, efficient {{serialization|serialization}}, and flexible data fetching...' + "[[pioneer:roy-fielding|Roy Fielding]]'s 2000 dissertation defined [[rest|REST]] as an architectural style: use [[http1|HTTP]] verbs for operations, URLs for resources, and make everything {{stateless|stateless}}. [[rest|REST]] dominated the {{api|API}} landscape for two decades because of its simplicity β€” any language with an [[http1|HTTP]] client could call a [[rest|REST]] {{api|API}}. But [[rest|REST]] was designed for human developers building web applications, not for {{ai|AI}} systems that need to dynamically discover and invoke capabilities. {{over-fetching|Over-fetching}}, under-fetching, and the lack of machine-readable schemas were annoyances for developers but blockers for autonomous agents.", + transition: + '[[rest|REST]] served the web brilliantly for human-to-machine communication. But as systems grew more complex, developers needed richer patterns β€” typed contracts, efficient {{serialization|serialization}}, and flexible data fetching...' }, { protocolId: 'grpc', title: 'gRPC: Typed, Efficient RPC', description: - '{{google|Google}}\'s internal {{rpc|RPC}} system, Stubby, handled billions of requests per day. When they open-sourced it as [[grpc|gRPC]] in 2015, it brought {{protocol-buffers|protocol buffers}} (binary {{serialization|serialization}} 3-10x smaller than {{json|JSON}}), [[http2|HTTP/2]] {{multiplexing|multiplexing}}, and streaming to the developer community. For the first time, {{api|API}} contracts were machine-enforced at compile time via .proto files. The tradeoff was complexity β€” code generation, [[http2|HTTP/2]] requirements, and binary payloads that couldn\'t be debugged with curl. But for service-to-service communication at scale, [[grpc|gRPC]] was a revelation.', - transition: '[[grpc|gRPC]] optimized for machine-to-machine efficiency, but it required schema compilation and couldn\'t easily serve browser clients. What if there was something in between β€” human-readable like [[rest|REST]] but with typed schemas and flexible querying?' + "{{google|Google}}'s internal {{rpc|RPC}} system, Stubby, handled billions of requests per day. When they open-sourced it as [[grpc|gRPC]] in 2015, it brought {{protocol-buffers|protocol buffers}} (binary {{serialization|serialization}} 3-10x smaller than {{json|JSON}}), [[http2|HTTP/2]] {{multiplexing|multiplexing}}, and streaming to the developer community. For the first time, {{api|API}} contracts were machine-enforced at compile time via .proto files. The tradeoff was complexity β€” code generation, [[http2|HTTP/2]] requirements, and binary payloads that couldn't be debugged with curl. But for service-to-service communication at scale, [[grpc|gRPC]] was a revelation.", + transition: + "[[grpc|gRPC]] optimized for machine-to-machine efficiency, but it required schema compilation and couldn't easily serve browser clients. What if there was something in between β€” human-readable like [[rest|REST]] but with typed schemas and flexible querying?" }, { protocolId: 'json-rpc', title: 'JSON-RPC: The Minimal Wire Format', description: - 'While [[rest|REST]] and [[grpc|gRPC]] dominated mainstream APIs, a quieter revolution was happening in infrastructure. [[json-rpc|JSON-RPC]] 2.0 β€” a one-page spec for calling methods by name over {{json|JSON}} β€” became the backbone of Ethereum\'s blockchain {{api|API}}, Bitcoin Core, and {{microsoft|Microsoft}}\'s {{lsp|Language Server Protocol}}. Its appeal was radical simplicity: no {{url|URL}} routing, no [[http1|HTTP]] verb semantics, no schema compilation. Just a method name, params, and an {{id-identifier|ID}}. The spec was so simple and transport-agnostic ([[http1|HTTP]], [[websockets|WebSocket]], {{stdio|stdio}}, [[tcp|TCP]]) that it became the natural foundation for the next generation of protocols.', - transition: '[[json-rpc|JSON-RPC]] proved that method-oriented {{rpc|RPC}} over {{json|JSON}} was powerful enough for critical infrastructure. When the {{ai|AI}} revolution demanded new protocols for tool use and agent collaboration, [[json-rpc|JSON-RPC]] was the obvious wire format...' + "While [[rest|REST]] and [[grpc|gRPC]] dominated mainstream APIs, a quieter revolution was happening in infrastructure. [[json-rpc|JSON-RPC]] 2.0 β€” a one-page spec for calling methods by name over {{json|JSON}} β€” became the backbone of Ethereum's blockchain {{api|API}}, Bitcoin Core, and {{microsoft|Microsoft}}'s {{lsp|Language Server Protocol}}. Its appeal was radical simplicity: no {{url|URL}} routing, no [[http1|HTTP]] verb semantics, no schema compilation. Just a method name, params, and an {{id-identifier|ID}}. The spec was so simple and transport-agnostic ([[http1|HTTP]], [[websockets|WebSocket]], {{stdio|stdio}}, [[tcp|TCP]]) that it became the natural foundation for the next generation of protocols.", + transition: + '[[json-rpc|JSON-RPC]] proved that method-oriented {{rpc|RPC}} over {{json|JSON}} was powerful enough for critical infrastructure. When the {{ai|AI}} revolution demanded new protocols for tool use and agent collaboration, [[json-rpc|JSON-RPC]] was the obvious wire format...' }, { protocolId: 'mcp', title: 'MCP: AI-Native Tool Access', description: - 'In November 2024, {{anthropic|Anthropic}} released the Model Context Protocol β€” the first protocol designed specifically for {{ai|AI}} applications. Built on [[json-rpc|JSON-RPC]] 2.0, [[mcp|MCP]] provides dynamic tool discovery (tools/list returns {{json|JSON}} Schema definitions that LLMs can understand), resource access (files, database rows, {{api|API}} responses), and prompt templates. The key insight was that {{ai|AI}} applications don\'t just need APIs β€” they need self-describing APIs that an {{llm|LLM}} can discover, understand, and invoke autonomously. Within a year, Claude, ChatGPT, Copilot, Cursor, and VS Code all spoke [[mcp|MCP]], with over 10,000 [[mcp|MCP]] servers in production.', - transition: '[[mcp|MCP]] connected {{ai|AI}} agents to tools, solving the integration problem. But the next challenge was bigger: how do you get multiple {{ai|AI}} agents β€” potentially from different vendors, built with different frameworks β€” to collaborate on complex tasks?' + "In November 2024, {{anthropic|Anthropic}} released the Model Context Protocol β€” the first protocol designed specifically for {{ai|AI}} applications. Built on [[json-rpc|JSON-RPC]] 2.0, [[mcp|MCP]] provides dynamic tool discovery (tools/list returns {{json|JSON}} Schema definitions that LLMs can understand), resource access (files, database rows, {{api|API}} responses), and prompt templates. The key insight was that {{ai|AI}} applications don't just need APIs β€” they need self-describing APIs that an {{llm|LLM}} can discover, understand, and invoke autonomously. Within a year, Claude, ChatGPT, Copilot, Cursor, and VS Code all spoke [[mcp|MCP]], with over 10,000 [[mcp|MCP]] servers in production.", + transition: + '[[mcp|MCP]] connected {{ai|AI}} agents to tools, solving the integration problem. But the next challenge was bigger: how do you get multiple {{ai|AI}} agents β€” potentially from different vendors, built with different frameworks β€” to collaborate on complex tasks?' }, { protocolId: 'a2a', title: 'A2A: AI-Native Agent Collaboration', description: - '{{google|Google}}\'s Agent-to-Agent Protocol, announced in April 2025, completed the picture. Where [[mcp|MCP]] connects agents to tools, [[a2a|A2A]] connects agents to each other. An agent publishes its skills in an {{agent-card|Agent Card}}, and other agents discover it, delegate tasks, and receive structured results β€” all without knowing anything about the internal implementation. The task lifecycle (submitted β†’ working β†’ completed) with [[sse|SSE]] streaming provides the coordination primitives that multi-agent systems need. Together, [[mcp|MCP]] and [[a2a|A2A]] form the two-protocol foundation of the agentic {{ai|AI}} era β€” donated to the {{linux|Linux}} Foundation as open industry standards.' + "{{google|Google}}'s Agent-to-Agent Protocol, announced in April 2025, completed the picture. Where [[mcp|MCP]] connects agents to tools, [[a2a|A2A]] connects agents to each other. An agent publishes its skills in an {{agent-card|Agent Card}}, and other agents discover it, delegate tasks, and receive structured results β€” all without knowing anything about the internal implementation. The task lifecycle (submitted β†’ working β†’ completed) with [[sse|SSE]] streaming provides the coordination primitives that multi-agent systems need. Together, [[mcp|MCP]] and [[a2a|A2A]] form the two-protocol foundation of the agentic {{ai|AI}} era β€” donated to the {{linux|Linux}} Foundation as open industry standards." } ] }, @@ -836,35 +884,40 @@ export const journeys: Journey[] = [ title: 'Field on β€” phone harvests power inductively', description: "The terminal's antenna is radiating a 13.56 MHz magnetic field continuously. When you bring your phone within ~4 cm, the phone's [[nfc|NFC]] controller and {{ese|embedded Secure Element}} harvest microwatts directly from the field β€” no battery contribution needed on the {{se-secure-element|SE}} side. This is the {{inductive-coupling|inductive coupling}} that makes [[nfc|NFC]] work: magnetic field falls off as 1/rΒ³, which is exactly why 10 cm is a feature, not a bug. The biometric release (Face {{id-identifier|ID}} / Touch {{id-identifier|ID}}) had to happen *before* this point β€” the eSE applet is now armed and waiting.", - transition: 'The phone is powered and the terminal needs to discover what kind of card is in the field. {{iso|ISO}} 14443-3 defines a tight {{anti-collision|anti-collision}} sequence β€” {{reqa|REQA}} / {{atqa|ATQA}} / {{sel-iso|SEL}} / {{sak|SAK}} β€” that completes in under 20 ms...' + transition: + 'The phone is powered and the terminal needs to discover what kind of card is in the field. {{iso|ISO}} 14443-3 defines a tight {{anti-collision|anti-collision}} sequence β€” {{reqa|REQA}} / {{atqa|ATQA}} / {{sel-iso|SEL}} / {{sak|SAK}} β€” that completes in under 20 ms...' }, { protocolId: 'nfc', title: 'Anti-collision + RATS/ATS β€” negotiate framing', description: - "The terminal sends a 7-bit `0x26` {{reqa|REQA}}. The eSE replies with **{{atqa|ATQA}}** declaring a 4-byte {{uid|UID}} and standard {{anti-collision|anti-collision}}. The terminal then runs the bit-frame {{anti-collision|anti-collision}} loop (`{{sel-iso|SEL}}=0x93`, `NVB=0x20` β†’ {{uid|UID}} β†’ `NVB=0x70`) to converge on the {{frame|frame}} {{uid|UID}}, ending in **{{sak|SAK}}** = `0x28` β€” bit 6 set means *I speak {{iso|ISO}} 14443-4*. The terminal sends **{{rats|RATS}}**, the eSE replies with **{{ats-nfc|ATS}}** declaring its frame-size budget (FSCI=5 = 64 bytes max). Both ends now know how to {{packet|packet}}ise the {{emv-cryptogram|EMV}} {{exchange|exchange}}.", - transition: "With 14443-4 framing established, the terminal switches into {{iso|ISO}} 7816-4 {{apdu|APDU}} mode and asks the canonical {{emv-cryptogram|EMV}} opening question: *which payment networks do you support?*" + 'The terminal sends a 7-bit `0x26` {{reqa|REQA}}. The eSE replies with **{{atqa|ATQA}}** declaring a 4-byte {{uid|UID}} and standard {{anti-collision|anti-collision}}. The terminal then runs the bit-frame {{anti-collision|anti-collision}} loop (`{{sel-iso|SEL}}=0x93`, `NVB=0x20` β†’ {{uid|UID}} β†’ `NVB=0x70`) to converge on the {{frame|frame}} {{uid|UID}}, ending in **{{sak|SAK}}** = `0x28` β€” bit 6 set means *I speak {{iso|ISO}} 14443-4*. The terminal sends **{{rats|RATS}}**, the eSE replies with **{{ats-nfc|ATS}}** declaring its frame-size budget (FSCI=5 = 64 bytes max). Both ends now know how to {{packet|packet}}ise the {{emv-cryptogram|EMV}} {{exchange|exchange}}.', + transition: + 'With 14443-4 framing established, the terminal switches into {{iso|ISO}} 7816-4 {{apdu|APDU}} mode and asks the canonical {{emv-cryptogram|EMV}} opening question: *which payment networks do you support?*' }, { protocolId: 'nfc', title: 'SELECT PPSE β†’ SELECT AID β€” enumerate payment apps', description: - "The terminal sends `00 A4 04 00 0E 32 50 41 59 2E 53 59 53 2E 44 44 46 30 31` β€” {{imap-select|SELECT}} **{{ppse|PPSE}}** (Proximity Payment System Environment, the magic {{aid|AID}} `2PAY.SYS.DDF01`). The eSE returns an FCI Template listing every payment {{aid|AID}} it supports in priority order β€” Mastercard `A0000000041010`, Visa `A0000000031010`, etc. The terminal picks the highest-priority one and SELECTs it; the card returns its **{{pdol|PDOL}}** β€” the list of {{emv-cryptogram|EMV}} tags the card needs filled in to compute the cryptogram (amount, currency, country, terminal type, Unpredictable Number).", - transition: 'The card now knows what payment network it is on; the terminal knows what data the card wants. Time to bind the transaction: amount, currency, a fresh random {{nonce|nonce}}.' + 'The terminal sends `00 A4 04 00 0E 32 50 41 59 2E 53 59 53 2E 44 44 46 30 31` β€” {{imap-select|SELECT}} **{{ppse|PPSE}}** (Proximity Payment System Environment, the magic {{aid|AID}} `2PAY.SYS.DDF01`). The eSE returns an FCI Template listing every payment {{aid|AID}} it supports in priority order β€” Mastercard `A0000000041010`, Visa `A0000000031010`, etc. The terminal picks the highest-priority one and SELECTs it; the card returns its **{{pdol|PDOL}}** β€” the list of {{emv-cryptogram|EMV}} tags the card needs filled in to compute the cryptogram (amount, currency, country, terminal type, Unpredictable Number).', + transition: + 'The card now knows what payment network it is on; the terminal knows what data the card wants. Time to bind the transaction: amount, currency, a fresh random {{nonce|nonce}}.' }, { protocolId: 'nfc', title: 'GENERATE AC β€” the cryptogram', description: - "After GET PROCESSING OPTIONS (returning AIP+{{afl|AFL}}) and {{read-record|READ RECORD}} Γ—N (pulling the **{{dpan|DPAN}}**, expiry, {{certificate-chain|certificate chain}}), the terminal sends `80 AE 80 00` {{generate-ac|GENERATE AC}} with the filled CDOL1 data. The eSE composes the inputs (amount, currency, country, TVR, {{atc|ATC}}, Unpredictable Number, AIP) and runs them through {{aes|AES}}-{{mac-address|MAC}} under the per-{{dpan|DPAN}} key, producing the **{{emv-cryptogram|Application Cryptogram (ARQC)}}**. The {{anti-replay|ATC}} (Application Transaction Counter) has already incremented by 1; the cryptogram is unforgeable without the eSE key.", - transition: "The cryptogram is now in the terminal's hand. But the eSE has no online connection β€” it can't authorise the transaction itself. The terminal needs to send the {{arqc|ARQC}} to the issuer bank, which is somewhere on the other end of the carrier network..." + 'After GET PROCESSING OPTIONS (returning AIP+{{afl|AFL}}) and {{read-record|READ RECORD}} Γ—N (pulling the **{{dpan|DPAN}}**, expiry, {{certificate-chain|certificate chain}}), the terminal sends `80 AE 80 00` {{generate-ac|GENERATE AC}} with the filled CDOL1 data. The eSE composes the inputs (amount, currency, country, TVR, {{atc|ATC}}, Unpredictable Number, AIP) and runs them through {{aes|AES}}-{{mac-address|MAC}} under the per-{{dpan|DPAN}} key, producing the **{{emv-cryptogram|Application Cryptogram (ARQC)}}**. The {{anti-replay|ATC}} (Application Transaction Counter) has already incremented by 1; the cryptogram is unforgeable without the eSE key.', + transition: + "The cryptogram is now in the terminal's hand. But the eSE has no online connection β€” it can't authorise the transaction itself. The terminal needs to send the {{arqc|ARQC}} to the issuer bank, which is somewhere on the other end of the carrier network..." }, { protocolId: 'cellular', title: 'Backhaul over LTE / 5G to the acquirer', description: "Modern wireless POS terminals (Square, Stripe, Verifone Engage) send the {{arqc|ARQC}} to the acquirer over [[cellular|cellular]] data β€” {{lte|LTE}} Cat-1 or 5G in 2026. The terminal opens a [[tls|TLS]] connection to the acquirer's {{api|API}} endpoint, posts a {{json|JSON}} body containing the cryptogram + transaction details. The carrier core wraps the [[ip|IP]] traffic in **{{gtp-u|GTP-U}} over [[ipsec|IPsec ESP]]** between the gNB and {{upf|UPF}} β€” per {{3gpp|3GPP}} {{ts-3gpp|TS}} 33.501, every backhaul {{hop|hop}} is IPsec-wrapped. The single largest enterprise [[ipsec|IPsec]] deployment on Earth lives inside this layer.", - transition: "The cryptogram reaches the acquirer; the acquirer routes it through the payment network (Mastercard / Visa) to the issuing bank's {{hsm|HSM}}..." + transition: + "The cryptogram reaches the acquirer; the acquirer routes it through the payment network (Mastercard / Visa) to the issuing bank's {{hsm|HSM}}..." }, { protocolId: 'tls', @@ -888,21 +941,24 @@ export const journeys: Journey[] = [ title: 'BLE advertising β€” the car says hello on ch 37/38/39', description: "The car's {{ble|BLE}} radio broadcasts `{{adv-ind|ADV_IND}}` on advertising channels 37 (2402 MHz), 38 (2426 MHz), and 39 (2480 MHz) every 100 ms or so β€” three channels carefully chosen to avoid [[wifi|Wi-Fi]]'s 1/6/11. The advert carries the {{ccc-digital-key|CCC Digital Key}} service {{uuid|UUID}} and an ephemeral identifier. Your iPhone (or Galaxy, or {{android|Android}} phone with {{aliro|Aliro}}) scans those channels continuously. When the phone sees the car's {{uuid|UUID}}, it sends `{{connect-ind|CONNECT_IND}}` β€” switching both radios from advertising channels to one of the 37 data channels β€” and the {{ble|BLE}} link is up.", - transition: '{{ble|BLE}} is now connected, but {{ble|BLE}} alone proved insecure in 2022 β€” Sultan Qasim Khan unlocked a parked Tesla from 25 m using $50 of dev boards by relaying the {{ble|BLE}} signals. {{ccc-digital-key|CCC Digital Key}} 3.0 fixes this with a layered cryptographic + physical defence...' + transition: + '{{ble|BLE}} is now connected, but {{ble|BLE}} alone proved insecure in 2022 β€” Sultan Qasim Khan unlocked a parked Tesla from 25 m using $50 of dev boards by relaying the {{ble|BLE}} signals. {{ccc-digital-key|CCC Digital Key}} 3.0 fixes this with a layered cryptographic + physical defence...' }, { protocolId: 'bluetooth', title: 'GATT pairing + SPAKE2+ authentication', description: - "Over the {{ble|BLE}} encrypted channel, the car and the phone run **{{spake2|SPAKE2}}+ / {{pake|PAKE}}** authentication β€” the car proves it has the right vehicle key, the phone proves it has the right Digital Key applet in its {{ese|embedded Secure Element}}. {{apdu|APDUs}} flow over {{gatt|GATT}} carrying the {{emv-cryptogram|EMV}}-style {{certificate-chain|certificate chain}}. Both sides now share session keys. The next critical message: the car sends the phone the **STS_KEY** β€” a 128-bit {{aes|AES}} key for the upcoming [[uwb|UWB]] ranging session β€” over the now-encrypted {{ble|BLE}} channel. [[uwb|UWB]] has no power-efficient discovery of its own; {{ble|BLE}} provides the on-ramp.", - transition: 'The phone has the STS_KEY. The car has the STS_KEY. Both fire up their [[uwb|UWB]] radios for the ranging round that proves *the phone is actually here*, not relayed from across the parking lot...' + 'Over the {{ble|BLE}} encrypted channel, the car and the phone run **{{spake2|SPAKE2}}+ / {{pake|PAKE}}** authentication β€” the car proves it has the right vehicle key, the phone proves it has the right Digital Key applet in its {{ese|embedded Secure Element}}. {{apdu|APDUs}} flow over {{gatt|GATT}} carrying the {{emv-cryptogram|EMV}}-style {{certificate-chain|certificate chain}}. Both sides now share session keys. The next critical message: the car sends the phone the **STS_KEY** β€” a 128-bit {{aes|AES}} key for the upcoming [[uwb|UWB]] ranging session β€” over the now-encrypted {{ble|BLE}} channel. [[uwb|UWB]] has no power-efficient discovery of its own; {{ble|BLE}} provides the on-ramp.', + transition: + 'The phone has the STS_KEY. The car has the STS_KEY. Both fire up their [[uwb|UWB]] radios for the ranging round that proves *the phone is actually here*, not relayed from across the parking lot...' }, { protocolId: 'uwb', title: 'UWB DS-TWR β€” three messages, six timestamps, cm-class distance', description: - "The phone transmits a **Poll** RFRAME on [[uwb|UWB]] Channel 9 (7987.2 MHz, 499.2 MHz {{bandwidth|bandwidth}}, {{bprf|BPRF}} mode, 6.81 Mbps). The frame carries a 32-chip **{{sts|STS}}** (Scrambled Timestamp Sequence) generated by `{{aes-128|AES-128}}-CTR(STS_KEY, {{nonce|nonce}})` β€” the {{aes|AES}}-keyed pulse pattern an attacker without STS_KEY cannot predict. The phone records `t1 = TX timestamp` at the {{sfd|SFD}} with ~15 ps resolution. The car (multiple anchors typically) RX-timestamps at t2, delays by `T_reply1` (~200 Β΅s), transmits **Response** carrying t2 + t3. Phone records t4 = RX. Phone delays by T_reply2, transmits **Final** carrying t1, t4, t5. Car records t6 = RX. All six timestamps now exist.", - transition: 'The car can now compute {{tof-ranging|time-of-flight}}. The cross-product formula cancels relative {{clock-drift|clock drift}} to first order β€” {{ds-twr|DS-TWR}} is insensitive to 20 ppm crystal offsets. Multiply ToF by the speed of light and you have distance...' + 'The phone transmits a **Poll** RFRAME on [[uwb|UWB]] Channel 9 (7987.2 MHz, 499.2 MHz {{bandwidth|bandwidth}}, {{bprf|BPRF}} mode, 6.81 Mbps). The frame carries a 32-chip **{{sts|STS}}** (Scrambled Timestamp Sequence) generated by `{{aes-128|AES-128}}-CTR(STS_KEY, {{nonce|nonce}})` β€” the {{aes|AES}}-keyed pulse pattern an attacker without STS_KEY cannot predict. The phone records `t1 = TX timestamp` at the {{sfd|SFD}} with ~15 ps resolution. The car (multiple anchors typically) RX-timestamps at t2, delays by `T_reply1` (~200 Β΅s), transmits **Response** carrying t2 + t3. Phone records t4 = RX. Phone delays by T_reply2, transmits **Final** carrying t1, t4, t5. Car records t6 = RX. All six timestamps now exist.', + transition: + 'The car can now compute {{tof-ranging|time-of-flight}}. The cross-product formula cancels relative {{clock-drift|clock drift}} to first order β€” {{ds-twr|DS-TWR}} is insensitive to 20 ppm crystal offsets. Multiply ToF by the speed of light and you have distance...' }, { protocolId: 'uwb', @@ -926,27 +982,30 @@ export const journeys: Journey[] = [ title: 'Beacon Request β€” joiner asks "any networks?"', description: "The new bulb powers on, has no parent yet, and broadcasts an {{ieee-802-15-4|IEEE 802.15.4}} {{mac-address|MAC}} Command `0x07` (**Beacon Request**) on its channel β€” picked from {15, 20, 25, 26} to dodge [[wifi|Wi-Fi]] 1/6/11 at 2412/2437/2462 MHz. Every {{zigbee-router|Zigbee router}} with permit-joining enabled responds with a **Beacon**: the {{pan-id|PAN ID}}, the Coordinator's {{short-address|short address}} (0x0000), the Stack Profile (Zigbee PRO), and the Permit-Joining flag. The joiner picks the best parent by {{rssi|RSSI}} + LQI. This is the slowest step β€” beacon scanning can take 2–4 seconds across all candidate channels.", - transition: 'The bulb has picked a parent. Now it needs a {{short-address|short address}} β€” a 16-bit local identifier much cheaper than its 64-bit {{eui-64|EUI-64}} on every frame for the rest of its life on this network...' + transition: + 'The bulb has picked a parent. Now it needs a {{short-address|short address}} β€” a 16-bit local identifier much cheaper than its 64-bit {{eui-64|EUI-64}} on every frame for the rest of its life on this network...' }, { protocolId: 'zigbee', title: 'Association Request + Response β€” get a short address', description: "The bulb sends {{mac-address|MAC}} Command `0x01` (**{{association-request|Association Request}}**) with its Capability byte (`0x8E` = {{ffd|FFD}}, mains-powered, security-capable, allocate-short). The Coordinator allocates a unique 16-bit {{short-address|short address}} (e.g. `0x3F4E`) and replies with {{mac-address|MAC}} Command `0x02` (**{{association-response|Association Response}}**). The bulb is now associated with the network at the {{mac-address|MAC}} layer β€” but it doesn't have the **{{network-key|network key}}** yet, which means it can't decrypt or {{encryption|encrypt}} any actual Zigbee frames. The critical security step is next.", - transition: 'Without the {{network-key|network key}} the bulb is useless. The Coordinator (acting as {{trust-center|Trust Center}}) needs to securely deliver it β€” and how it does that is the single most important security decision in the whole Zigbee architecture...' + transition: + 'Without the {{network-key|network key}} the bulb is useless. The Coordinator (acting as {{trust-center|Trust Center}}) needs to securely deliver it β€” and how it does that is the single most important security decision in the whole Zigbee architecture...' }, { protocolId: 'zigbee', title: 'APS Transport-Key β€” the network key, encrypted at the application layer', description: "The Coordinator sends an **{{aps-layer|APS}} Transport-Key** command (cmd `0x05`) containing the 128-bit {{aes|AES}} {{network-key|network key}}, **{{encryption|encrypted}} under the joiner's pre-configured link key**. With a per-device {{install-code|install code}} (printed on the Hue bulb's box as a QR code), that link key is unique and an eavesdropper at join cannot decrypt this frame. With the default *ZigBeeAlliance09* link key (universally known: `5A:69:67:42:65:65:41:6C:6C:69:61:6E:63:65:30:39`), an eavesdropper *can* β€” this is the canonical Zigbee sniffer-at-join attack. Zigbee R23's **{{dynamic-link-key|Dynamic Link Key}}** with SPEKE-over-{{curve25519|Curve25519}} removes the question entirely.", - transition: "The bulb now has both a {{short-address|short address}} and the {{network-key|network key}}. It can encrypt frames and join the mesh as a router for its neighbours. Time to announce its arrival..." + transition: + 'The bulb now has both a {{short-address|short address}} and the {{network-key|network key}}. It can encrypt frames and join the mesh as a router for its neighbours. Time to announce its arrival...' }, { protocolId: 'zigbee', title: 'Device Announce + first ZCL command', description: - "The bulb {{zigbee-nwk|NWK}}-broadcasts a **Device Announce** {{zigbee-zdo|ZDO}} message (cluster `0x0013`): *I am 0x3F4E, {{eui-64|EUI-64}} = …, capability = mains-powered router*. Every router on the mesh adds the new bulb to its {{routing-table|routing}} and binding tables. The Hue app now appears to discover the bulb. Tapping the on/off toggle sends a single **{{zcl|ZCL}} OnOff.Toggle** command β€” {{aps-layer|APS}} profile `0x0104` (Home Automation), cluster `0x0006` (OnOff), command `0x02` (Toggle). The whole on-the-wire {{payload|payload}}, including all 802.15.4 + {{zigbee-nwk|NWK}} + {{aps-layer|APS}} + {{zcl|ZCL}} {{header|headers}} + {{aes|AES}}-{{ccm-mode|CCM}}* {{mic|MIC}}, fits in ~40 bytes. The bulb turns on. From boot to first command: ~4 seconds." + 'The bulb {{zigbee-nwk|NWK}}-broadcasts a **Device Announce** {{zigbee-zdo|ZDO}} message (cluster `0x0013`): *I am 0x3F4E, {{eui-64|EUI-64}} = …, capability = mains-powered router*. Every router on the mesh adds the new bulb to its {{routing-table|routing}} and binding tables. The Hue app now appears to discover the bulb. Tapping the on/off toggle sends a single **{{zcl|ZCL}} OnOff.Toggle** command β€” {{aps-layer|APS}} profile `0x0104` (Home Automation), cluster `0x0006` (OnOff), command `0x02` (Toggle). The whole on-the-wire {{payload|payload}}, including all 802.15.4 + {{zigbee-nwk|NWK}} + {{aps-layer|APS}} + {{zcl|ZCL}} {{header|headers}} + {{aes|AES}}-{{ccm-mode|CCM}}* {{mic|MIC}}, fits in ~40 bytes. The bulb turns on. From boot to first command: ~4 seconds.' } ] } diff --git a/src/lib/data/outages.ts b/src/lib/data/outages.ts index 285ff07..bccede2 100644 --- a/src/lib/data/outages.ts +++ b/src/lib/data/outages.ts @@ -75,7 +75,7 @@ export const outages: Outage[] = [ duration: '~6 hours', scale: 'Global β€” 3 billion users; Facebook, Instagram, WhatsApp, Oculus all dark', oneLiner: - 'A routine maintenance command on {{meta|Meta}}\'s global backbone took down its [[dns|DNS]], then its websites, then its employees\' badge readers β€” all because the safety mechanism worked exactly as designed.', + "A routine maintenance command on {{meta|Meta}}'s global backbone took down its [[dns|DNS]], then its websites, then its employees' badge readers β€” all because the safety mechanism worked exactly as designed.", category: 'configuration', affectedProtocols: ['bgp', 'dns', 'tcp'], cast: [ @@ -84,7 +84,7 @@ export const outages: Outage[] = [ { name: 'ThousandEyes', role: 'External monitor' } ], setup: - "{{meta|Meta}} runs tens of thousands of miles of fibre between its data centres β€” a global private backbone. Its [[dns|DNS]] servers live in smaller \"edge\" facilities, programmed with a defensive safety: if a [[dns|DNS]] server cannot reach the data centres (and therefore cannot answer authoritatively), it withdraws its own [[bgp|BGP]] advertisements so nobody routes queries to it. The reasoning was sound: a [[dns|DNS]] server that can't answer shouldn't be reached.", + '{{meta|Meta}} runs tens of thousands of miles of fibre between its data centres β€” a global private backbone. Its [[dns|DNS]] servers live in smaller "edge" facilities, programmed with a defensive safety: if a [[dns|DNS]] server cannot reach the data centres (and therefore cannot answer authoritatively), it withdraws its own [[bgp|BGP]] advertisements so nobody routes queries to it. The reasoning was sound: a [[dns|DNS]] server that can\'t answer shouldn\'t be reached.', mistake: "During routine maintenance an engineer issued a command intended to assess the availability of global backbone capacity. {{meta|Meta}}'s audit tooling β€” designed to catch destructive commands β€” had a bug, and didn't stop it. The command took down the entire backbone.", cascade: [ @@ -118,9 +118,9 @@ export const outages: Outage[] = [ }, { time: '~16:00 UTC', - title: "Internal tools disappear too", + title: 'Internal tools disappear too', description: - "{{meta|Meta}} engineers cannot get into the network to fix it because their internal tools depend on the same [[dns|DNS]], and their physical badge readers depend on the same network. Engineers are reportedly dispatched to data centres with bolt cutters." + '{{meta|Meta}} engineers cannot get into the network to fix it because their internal tools depend on the same [[dns|DNS]], and their physical badge readers depend on the same network. Engineers are reportedly dispatched to data centres with bolt cutters.' }, { time: '21:00 UTC', @@ -131,11 +131,11 @@ export const outages: Outage[] = [ } ], consequence: - "Estimated revenue impact crosses $60M. Mark Zuckerberg's net worth drops by more than $6B in a day. In developing countries where Facebook's \"Free Basics\" program is the de-facto internet, communication, business, and humanitarian work pause for seven hours.", + 'Estimated revenue impact crosses $60M. Mark Zuckerberg\'s net worth drops by more than $6B in a day. In developing countries where Facebook\'s "Free Basics" program is the de-facto internet, communication, business, and humanitarian work pause for seven hours.', resolution: "{{meta|Meta}}'s post-mortem the next day acknowledges configuration tooling and audit-bypass as the root cause; the [[bgp|BGP]] withdrawal was the *symptom* of the larger backbone failure, not its cause.", lesson: - "Three layers β€” [[bgp|BGP]], [[dns|DNS]], and physical access β€” fail in cascade because each one trusts the layer below it. Never have a single dependency chain run through your own product. The defensive safety ([[dns|DNS]] withdraws on failure) is sound; the issue is that *every* product, including badge readers and audit tools, depended on the same [[dns|DNS]].", + 'Three layers β€” [[bgp|BGP]], [[dns|DNS]], and physical access β€” fail in cascade because each one trusts the layer below it. Never have a single dependency chain run through your own product. The defensive safety ([[dns|DNS]] withdraws on failure) is sound; the issue is that *every* product, including badge readers and audit tools, depended on the same [[dns|DNS]].', sources: [ { url: 'https://blog.cloudflare.com/october-2021-facebook-outage/', @@ -162,7 +162,7 @@ export const outages: Outage[] = [ category: 'configuration', affectedProtocols: ['bgp'], setup: - "In 1997 [[bgp|BGP]]-4 had been the inter-domain routing protocol for eight years. It assumes neighbours announce only what they own. There were almost no upstream filters: if a customer announced something, the upstream took it.", + 'In 1997 [[bgp|BGP]]-4 had been the inter-domain routing protocol for eight years. It assumes neighbours announce only what they own. There were almost no upstream filters: if a customer announced something, the upstream took it.', mistake: "MAI Network Services ({{autonomous-system|AS}} 7007) had a Bay Networks router whose forwarding table got dumped into [[bgp|BGP]] as if every entry were a route the {{autonomous-system|AS}} originated. The router didn't just announce its own prefixes β€” it announced /24 fragments of the entire global {{routing-table|routing table}}, claiming MAI was the origin {{autonomous-system|AS}} for everything.", cascade: [ @@ -182,17 +182,17 @@ export const outages: Outage[] = [ "Sprint's network couldn't handle the redirected traffic. Routers crashed. Sprint went largely dark." }, { - title: 'Withdrawals don\'t help', + title: "Withdrawals don't help", description: 'Even after MAI withdrew the routes, the propagation took hours to drain β€” the bad routes had been cached widely.' } ], consequence: - "Multi-hour partial outage of the public internet. Sprint customers especially affected. The first time the [[bgp|BGP]] community truly understood that a single misconfigured router anywhere on earth could take down the entire internet.", + 'Multi-hour partial outage of the public internet. Sprint customers especially affected. The first time the [[bgp|BGP]] community truly understood that a single misconfigured router anywhere on earth could take down the entire internet.', resolution: "Vince Bono's apology email to NANOG that day is preserved in the archives β€” a remarkably calm and detailed admission that became a model for incident communication.", lesson: - "[[bgp|BGP]] trusts every neighbour by default. Without prefix filters at every {{peering|peering}} point, a single broken router can become the apparent origin of the entire internet. Prompted the slow rollout of route filters across {{transit|transit}} providers, but the protocol-level fix ({{rpki|RPKI}} {{rov|ROV}}) took another 25 years to reach 50% deployment.", + '[[bgp|BGP]] trusts every neighbour by default. Without prefix filters at every {{peering|peering}} point, a single broken router can become the apparent origin of the entire internet. Prompted the slow rollout of route filters across {{transit|transit}} providers, but the protocol-level fix ({{rpki|RPKI}} {{rov|ROV}}) took another 25 years to reach 50% deployment.', sources: [ { url: 'https://en.wikipedia.org/wiki/AS_7007_incident', @@ -200,7 +200,7 @@ export const outages: Outage[] = [ }, { url: 'https://archive.nanog.org/mailinglist/mailarchives/old_archive/1997-04/msg00444.html', - label: "Bono β€” \"7007 Explanation and Apology\" (NANOG, April 1997)" + label: 'Bono β€” "7007 Explanation and Apology" (NANOG, April 1997)' } ] }, @@ -211,7 +211,7 @@ export const outages: Outage[] = [ duration: '~2 hours', scale: 'Global β€” YouTube unreachable from most of the internet', oneLiner: - 'Pakistan tried to block YouTube domestically. Its upstream provider didn\'t filter, and the block leaked to the whole internet.', + "Pakistan tried to block YouTube domestically. Its upstream provider didn't filter, and the block leaked to the whole internet.", category: 'configuration', affectedProtocols: ['bgp'], setup: @@ -228,19 +228,19 @@ export const outages: Outage[] = [ { title: 'YouTube goes dark', description: - "Traffic for the affected prefix headed to Pakistan, where it was null-routed. YouTube was unreachable for most of the internet for ~2 hours.", + 'Traffic for the affected prefix headed to Pakistan, where it was null-routed. YouTube was unreachable for most of the internet for ~2 hours.', protocols: ['bgp', 'tcp'] }, { title: 'YouTube counters with /25', description: - "YouTube announced an even more specific /25 to outcompete the hijack on the longest-prefix-match rule. The announcement spread; service started to recover.", + 'YouTube announced an even more specific /25 to outcompete the hijack on the longest-prefix-match rule. The announcement spread; service started to recover.', protocols: ['bgp'] }, { title: 'PCCW blackholes', description: - "PCCW eventually blackholed traffic to {{autonomous-system|AS}} 17557 to stop propagating the hijack." + 'PCCW eventually blackholed traffic to {{autonomous-system|AS}} 17557 to stop propagating the hijack.' } ], consequence: @@ -308,7 +308,7 @@ export const outages: Outage[] = [ resolution: 'No technical resolution beyond the withdrawal itself. The structural fix β€” {{rpki|RPKI}} Route Origin Authorisations and {{rov|ROV}} enforcement at {{peering|peering}} points β€” was already specified but a decade away from broad deployment.', lesson: - "Plain [[bgp|BGP]] advertises trust. A single {{autonomous-system|AS}} can globally redirect an arbitrary slice of internet traffic in minutes, with no protocol-level barrier to detection. China Telecom 2010 became one of the most-cited examples in the slow industry case for [[frontier:rpki-rov-50-percent|RPKI/ROV]], which finally crossed 50% of advertised {{ip-address|IP}} space in 2024 β€” fourteen years later.", + 'Plain [[bgp|BGP]] advertises trust. A single {{autonomous-system|AS}} can globally redirect an arbitrary slice of internet traffic in minutes, with no protocol-level barrier to detection. China Telecom 2010 became one of the most-cited examples in the slow industry case for [[frontier:rpki-rov-50-percent|RPKI/ROV]], which finally crossed 50% of advertised {{ip-address|IP}} space in 2024 β€” fourteen years later.', sources: [ { url: 'https://www.uscc.gov/sites/default/files/annual_reports/2010-Report-to-Congress.pdf', @@ -337,7 +337,10 @@ export const outages: Outage[] = [ affectedProtocols: ['tcp'], cast: [ { name: 'Van Jacobson (LBL)', role: "Co-author of the SIGCOMM '88 fix" }, - { name: 'Mike Karels (UC Berkeley CSRG)', role: 'Co-author; shipped the fixes in 4.3BSD-Tahoe' } + { + name: 'Mike Karels (UC Berkeley CSRG)', + role: 'Co-author; shipped the fixes in 4.3BSD-Tahoe' + } ], setup: 'In 1986 the early internet ran [[tcp|TCP]] without any {{congestion-control|congestion-control}} feedback loop. The original {{bsd|BSD}} [[tcp|TCP]] retransmitted aggressively when {{ack|ACKs}} were late: a missing {{ack|ACK}} at time *t* meant "the packet is probably gone, send again." Across the link from Lawrence Berkeley Lab to UC Berkeley β€” a path of three {{imp|IMP}} hops, less than 400 yards of physical distance β€” that policy worked fine until traffic levels rose.', @@ -365,7 +368,7 @@ export const outages: Outage[] = [ consequence: 'The first proof that a protocol designed for a small, lightly-loaded research network could fail catastrophically under production load. NSFNET regional links became unusable for hours at a time through October 1986. The internet engineering community accepted that an end-to-end {{congestion-control|congestion-control}} loop was not optional.', resolution: - "[[pioneer:van-jacobson|Van Jacobson]] and Mike Karels at Berkeley spent six months instrumenting the wire and reading the {{bsd|BSD}} source. Their 1988 {{sigcomm-conf|SIGCOMM}} paper β€” *{{congestion-avoidance|Congestion Avoidance}} and Control* β€” introduced six algorithms in one document: **{{slow-start|slow start}}**, **{{aimd|AIMD}} {{congestion-avoidance|congestion avoidance}}**, **fast retransmit**, **fast recovery**, **{{exponential-backoff|exponential RTO backoff}}**, and a refined **{{rtt|RTT}} estimator**. The fixes shipped in 4.3BSD-Tahoe and propagated to every [[tcp|TCP]] stack on earth.", + '[[pioneer:van-jacobson|Van Jacobson]] and Mike Karels at Berkeley spent six months instrumenting the wire and reading the {{bsd|BSD}} source. Their 1988 {{sigcomm-conf|SIGCOMM}} paper β€” *{{congestion-avoidance|Congestion Avoidance}} and Control* β€” introduced six algorithms in one document: **{{slow-start|slow start}}**, **{{aimd|AIMD}} {{congestion-avoidance|congestion avoidance}}**, **fast retransmit**, **fast recovery**, **{{exponential-backoff|exponential RTO backoff}}**, and a refined **{{rtt|RTT}} estimator**. The fixes shipped in 4.3BSD-Tahoe and propagated to every [[tcp|TCP]] stack on earth.', lesson: "Conservation of packets β€” put one packet into the network only when an {{ack|ACK}} confirms a previous one has left it β€” is the load-bearing principle that has held for forty years. Every later {{congestion-control|congestion-control}} algorithm (Reno, NewReno, Vegas, [[rfc:9438|CUBIC]], Compound, {{bbr|BBR}} v1/v2/v3, Prague over [[frontier:l4s-comcast-launch|L4S]]) is a refinement of Jacobson's six.", sources: [ @@ -414,24 +417,24 @@ export const outages: Outage[] = [ { title: 'Sessions re-establish', description: - "Each [[bgp|BGP]] session times out, retries, and re-establishes. As soon as it does, it re-receives the same Flowspec rule. The cycle restarts.", + 'Each [[bgp|BGP]] session times out, retries, and re-establishes. As soon as it does, it re-receives the same Flowspec rule. The cycle restarts.', protocols: ['bgp'] }, { title: 'Tier-1 collapse', description: - "The continuous churn means routes never converge. Customers across the Level 3 footprint experience massive packet loss. {{cloudflare|Cloudflare}} measures a 3.5% drop in *global* internet traffic." + 'The continuous churn means routes never converge. Customers across the Level 3 footprint experience massive packet loss. {{cloudflare|Cloudflare}} measures a 3.5% drop in *global* internet traffic.' }, { title: 'Manual de-peering needed', description: - "Level 3 has to ask other tier-1s to de-{{peer|peer}} with them temporarily to drain the [[bgp|BGP]]-{{bgp-update|update}} queue and let the bad rule be removed." + 'Level 3 has to ask other tier-1s to de-{{peer|peer}} with them temporarily to drain the [[bgp|BGP]]-{{bgp-update|update}} queue and let the bad rule be removed.' } ], consequence: "~5 hours of severe disruption across one of the world's largest backbones. {{cloudflare|Cloudflare}} publicly reported a 3.5% drop in global internet traffic. Many SaaS providers, video calls, and games hit by the cascading failures.", resolution: - "Level 3 manually de-peered with other tier-1s to break the [[bgp|BGP]]-{{bgp-update|update}} loop, removed the bad Flowspec rule, then re-peered.", + 'Level 3 manually de-peered with other tier-1s to break the [[bgp|BGP]]-{{bgp-update|update}} loop, removed the bad Flowspec rule, then re-peered.', lesson: "Don't deploy a feature whose failure mode disables the channel that controls it. [[bgp|BGP]] Flowspec is powerful β€” and Flowspec rules that touch [[bgp|BGP]] itself can lock you out of your own network. The same lesson applies to any in-band control protocol.", sources: [ @@ -450,16 +453,17 @@ export const outages: Outage[] = [ title: 'Rogers β€” A Country Disconnected', date: '2022-07-08', duration: '~15 hours', - scale: '12+ million Canadians lost wireless, wireline, internet, and Interac debit-card service', + scale: + '12+ million Canadians lost wireless, wireline, internet, and Interac debit-card service', oneLiner: - "A maintenance change to [[bgp|BGP]] route policy in the [[ip|IP]] core inadvertently allowed a full [[bgp|BGP]] table redistribution into [[ospf|OSPF]] β€” overwhelming the core router CPUs and crashing the entire network.", + 'A maintenance change to [[bgp|BGP]] route policy in the [[ip|IP]] core inadvertently allowed a full [[bgp|BGP]] table redistribution into [[ospf|OSPF]] β€” overwhelming the core router CPUs and crashing the entire network.', category: 'configuration', affectedProtocols: ['bgp'], cast: [{ name: 'Rogers Communications (AS 812)', role: 'Operator' }], setup: "Rogers ran one of Canada's three national telecom networks β€” wireless, wireline, internet, and the Interac point-of-sale debit card system that runs Canadian retail. The [[ip|IP]] core used [[bgp|BGP]] for inter-{{autonomous-system|AS}} routing and [[ospf|OSPF]] for intra-{{autonomous-system|AS}} routing β€” the standard separation.", mistake: - "A maintenance change to [[bgp|BGP]] route policy in the [[ip|IP]] core was meant to apply to a small set of routes. A missing filter let the entire [[bgp|BGP]] table β€” nearly a million prefixes β€” redistribute into [[ospf|OSPF]], the intra-{{autonomous-system|AS}} routing protocol.", + 'A maintenance change to [[bgp|BGP]] route policy in the [[ip|IP]] core was meant to apply to a small set of routes. A missing filter let the entire [[bgp|BGP]] table β€” nearly a million prefixes β€” redistribute into [[ospf|OSPF]], the intra-{{autonomous-system|AS}} routing protocol.', cascade: [ { title: 'BGP-into-OSPF flood', @@ -486,9 +490,9 @@ export const outages: Outage[] = [ consequence: "12+ million customers without service for a full business day. Hospitals, 911 operations, point-of-sale systems, government services impacted. {{crtc|CRTC}}'s 2024 executive summary identified missing route filters and lab-testing skipped due to an algorithm down-grading risk from 'High' to 'Low' after earlier phases succeeded.", resolution: - "Manual rollback of the offending policy change, with engineers physically present at core sites.", + 'Manual rollback of the offending policy change, with engineers physically present at core sites.', lesson: - "A single national telecom outage can take down payment systems, hospitals, and emergency services. Canada subsequently mandated mutual emergency-roaming agreements between carriers, on the principle that a single {{autonomous-system|AS}} failing should not disconnect a country.", + 'A single national telecom outage can take down payment systems, hospitals, and emergency services. Canada subsequently mandated mutual emergency-roaming agreements between carriers, on the principle that a single {{autonomous-system|AS}} failing should not disconnect a country.', sources: [ { url: 'https://blog.cloudflare.com/cloudflares-view-of-the-rogers-communications-outage-in-canada/', @@ -518,7 +522,7 @@ export const outages: Outage[] = [ setup: "AT&T Mobility is one of the three large US national wireless carriers. The mobility network has elaborate self-protection mechanisms β€” when the system detects something seriously wrong, it can enter a defensive 'protect mode' that disconnects subscribers to limit damage.", mistake: - "At 02:42 CT, a network change with an equipment configuration error tripped the protect-mode threshold. The network defended itself by disconnecting every wireless device.", + 'At 02:42 CT, a network change with an equipment configuration error tripped the protect-mode threshold. The network defended itself by disconnecting every wireless device.', cascade: [ { time: '02:42 CT', @@ -529,7 +533,7 @@ export const outages: Outage[] = [ time: '02:43 CT', title: 'Protect mode', description: - 'The error trips the network\'s self-protection threshold. The mobility core enters \'protect mode\' and starts disconnecting devices.' + "The error trips the network's self-protection threshold. The mobility core enters 'protect mode' and starts disconnecting devices." }, { title: 'Nationwide outage', @@ -542,11 +546,11 @@ export const outages: Outage[] = [ } ], consequence: - "125M+ devices affected. 92M+ blocked voice calls. 25K+ failed 911 calls. The {{fcc|FCC}} report reads like every [[bgp|BGP]] outage post-mortem: insufficient {{peer|peer}} review, missing controls, unscanned changes.", + '125M+ devices affected. 92M+ blocked voice calls. 25K+ failed 911 calls. The {{fcc|FCC}} report reads like every [[bgp|BGP]] outage post-mortem: insufficient {{peer|peer}} review, missing controls, unscanned changes.', resolution: 'Configuration rollback and gradual reconnection of subscribers to avoid signalling overload.', lesson: - "\"Self-protection mechanisms that disconnect users\" is a category that needs careful design. The threshold for protect mode should not be reachable by an operator's mistake β€” and if it is, recovery should not require 12 hours.", + '"Self-protection mechanisms that disconnect users" is a category that needs careful design. The threshold for protect mode should not be reachable by an operator\'s mistake β€” and if it is, recovery should not require 12 hours.', sources: [ { url: 'https://docs.fcc.gov/public/attachments/DOC-404154A1.pdf', @@ -573,9 +577,9 @@ export const outages: Outage[] = [ { name: 'Linux Kernel TCP maintainers', role: 'Vendors' } ], setup: - "[[tcp|TCP]] {{sack|Selective Acknowledgment}} ({{sack|SACK}}, [[rfc:2018|RFC 2018]]) lets the receiver tell the sender exactly which non-contiguous byte ranges have arrived. The {{linux|Linux}} kernel tracks these as a queue of skb (socket buffer) ranges. The data structure includes a 16-bit gso_segs counter for the segments-in-flight on a single sk_buff.", + '[[tcp|TCP]] {{sack|Selective Acknowledgment}} ({{sack|SACK}}, [[rfc:2018|RFC 2018]]) lets the receiver tell the sender exactly which non-contiguous byte ranges have arrived. The {{linux|Linux}} kernel tracks these as a queue of skb (socket buffer) ranges. The data structure includes a 16-bit gso_segs counter for the segments-in-flight on a single sk_buff.', mistake: - "With a small enough {{mss|MSS}} β€” easily set by a remote {{peer|peer}} β€” a single sk_buff could be split into more than 65,535 GSO segments. The 16-bit counter overflowed. The kernel hit an integer overflow in tcp_skb_cb, triggering a panic.", + 'With a small enough {{mss|MSS}} β€” easily set by a remote {{peer|peer}} β€” a single sk_buff could be split into more than 65,535 GSO segments. The 16-bit counter overflowed. The kernel hit an integer overflow in tcp_skb_cb, triggering a panic.', cascade: [ { title: 'Patch crafted', @@ -594,7 +598,7 @@ export const outages: Outage[] = [ } ], consequence: - "Most {{linux|Linux}} servers on the public internet were vulnerable. CVSS 7.5 (high). Operators scrambled to patch; many disabled {{sack|SACK}} as an interim mitigation, accepting performance degradation to avoid the crash.", + 'Most {{linux|Linux}} servers on the public internet were vulnerable. CVSS 7.5 (high). Operators scrambled to patch; many disabled {{sack|SACK}} as an interim mitigation, accepting performance degradation to avoid the crash.', resolution: 'Mainline kernel patch shipped within days. Mitigations: disable {{sack|SACK}} (`net.ipv4.tcp_sack=0`) or enforce a minimum {{mss|MSS}} via the new `net.ipv4.tcp_min_snd_mss` sysctl.', lesson: @@ -602,7 +606,7 @@ export const outages: Outage[] = [ sources: [ { url: 'https://github.com/Netflix/security-bulletins/blob/master/advisories/third-party/2019-001.md', - label: "Netflix Security Bulletin β€” TCP SACK PANIC" + label: 'Netflix Security Bulletin β€” TCP SACK PANIC' }, { url: 'https://access.redhat.com/security/vulnerabilities/tcpsack', diff --git a/src/lib/data/pioneers.ts b/src/lib/data/pioneers.ts index 3e842ae..19e5078 100644 --- a/src/lib/data/pioneers.ts +++ b/src/lib/data/pioneers.ts @@ -1216,7 +1216,7 @@ Authored **qmail** and **djbdns** in the late 1990s β€” uncompromising secure al imagePath: 'https://upload.wikimedia.org/wikipedia/commons/thumb/c/cb/Daniel_J._Bernstein.jpg/330px-Daniel_J._Bernstein.jpg', protocols: ['tcp', 'tls', 'ssh'], - categories: ['security', 'transport'], + categories: ['utilities', 'transport'], links: { wikipedia: 'https://en.wikipedia.org/wiki/Daniel_J._Bernstein', homepage: 'https://cr.yp.to/' diff --git a/src/lib/data/protocols/amqp.ts b/src/lib/data/protocols/amqp.ts index aa03c73..ae530c9 100644 --- a/src/lib/data/protocols/amqp.ts +++ b/src/lib/data/protocols/amqp.ts @@ -71,7 +71,8 @@ def callback(ch, method, properties, body): channel.basic_consume(queue='tasks', on_message_callback=callback) channel.start_consuming()`, - caption: 'RabbitMQ with pika β€” {{mqtt-publish|publish}} durable messages and consume with acknowledgments', + caption: + 'RabbitMQ with pika β€” {{mqtt-publish|publish}} durable messages and consume with acknowledgments', alternatives: [ { language: 'javascript', diff --git a/src/lib/data/protocols/arp.ts b/src/lib/data/protocols/arp.ts index 8c5b399..60c0000 100644 --- a/src/lib/data/protocols/arp.ts +++ b/src/lib/data/protocols/arp.ts @@ -8,7 +8,8 @@ export const arp: Protocol = { port: undefined, year: 1982, rfc: 'RFC 826', - oneLiner: 'Translates [[ip|IP]] addresses to {{mac-address|MAC}} addresses β€” the bridge between Layer 3 and Layer 2.', + oneLiner: + 'Translates [[ip|IP]] addresses to {{mac-address|MAC}} addresses β€” the bridge between Layer 3 and Layer 2.', overview: `[[arp|ARP]] is the glue between [[ip|IP]] addresses and [[ethernet|Ethernet]] {{mac-address|MAC addresses}}. When your computer wants to send a {{packet|packet}} to 192.168.1.1, it knows the [[ip|IP]] but not the {{mac-address|MAC address}} of the destination. [[arp|ARP]] {{broadcast|broadcasts}} a question to the entire local network: "Who has 192.168.1.1? Tell me your {{mac-address|MAC address}}." The owner responds with a {{unicast|unicast}} reply containing its {{mac-address|MAC}}, and the sender caches this mapping for future use. Under the hood, [[arp|ARP]] uses EtherType 0x0806 and operates directly on [[ethernet|Ethernet]] β€” it has no [[ip|IP]] header. The request is {{broadcast|broadcast}} to \`FF:FF:FF:FF:FF:FF\`, so every device on the segment receives it, but only the target replies. That reply is {{unicast|unicast}} directly back to the requester. The resulting [[ip|IP]]-to-{{mac-address|MAC}} mapping is stored in the [[arp|ARP]] cache (also called the [[arp|ARP]] table) with a {{ttl|time-to-live}} β€” typically 15-45 seconds on modern systems (randomized per [[rfc:4861|RFC 4861]]) β€” after which the entry expires and must be re-resolved. @@ -23,7 +24,7 @@ Under the hood, [[arp|ARP]] uses EtherType 0x0806 and operates directly on [[eth { title: 'Broadcast ARP request', description: - 'If no cache entry exists, the sender crafts an [[arp|ARP]] request with its own [[ip|IP]]/{{mac-address|MAC}} as the source and the target [[ip|IP]] with an empty {{mac-address|MAC}} (\`00:00:00:00:00:00\`). This is sent as an [[ethernet|Ethernet]] {{broadcast|broadcast}} (\`FF:FF:FF:FF:FF:FF\`), reaching every device on the local segment.' + 'If no cache entry exists, the sender crafts an [[arp|ARP]] request with its own [[ip|IP]]/{{mac-address|MAC}} as the source and the target [[ip|IP]] with an empty {{mac-address|MAC}} (`00:00:00:00:00:00`). This is sent as an [[ethernet|Ethernet]] {{broadcast|broadcast}} (`FF:FF:FF:FF:FF:FF`), reaching every device on the local segment.' }, { title: 'Unicast ARP reply', diff --git a/src/lib/data/protocols/bgp.ts b/src/lib/data/protocols/bgp.ts index 6ec48b2..e2611fe 100644 --- a/src/lib/data/protocols/bgp.ts +++ b/src/lib/data/protocols/bgp.ts @@ -172,7 +172,7 @@ for await (const elem of parser) { date: '2026', title: 'RPKI/ROV crosses 50% of advertised IP space', description: - '{{nist|NIST}} {{rov|Route Origin Validation}} Monitor and {{cloudflare|Cloudflare}}\'s isbgpsafeyet.com show over 50% of advertised [[ip|IPv4]] space now covered by signed Route Origin Authorisations. Most tier-1 transits enforce {{rov|ROV}} on incoming announcements.' + "{{nist|NIST}} {{rov|Route Origin Validation}} Monitor and {{cloudflare|Cloudflare}}'s isbgpsafeyet.com show over 50% of advertised [[ip|IPv4]] space now covered by signed Route Origin Authorisations. Most tier-1 transits enforce {{rov|ROV}} on incoming announcements." }, { date: '2024-2025', diff --git a/src/lib/data/protocols/bluetooth.ts b/src/lib/data/protocols/bluetooth.ts index faec0c9..ee539cd 100644 --- a/src/lib/data/protocols/bluetooth.ts +++ b/src/lib/data/protocols/bluetooth.ts @@ -212,7 +212,7 @@ CRC: x^24 + x^10 + x^9 + x^6 + x^4 + x^3 + x + 1, seeded by Access Address.` src: 'https://upload.wikimedia.org/wikipedia/commons/thumb/d/da/Bluetooth.svg/250px-Bluetooth.svg.png', alt: 'The Bluetooth logo β€” a bind-rune combining Hagall (ᚼ) and Bjarkan (α›’), the initials of Harald Bluetooth in Younger Futhark', caption: - "The Bluetooth logo is a bind-rune combining **Hagall** (ᚼ) and **Bjarkan** (α›’) β€” the initials of *Harald BlΓ₯tand*, the 10th-century Danish king who united Denmark and Norway. Jim Kardach at {{intel|Intel}} proposed the name as a placeholder during a 1997 {{sig|SIG}} meeting; it was never supposed to ship.", + 'The Bluetooth logo is a bind-rune combining **Hagall** (ᚼ) and **Bjarkan** (α›’) β€” the initials of *Harald BlΓ₯tand*, the 10th-century Danish king who united Denmark and Norway. Jim Kardach at {{intel|Intel}} proposed the name as a placeholder during a 1997 {{sig|SIG}} meeting; it was never supposed to ship.', credit: 'Image: Wikimedia Commons / Public Domain (Bluetooth SIG trademark)' }, @@ -311,7 +311,7 @@ CRC: x^24 + x^10 + x^9 + x^6 + x^4 + x^3 + x + 1, seeded by Access Address.` }, { title: 'BR/EDR and BLE share a logo but not a single bit', - text: "Despite the unified branding, **Bluetooth Classic and {{ble|BLE}} share no bits over the air**. Different modulation (GFSK + DPSK for Classic, GFSK only for {{ble|BLE}} 1M), different channel plan (79 Γ— 1 MHz vs 40 Γ— 2 MHz), different hopping (1,600/s vs once-per-connection-event), different framing, different security. A dual-mode chip runs both stacks side by side. The {{sig|SIG}} estimates more than half of all shipping radios are dual-mode in 2024." + text: 'Despite the unified branding, **Bluetooth Classic and {{ble|BLE}} share no bits over the air**. Different modulation (GFSK + DPSK for Classic, GFSK only for {{ble|BLE}} 1M), different channel plan (79 Γ— 1 MHz vs 40 Γ— 2 MHz), different hopping (1,600/s vs once-per-connection-event), different framing, different security. A dual-mode chip runs both stacks side by side. The {{sig|SIG}} estimates more than half of all shipping radios are dual-mode in 2024.' } ], @@ -319,7 +319,7 @@ CRC: x^24 + x^10 + x^9 + x^6 + x^4 + x^3 + x + 1, seeded by Access Address.` pitfalls: [ { title: 'The default ATT MTU is 23 bytes', - text: "Every {{ble|BLE}} connection starts with {{att-mtu|ATT MTU}} = 23, which means only **20 bytes of {{payload|payload}} per Notify** after the 3-byte {{att-mtu|ATT}} header. If you ship that default, your sensor stream is throughput-bound on overhead. **Cure:** request an {{mtu|MTU}} {{exchange|exchange}} (`ATT_Exchange_MTU_Request`) to 247 (one LL {{pdu-session|PDU}} with Data Length Extension) or 517 (the {{ble|BLE}} maximum) as the first {{att-mtu|ATT}} operation after pairing. Most platforms now do this automatically β€” but verify with an nRF Sniffer capture." + text: 'Every {{ble|BLE}} connection starts with {{att-mtu|ATT MTU}} = 23, which means only **20 bytes of {{payload|payload}} per Notify** after the 3-byte {{att-mtu|ATT}} header. If you ship that default, your sensor stream is throughput-bound on overhead. **Cure:** request an {{mtu|MTU}} {{exchange|exchange}} (`ATT_Exchange_MTU_Request`) to 247 (one LL {{pdu-session|PDU}} with Data Length Extension) or 517 (the {{ble|BLE}} maximum) as the first {{att-mtu|ATT}} operation after pairing. Most platforms now do this automatically β€” but verify with an nRF Sniffer capture.' }, { title: 'Connection interval Γ— Slave latency Γ— Supervision timeout', @@ -327,7 +327,7 @@ CRC: x^24 + x^10 + x^9 + x^6 + x^4 + x^3 + x + 1, seeded by Access Address.` }, { title: 'Wi-Fi coexistence on 2.4 GHz', - text: "{{ble|BLE}} channels 37/38/39 (advertising) sit at 2402, 2426, and 2480 MHz β€” carefully chosen to **avoid** [[wifi|Wi-Fi]] channels 1/6/11 (2412/2437/2462 MHz). But the 37 data channels (0–36) overlap. Modern combo chips do time-division arbitration internally; on a discrete radio, a saturated [[wifi|Wi-Fi]] {{ap-access-point|AP}} can starve {{ble|BLE}} for tens of seconds. **Cure:** if running mission-critical {{ble|BLE}} next to enterprise Wi-Fi, fix the Wi-Fi APs to use 5/6 GHz where possible, or use **{{le-audio|LE}} Coded S=8** which trades 8Γ— more {{airtime|airtime}} for 8Γ— better link budget β€” surviving interference where {{le-audio|LE}} 1M won\'t." + text: "{{ble|BLE}} channels 37/38/39 (advertising) sit at 2402, 2426, and 2480 MHz β€” carefully chosen to **avoid** [[wifi|Wi-Fi]] channels 1/6/11 (2412/2437/2462 MHz). But the 37 data channels (0–36) overlap. Modern combo chips do time-division arbitration internally; on a discrete radio, a saturated [[wifi|Wi-Fi]] {{ap-access-point|AP}} can starve {{ble|BLE}} for tens of seconds. **Cure:** if running mission-critical {{ble|BLE}} next to enterprise Wi-Fi, fix the Wi-Fi APs to use 5/6 GHz where possible, or use **{{le-audio|LE}} Coded S=8** which trades 8Γ— more {{airtime|airtime}} for 8Γ— better link budget β€” surviving interference where {{le-audio|LE}} 1M won't." } ] } diff --git a/src/lib/data/protocols/cellular.ts b/src/lib/data/protocols/cellular.ts index da93ec1..9bd6f0a 100644 --- a/src/lib/data/protocols/cellular.ts +++ b/src/lib/data/protocols/cellular.ts @@ -21,7 +21,7 @@ The frontier in 2026 is **5G-Advanced** (Release 18, frozen June 2024; Release 1 { title: 'PHY β€” OFDMA with five numerologies', description: - "{{5g-nr|5G NR}} carries data on **Orthogonal Frequency-Division Multiple Access** subcarriers spaced at 15, 30, 60, 120, or 240 kHz ({{3gpp|3GPP}} {{ts-3gpp|TS}} 38.211). The choice is the *numerology* β€” smaller spacing = longer symbols = more robust at low frequencies; larger spacing = shorter symbols = required at {{mmwave|mmWave}}. One framework, two very different deployment regimes (FR1 sub-6 GHz, FR2 {{mmwave|mmWave}} 24–52 GHz)." + '{{5g-nr|5G NR}} carries data on **Orthogonal Frequency-Division Multiple Access** subcarriers spaced at 15, 30, 60, 120, or 240 kHz ({{3gpp|3GPP}} {{ts-3gpp|TS}} 38.211). The choice is the *numerology* β€” smaller spacing = longer symbols = more robust at low frequencies; larger spacing = shorter symbols = required at {{mmwave|mmWave}}. One framework, two very different deployment regimes (FR1 sub-6 GHz, FR2 {{mmwave|mmWave}} 24–52 GHz).' }, { title: 'MAC β€” Hybrid ARQ', @@ -36,7 +36,7 @@ The frontier in 2026 is **5G-Advanced** (Release 18, frozen June 2024; Release 1 { title: 'RRC β€” connection state machine', description: - 'The Radio Resource Control state machine ({{ts-3gpp|TS}} 38.331) has three states in 5G: \`RRC_IDLE\` ({{ue|UE}} sleeps, only listens to {{notification|paging}}), \`RRC_INACTIVE\` (5G-only; {{ue|UE}} keeps security context for fast resume), \`RRC_CONNECTED\` (full bearer, scheduled). State transitions cost battery β€” careful {{rrc|RRC}} tuning is the difference between 6-hour and 24-hour battery life on an IoT module.' + 'The Radio Resource Control state machine ({{ts-3gpp|TS}} 38.331) has three states in 5G: `RRC_IDLE` ({{ue|UE}} sleeps, only listens to {{notification|paging}}), `RRC_INACTIVE` (5G-only; {{ue|UE}} keeps security context for fast resume), `RRC_CONNECTED` (full bearer, scheduled). State transitions cost battery β€” careful {{rrc|RRC}} tuning is the difference between 6-hour and 24-hour battery life on an IoT module.' }, { title: 'NAS β€” authentication, mobility, session management', @@ -46,7 +46,7 @@ The frontier in 2026 is **5G-Advanced** (Release 18, frozen June 2024; Release 1 { title: '5GC service-based architecture', description: - "The {{5g-core|5G Core}} is a {{service-mesh|microservice fabric}}. {{amf|AMF}}, {{smf|SMF}}, {{upf|UPF}}, {{ausf|AUSF}}, {{udm|UDM}}, PCF, NRF, NEF, NSSF, AF β€” each is a **network function** with an [[http2|HTTP/2]]+{{json|JSON}} {{api|API}} protected by [[tls|TLS]]. Service-based interfaces are named Nausf, Nudm, Namf, Nsmf, Npcf, Nnrf, Nnef, Nnssf, Naf. The control plane of every 5G carrier on Earth is now an [[http2|HTTP/2]] microservice fabric β€” and every backhaul {{hop|hop}} is wrapped in [[ipsec|IPsec ESP]]." + 'The {{5g-core|5G Core}} is a {{service-mesh|microservice fabric}}. {{amf|AMF}}, {{smf|SMF}}, {{upf|UPF}}, {{ausf|AUSF}}, {{udm|UDM}}, PCF, NRF, NEF, NSSF, AF β€” each is a **network function** with an [[http2|HTTP/2]]+{{json|JSON}} {{api|API}} protected by [[tls|TLS]]. Service-based interfaces are named Nausf, Nudm, Namf, Nsmf, Npcf, Nnrf, Nnef, Nnssf, Naf. The control plane of every 5G carrier on Earth is now an [[http2|HTTP/2]] microservice fabric β€” and every backhaul {{hop|hop}} is wrapped in [[ipsec|IPsec ESP]].' }, { title: 'GTP-U on N3 β€” the user-plane tunnel', @@ -110,7 +110,8 @@ sudo tshark -i lo -f 'sctp port 38412' -V # Decode NAS Registration Request, NAS Authentication, Security Mode, # Registration Accept, PDU Session Establishment Request, all in # real time. Wireshark NGAP/NAS-5GS dissectors handle the whole thing.`, - caption: 'A locally-runnable 5G testbed in three commands β€” srsRAN gNB + Open5GS 5GC + {{wireshark|Wireshark}}. Used by every cellular-protocol researcher in 2026.', + caption: + 'A locally-runnable 5G testbed in three commands β€” srsRAN gNB + Open5GS 5GC + {{wireshark|Wireshark}}. Used by every cellular-protocol researcher in 2026.', alternatives: [ { language: 'python', @@ -267,7 +268,24 @@ Inner packet: overhead: 'Air-interface MAC + RLC + PDCP overhead is ~5–15% depending on numerology. On the backhaul, GTP-U adds 8 bytes plus the IPsec ESP wrapping (36–60 bytes) β€” every cellular packet pays an IPsec round on every N3 hop. ROHC header compression brings the 40-byte IPv6+TCP header down to 1–4 bytes on a steady flow' }, - connections: ['ip', 'ipv6', 'tcp', 'udp', 'quic', 'ipsec', 'http2', 'http3', 'tls', 'dns', 'sip', 'rtp', 'webrtc', 'wifi', 'bluetooth', 'nfc'], + connections: [ + 'ip', + 'ipv6', + 'tcp', + 'udp', + 'quic', + 'ipsec', + 'http2', + 'http3', + 'tls', + 'dns', + 'sip', + 'rtp', + 'webrtc', + 'wifi', + 'bluetooth', + 'nfc' + ], links: { wikipedia: 'https://en.wikipedia.org/wiki/5G_NR', official: 'https://www.3gpp.org/' @@ -276,7 +294,7 @@ Inner packet: src: 'https://upload.wikimedia.org/wikipedia/commons/thumb/4/4a/Cellular_network_standards_and_generation_timeline.svg/500px-Cellular_network_standards_and_generation_timeline.svg.png', alt: 'Cellular network standards generation timeline β€” 1G through 5G with milestones', caption: - "The cellular generation timeline β€” the {{3gpp|3GPP}} release cadence that took us from 1G analog AMPS (1979) β†’ {{gsm|GSM}} 2G (1991) β†’ {{umts|UMTS}}/{{wcdma|WCDMA}} 3G (2001) β†’ **[[cellular|LTE 4G]] Release 8 (December 2008)** β†’ **[[cellular|5G NR]] Release 15 (June 2018)** β†’ 5G-Advanced Release 18 (June 2024) β†’ 6G study items now. Every generation roughly doubled spectral efficiency and added a fundamentally new use case.", + 'The cellular generation timeline β€” the {{3gpp|3GPP}} release cadence that took us from 1G analog AMPS (1979) β†’ {{gsm|GSM}} 2G (1991) β†’ {{umts|UMTS}}/{{wcdma|WCDMA}} 3G (2001) β†’ **[[cellular|LTE 4G]] Release 8 (December 2008)** β†’ **[[cellular|5G NR]] Release 15 (June 2018)** β†’ 5G-Advanced Release 18 (June 2024) β†’ 6G study items now. Every generation roughly doubled spectral efficiency and added a fundamentally new use case.', credit: 'Image: Wikimedia Commons / CC BY-SA' }, @@ -338,7 +356,7 @@ Inner packet: org: '3GPP / every mobile carrier on Earth', scale: '~9 billion subscriptions (GSMA, 2024)', description: - "The largest wireless protocol family by user count. Specified collectively by {{3gpp|3GPP}} β€” a partnership of {{etsi|ETSI}} (Europe), ARIB + TTC (Japan), ATIS (North America), CCSA (China), TSDSI (India), TTA (Korea). Every cellular phone on Earth runs {{3gpp|3GPP}} protocols at the radio layer." + 'The largest wireless protocol family by user count. Specified collectively by {{3gpp|3GPP}} β€” a partnership of {{etsi|ETSI}} (Europe), ARIB + TTC (Japan), ATIS (North America), CCSA (China), TSDSI (India), TTA (Korea). Every cellular phone on Earth runs {{3gpp|3GPP}} protocols at the radio layer.' }, { org: 'Reliance Jio', @@ -356,25 +374,25 @@ Inner packet: org: 'DISH Wireless / EchoStar', scale: '5G-SA on public cloud (AWS Wavelength)', description: - "The first commercial 5G-{{security-association|SA}} network running on **public-cloud infrastructure** ({{aws|AWS}} Wavelength + {{aws|AWS}} Local Zones). Proves the cloud-native {{5g-core|5G core}} architecture works in production. Rakuten Symphony (Japan) and Open5GS-based deployments worldwide follow the same pattern." + 'The first commercial 5G-{{security-association|SA}} network running on **public-cloud infrastructure** ({{aws|AWS}} Wavelength + {{aws|AWS}} Local Zones). Proves the cloud-native {{5g-core|5G core}} architecture works in production. Rakuten Symphony (Japan) and Open5GS-based deployments worldwide follow the same pattern.' } ], funFacts: [ { - title: "The first cellular call was a troll", - text: "**3 April 1973, Sixth Avenue, Manhattan.** Marty Cooper of Motorola dialed Joel Engel at AT&T Bell Labs β€” his direct rival in the cellular-system fight β€” and said: *\"Joel, this is Marty. I'm calling you from a cell phone, a real handheld portable cell phone.\"* Engel, by Cooper's account, claims not to remember the call." + title: 'The first cellular call was a troll', + text: '**3 April 1973, Sixth Avenue, Manhattan.** Marty Cooper of Motorola dialed Joel Engel at AT&T Bell Labs β€” his direct rival in the cellular-system fight β€” and said: *"Joel, this is Marty. I\'m calling you from a cell phone, a real handheld portable cell phone."* Engel, by Cooper\'s account, claims not to remember the call.' }, { - title: "Viterbi did not patent his most famous algorithm", - text: "*\"On advice of a lawyer, Viterbi did not patent the algorithm.\"* The **Viterbi algorithm** β€” convolutional code decoding (1967) β€” is used in every cellular phone, every disk-drive read channel, every {{gps|GPS}} receiver, and every speech recognizer. It made nothing for Andrew Viterbi directly; it made Qualcomm everything." + title: 'Viterbi did not patent his most famous algorithm', + text: '*"On advice of a lawyer, Viterbi did not patent the algorithm."* The **Viterbi algorithm** β€” convolutional code decoding (1967) β€” is used in every cellular phone, every disk-drive read channel, every {{gps|GPS}} receiver, and every speech recognizer. It made nothing for Andrew Viterbi directly; it made Qualcomm everything.' }, { title: 'MCC tells you where your SIM was issued', - text: 'The Mobile Country Code at the start of your IMSI is the protocol\'s private numbering plan: 234/235 = UK, 310–316 = USA, 460 = China, 405 = India, 440–441 = Japan, 262 = Germany, 222 = Italy, 208 = France. Your roaming bill itemises calls by MCC/MNC pair.' + text: "The Mobile Country Code at the start of your IMSI is the protocol's private numbering plan: 234/235 = UK, 310–316 = USA, 460 = China, 405 = India, 440–441 = Japan, 262 = Germany, 222 = Italy, 208 = France. Your roaming bill itemises calls by MCC/MNC pair." }, { - title: "The CDMA-vs-GSM wars were existential", + title: 'The CDMA-vs-GSM wars were existential', text: 'In January 1989 the US CTIA voted for {{tdma|TDMA}}; later that year Irwin Jacobs presented {{cdma|CDMA}} and *"no one found a hole in the technical presentation,"* but the political fight took a decade. Hong Kong (1995), then Korea, then the US were the first to ship cdmaOne. {{cdma|CDMA}}\'s mathematical foundation eventually became the basis of {{wcdma|WCDMA}} in {{umts|UMTS}} β€” the {{gsm|GSM}} camp ended up adopting it.' } ], @@ -383,15 +401,15 @@ Inner packet: pitfalls: [ { title: 'IPv6-only carriers + IPv4-literal apps', - text: "On modern carriers (T-Mobile USA, Reliance Jio, parts of Verizon and DT), the {{ue|UE}} receives **only an [[ipv6|IPv6]] prefix**. Legacy [[ip|IPv4]] destinations are reached via **{{four-six-four-xlat|464XLAT}}** ([[rfc:6877|RFC 6877]]) β€” {{clat-acr|CLAT}} on the {{ue|UE}}, PLAT/{{nat64|NAT64}} at the operator. **Pitfall:** apps with hardcoded [[ip|IPv4]] literals (`socket.{{mqtt-connect|connect}}(\"8.8.8.8\")`) silently fail. **Cure:** always resolve via [[dns|DNS]], always prefer [[ipv6|IPv6]] (`getaddrinfo`, `AF_UNSPEC`); use `IPv4v6` {{pdu-session|PDU session}} type, never `[[ip|IPv4]] only`." + text: 'On modern carriers (T-Mobile USA, Reliance Jio, parts of Verizon and DT), the {{ue|UE}} receives **only an [[ipv6|IPv6]] prefix**. Legacy [[ip|IPv4]] destinations are reached via **{{four-six-four-xlat|464XLAT}}** ([[rfc:6877|RFC 6877]]) β€” {{clat-acr|CLAT}} on the {{ue|UE}}, PLAT/{{nat64|NAT64}} at the operator. **Pitfall:** apps with hardcoded [[ip|IPv4]] literals (`socket.{{mqtt-connect|connect}}("8.8.8.8")`) silently fail. **Cure:** always resolve via [[dns|DNS]], always prefer [[ipv6|IPv6]] (`getaddrinfo`, `AF_UNSPEC`); use `IPv4v6` {{pdu-session|PDU session}} type, never `[[ip|IPv4]] only`.' }, { title: 'PMTUD black holes on the GTP tunnel', - text: "Many cellular networks drop ICMPv4 Type 3 Code 4 (Frag Needed) messages on the SGi/N6 side. The {{mtu|MTU}} on a {{gtp-u|GTP-U}} tunnel is 1500 βˆ’ 8 ([[udp|UDP]]) βˆ’ 20/40 ({{ip-address|IP}}) βˆ’ 8 ({{gtp-u|GTP-U}}) βˆ’ overhead = typically 1430–1452 inner bytes. **Cure:** [[tcp|TCP]] {{mss|MSS}} clamping at the {{pgw|PGW}}/{{upf|UPF}} saves [[tcp|TCP]]; [[quic|QUIC]] and other UDP-based protocols must implement {{plpmtud|PLPMTUD}} ({{rfc-doc|RFC}} 8899)." + text: 'Many cellular networks drop ICMPv4 Type 3 Code 4 (Frag Needed) messages on the SGi/N6 side. The {{mtu|MTU}} on a {{gtp-u|GTP-U}} tunnel is 1500 βˆ’ 8 ([[udp|UDP]]) βˆ’ 20/40 ({{ip-address|IP}}) βˆ’ 8 ({{gtp-u|GTP-U}}) βˆ’ overhead = typically 1430–1452 inner bytes. **Cure:** [[tcp|TCP]] {{mss|MSS}} clamping at the {{pgw|PGW}}/{{upf|UPF}} saves [[tcp|TCP]]; [[quic|QUIC]] and other UDP-based protocols must implement {{plpmtud|PLPMTUD}} ({{rfc-doc|RFC}} 8899).' }, { title: 'IPsec is mandatory on every backhaul hop', - text: "{{3gpp|3GPP}} {{ts-3gpp|TS}} 33.401 ({{lte|LTE}}) and {{ts-3gpp|TS}} 33.501 (5G) **mandate** [[ipsec|IPsec]] on every S1, X2, N2, N3, Xn, F1, and E1 interface. Forgetting this in a private-5G deployment is the single most common compliance-audit failure. **Cure:** terminate every gNB-to-core hop in [[ipsec|IPsec]] {{esp|ESP}} with {{ikev2|IKEv2}}; do not run plain {{gtp-u|GTP-U}} on any link that leaves the secure perimeter." + text: '{{3gpp|3GPP}} {{ts-3gpp|TS}} 33.401 ({{lte|LTE}}) and {{ts-3gpp|TS}} 33.501 (5G) **mandate** [[ipsec|IPsec]] on every S1, X2, N2, N3, Xn, F1, and E1 interface. Forgetting this in a private-5G deployment is the single most common compliance-audit failure. **Cure:** terminate every gNB-to-core hop in [[ipsec|IPsec]] {{esp|ESP}} with {{ikev2|IKEv2}}; do not run plain {{gtp-u|GTP-U}} on any link that leaves the secure perimeter.' } ] } diff --git a/src/lib/data/protocols/coap.ts b/src/lib/data/protocols/coap.ts index d2753d5..17476f5 100644 --- a/src/lib/data/protocols/coap.ts +++ b/src/lib/data/protocols/coap.ts @@ -8,7 +8,8 @@ export const coap: Protocol = { port: 5683, year: 2014, rfc: 'RFC 7252', - oneLiner: '{{http-method|HTTP}} for tiny devices β€” [[rest|REST]] semantics over [[udp|UDP]] for constrained IoT.', + oneLiner: + '{{http-method|HTTP}} for tiny devices β€” [[rest|REST]] semantics over [[udp|UDP]] for constrained IoT.', overview: `[[coap|CoAP]] brings the familiar [[rest|REST]] model (GET, POST, PUT, DELETE) to the world of constrained IoT devices β€” think microcontrollers with 10KB of {{ram|RAM}} on lossy, low-power wireless networks. It runs over [[udp|UDP]] instead of [[tcp|TCP]], uses a compact binary format, and adds built-in support for resource observation ({{mqtt-subscribe|subscribe}} to changes). The design mirrors [[http1|HTTP]] closely enough that translating between [[coap|CoAP]] and [[http1|HTTP]] is straightforward, enabling IoT devices to integrate with web infrastructure through simple {{gateway|proxies}}. But unlike [[http1|HTTP]], [[coap|CoAP]] supports {{multicast|multicast}} (discover all devices on a network), observation (a GET with an {{coap-observe|Observe}} option that lets clients receive push notifications when a resource changes), and block-wise transfer (for large payloads on constrained links). diff --git a/src/lib/data/protocols/dash.ts b/src/lib/data/protocols/dash.ts index 2a23907..18ba73a 100644 --- a/src/lib/data/protocols/dash.ts +++ b/src/lib/data/protocols/dash.ts @@ -68,7 +68,8 @@ for period in mpd.periods: # Download segments via HTTP GET # for seg_url in rep.base_urls: # data = requests.get(seg_url.base_url_value).content`, - caption: 'dash.js plays {{mpeg-org|MPEG}}-[[dash|DASH]] content with automatic adaptive bitrate', + caption: + 'dash.js plays {{mpeg-org|MPEG}}-[[dash|DASH]] content with automatic adaptive bitrate', alternatives: [ { language: 'javascript', @@ -131,14 +132,14 @@ ffmpeg -i https://cdn.example.com/manifest.mpd \\ <AdaptationSet mimeType="video/mp4" segmentAlignment="true"> <Representation id="720p" bandwidth="2400000" width="1280" height="720" codecs="avc1.4d401f"> - <SegmentTemplate media="seg_\$Number\$.m4s" + <SegmentTemplate media="seg_$Number$.m4s" initialization="init.m4s" duration="6000" timescale="1000" startNumber="1"/> </Representation> <Representation id="480p" bandwidth="1200000" width="854" height="480" codecs="avc1.4d401e"> - <SegmentTemplate media="seg_\$Number\$.m4s" + <SegmentTemplate media="seg_$Number$.m4s" initialization="init.m4s" duration="6000" timescale="1000"/> </Representation> diff --git a/src/lib/data/protocols/dhcp.ts b/src/lib/data/protocols/dhcp.ts index 7eef755..a0c23fa 100644 --- a/src/lib/data/protocols/dhcp.ts +++ b/src/lib/data/protocols/dhcp.ts @@ -67,7 +67,8 @@ ans = srp1(dhcp_discover, timeout=5, verbose=0) if ans: offered_ip = ans[BOOTP].yiaddr print(f"Offered IP: {offered_ip}")`, - caption: 'Scapy lets you construct and send raw [[dhcp|DHCP]] packets β€” see the {{dora|DORA}} process in action', + caption: + 'Scapy lets you construct and send raw [[dhcp|DHCP]] packets β€” see the {{dora|DORA}} process in action', alternatives: [ { language: 'javascript', diff --git a/src/lib/data/protocols/dns.ts b/src/lib/data/protocols/dns.ts index 4bf814f..49a3580 100644 --- a/src/lib/data/protocols/dns.ts +++ b/src/lib/data/protocols/dns.ts @@ -215,7 +215,7 @@ curl -sH 'accept: application/dns-json' \\ org: 'Google 8.8.8.8', scale: '~14 trillion queries/day', description: - 'The original public resolver, {{anycast|anycast}} across {{google|Google}}\'s edge network. Backbone of much of the modern internet\'s name resolution.' + "The original public resolver, {{anycast|anycast}} across {{google|Google}}'s edge network. Backbone of much of the modern internet's name resolution." }, { org: 'Root server system', @@ -252,7 +252,7 @@ curl -sH 'accept: application/dns-json' \\ }, { title: 'Negative caching can hurt', - text: 'Resolvers cache NXDOMAIN responses based on the SOA minimum field. If you typo a domain name and a resolver caches the failure for an hour, your fix won\'t take effect until the cache expires. Cure: monitor for unexpected NXDOMAIN; test resolution from multiple resolvers.' + text: "Resolvers cache NXDOMAIN responses based on the SOA minimum field. If you typo a domain name and a resolver caches the failure for an hour, your fix won't take effect until the cache expires. Cure: monitor for unexpected NXDOMAIN; test resolution from multiple resolvers." } ] } diff --git a/src/lib/data/protocols/ethernet.ts b/src/lib/data/protocols/ethernet.ts index fa0b2d5..bfcb5f7 100644 --- a/src/lib/data/protocols/ethernet.ts +++ b/src/lib/data/protocols/ethernet.ts @@ -24,7 +24,7 @@ The evolution from shared media to switched networks was transformative. Hubs ga { title: 'MAC addressing', description: - 'Every network interface has a 48-bit {{mac-address|MAC address}} (e.g., \`AA:BB:CC:DD:EE:FF\`), typically burned into hardware. The first 24 bits identify the manufacturer ({{oui|OUI}}). {{broadcast|Broadcast}} frames use \`FF:FF:FF:FF:FF:FF\` as the destination to reach all devices on the segment.' + 'Every network interface has a 48-bit {{mac-address|MAC address}} (e.g., `AA:BB:CC:DD:EE:FF`), typically burned into hardware. The first 24 bits identify the manufacturer ({{oui|OUI}}). {{broadcast|Broadcast}} frames use `FF:FF:FF:FF:FF:FF` as the destination to reach all devices on the segment.' }, { title: 'Switch forwarding', diff --git a/src/lib/data/protocols/graphql.ts b/src/lib/data/protocols/graphql.ts index 3642583..3cb115d 100644 --- a/src/lib/data/protocols/graphql.ts +++ b/src/lib/data/protocols/graphql.ts @@ -64,7 +64,8 @@ response = requests.post( data = response.json()["data"] print(data["user"]["name"], data["user"]["posts"])`, - caption: 'One [[graphql|GraphQL]] query replaces multiple [[rest|REST]] calls β€” ask for exactly the data you need', + caption: + 'One [[graphql|GraphQL]] query replaces multiple [[rest|REST]] calls β€” ask for exactly the data you need', alternatives: [ { language: 'javascript', diff --git a/src/lib/data/protocols/grpc.ts b/src/lib/data/protocols/grpc.ts index c452781..abfc307 100644 --- a/src/lib/data/protocols/grpc.ts +++ b/src/lib/data/protocols/grpc.ts @@ -8,7 +8,8 @@ export const grpc: Protocol = { port: 443, year: 2015, rfc: undefined, - oneLiner: 'High-performance {{rpc|RPC}} framework using {{protocol-buffers|Protocol Buffers}} over [[http2|HTTP/2]].', + oneLiner: + 'High-performance {{rpc|RPC}} framework using {{protocol-buffers|Protocol Buffers}} over [[http2|HTTP/2]].', overview: `[[grpc|gRPC]] is {{google|Google}}'s open-source framework for remote procedure calls. Instead of designing [[rest|REST]] endpoints and manually serializing {{json|JSON}}, you define your service and messages in {{protocol-buffers|Protocol Buffers}} (.proto files), and [[grpc|gRPC]] generates strongly-typed client and server code in 11 languages. It uses [[http2|HTTP/2]] for transport, gaining {{multiplexing|multiplexing}} and {{header|header}} compression for free. Messages are serialized as {{protocol-buffers|Protocol Buffers}} β€” a binary format that's 3-10x smaller and 3-10x faster to parse than {{json|JSON}}. [[grpc|gRPC]] also natively supports {{stream|streaming}}: server-streaming, client-streaming, and bidirectional streaming. diff --git a/src/lib/data/protocols/hls.ts b/src/lib/data/protocols/hls.ts index 679dd99..18ae9a3 100644 --- a/src/lib/data/protocols/hls.ts +++ b/src/lib/data/protocols/hls.ts @@ -8,7 +8,8 @@ export const hls: Protocol = { port: 443, year: 2009, rfc: 'RFC 8216', - oneLiner: "{{apple|Apple}}'s adaptive streaming protocol β€” video delivered as small {{http-method|HTTP}} file downloads.", + oneLiner: + "{{apple|Apple}}'s adaptive streaming protocol β€” video delivered as small {{http-method|HTTP}} file downloads.", overview: `[[hls|HLS]] takes a clever approach to streaming: instead of a continuous real-time stream, it chops video into small files (typically 2-10 second segments) and serves them as ordinary [[http1|HTTP]] downloads. A {{manifest|manifest}} file (.m3u8) lists the available segments and quality levels. This design is brilliant for several reasons: it works through any {{firewall|firewall}} (it's just [[http1|HTTP]]), it scales trivially with {{cdn|CDNs}} (segments are cacheable files), and it enables {{adaptive-bitrate|adaptive bitrate}} β€” the player switches between quality levels based on {{bandwidth|bandwidth}}, providing smooth playback even on unstable connections. Increasingly, [[hls|HLS]] and [[dash|DASH]] are converging on CMAF (Common Media Application Format), which defines a unified segment format ({{fragmented-mp4|fragmented MP4}}) so content providers can encode once and serve both [[hls|HLS]] and [[dash|DASH]] from the same segments. @@ -62,7 +63,8 @@ media = m3u8.load(playlist.playlists[0].uri) for segment in media.segments: print(f"Segment: {segment.uri} ({segment.duration}s)") # data = requests.get(segment.uri).content`, - caption: 'ffmpeg creates [[hls|HLS]] segments and playlists β€” CDNs serve these as ordinary {{http-method|HTTP}} files', + caption: + 'ffmpeg creates [[hls|HLS]] segments and playlists β€” CDNs serve these as ordinary {{http-method|HTTP}} files', alternatives: [ { language: 'javascript', diff --git a/src/lib/data/protocols/http2.ts b/src/lib/data/protocols/http2.ts index 8ba6983..d694bca 100644 --- a/src/lib/data/protocols/http2.ts +++ b/src/lib/data/protocols/http2.ts @@ -8,7 +8,8 @@ export const http2: Protocol = { port: 443, year: 2015, rfc: 'RFC 9113', - oneLiner: 'Multiplexed, binary {{http-method|HTTP}} β€” many requests flying over one connection simultaneously.', + oneLiner: + 'Multiplexed, binary {{http-method|HTTP}} β€” many requests flying over one connection simultaneously.', overview: `[[http2|HTTP/2]] was designed to fix [[http1|HTTP/1.1]]'s biggest pain points without changing the semantics developers know and love. You still use GET, POST, headers, and {{status-code|status codes}} β€” but under the hood, everything is different. The protocol is {{binary-framing|binary (not text)}}, {{multiplexing|multiplexed}} (many requests share one connection), and supports {{header|header}} compression ({{hpack|HPACK}}) and {{server-push|server push}} (now deprecated β€” Chrome removed support in Chrome 106; 103 {{early-hints|Early Hints}} is the recommended replacement). {{multiplexing|Multiplexing}} is the killer feature: instead of waiting for each response before sending the next request, [[http2|HTTP/2]] interleaves multiple {{request-response|request-response}} pairs as "{{stream|streams}}" on a single [[tcp|TCP]] connection. This eliminates the need for multiple connections and dramatically improves page load times for resource-heavy sites. @@ -58,7 +59,8 @@ print(f"Status: {response.status_code}") print(f"Body: {response.text}") client.close()`, - caption: '[[http2|HTTP/2]] multiplexes requests over a single connection with {{binary-framing|binary framing}}', + caption: + '[[http2|HTTP/2]] multiplexes requests over a single connection with {{binary-framing|binary framing}}', alternatives: [ { language: 'javascript', diff --git a/src/lib/data/protocols/http3.ts b/src/lib/data/protocols/http3.ts index 9c89a6b..5d1cc1b 100644 --- a/src/lib/data/protocols/http3.ts +++ b/src/lib/data/protocols/http3.ts @@ -8,7 +8,8 @@ export const http3: Protocol = { port: 443, year: 2022, rfc: 'RFC 9114', - oneLiner: '{{http-method|HTTP}} over [[quic|QUIC]] β€” faster connections, no {{head-of-line-blocking|head-of-line blocking}}, built-in {{encryption|encryption}}.', + oneLiner: + '{{http-method|HTTP}} over [[quic|QUIC]] β€” faster connections, no {{head-of-line-blocking|head-of-line blocking}}, built-in {{encryption|encryption}}.', overview: `[[http3|HTTP/3]] is the latest evolution of {{http-method|HTTP}}, replacing [[tcp|TCP]] with [[quic|QUIC]] as its transport layer. This seemingly simple swap has profound implications: connections establish faster (1 {{rtt|RTT}} vs 2-3), lost {{packet|packets}} don't block unrelated streams, and connections survive network changes ([[wifi|Wi-Fi]] to cellular). The {{api|API}} for developers is identical β€” same methods, headers, and status codes. The difference is entirely at the transport level. [[http3|HTTP/3]] uses [[quic|QUIC]]'s independent {{stream|streams}} to solve the {{head-of-line-blocking|head-of-line blocking}} that plagued [[http2|HTTP/2]] over [[tcp|TCP]]. Each {{http-method|HTTP}} request maps to a [[quic|QUIC]] stream; if one packet is lost, only that stream waits for {{retransmission|retransmission}}. @@ -55,7 +56,8 @@ curl -sI https://cloudflare-quic.com \\ # Force HTTP/3 only (fail if not supported) curl --http3-only https://cloudflare-quic.com`, - caption: '[[http3|HTTP/3]] uses [[quic|QUIC]] transport β€” clients discover it via the Alt-Svc header', + caption: + '[[http3|HTTP/3]] uses [[quic|QUIC]] transport β€” clients discover it via the Alt-Svc header', alternatives: [ { language: 'javascript', @@ -168,7 +170,7 @@ asyncio.run(fetch_h3())` org: 'Google', scale: 'google.com / YouTube', description: - 'Default for chrome.com, youtube.com, and most {{google|Google}} web properties. {{google|Google}}\'s investment is what drove [[quic|QUIC]] + [[http3|HTTP/3]] standardisation.' + "Default for chrome.com, youtube.com, and most {{google|Google}} web properties. {{google|Google}}'s investment is what drove [[quic|QUIC]] + [[http3|HTTP/3]] standardisation." }, { org: 'Meta', @@ -197,7 +199,7 @@ asyncio.run(fetch_h3())` pitfalls: [ { title: 'Alt-Svc bootstrap requires a TCP+TLS round-trip', - text: 'A new client doesn\'t know to try [[http3|HTTP/3]] until it sees an Alt-Svc header in an [[http1|HTTP/1.1]] or [[http2|HTTP/2]] response β€” meaning the very first connection still pays the [[tcp|TCP]]+[[tls|TLS]] round-trip cost. The HTTPS [[dns|DNS]] record (HTTPS RR, [[rfc:9460|RFC 9460]]) closes this gap by advertising [[http3|HTTP/3]] support directly in [[dns|DNS]], but adoption is partial.' + text: "A new client doesn't know to try [[http3|HTTP/3]] until it sees an Alt-Svc header in an [[http1|HTTP/1.1]] or [[http2|HTTP/2]] response β€” meaning the very first connection still pays the [[tcp|TCP]]+[[tls|TLS]] round-trip cost. The HTTPS [[dns|DNS]] record (HTTPS RR, [[rfc:9460|RFC 9460]]) closes this gap by advertising [[http3|HTTP/3]] support directly in [[dns|DNS]], but adoption is partial." }, { title: 'CDN coverage is much better than origin coverage', diff --git a/src/lib/data/protocols/icmp.ts b/src/lib/data/protocols/icmp.ts index 1edf64c..02383f2 100644 --- a/src/lib/data/protocols/icmp.ts +++ b/src/lib/data/protocols/icmp.ts @@ -8,7 +8,8 @@ export const icmp: Protocol = { port: undefined, year: 1981, rfc: 'RFC 792', - oneLiner: 'The diagnostic protocol behind {{ping|ping}} and {{traceroute|traceroute}} β€” how the network reports errors.', + oneLiner: + 'The diagnostic protocol behind {{ping|ping}} and {{traceroute|traceroute}} β€” how the network reports errors.', overview: `[[icmp|ICMP]] is the internet's error-reporting and diagnostic protocol. When you type \`ping google.com\`, [[icmp|ICMP]] {{echo-request|Echo Request}} and Reply messages measure whether the target is reachable and how long the {{rtt|round trip}} takes. When you run \`traceroute\`, [[icmp|ICMP]] {{time-exceeded|Time Exceeded}} messages reveal each {{hop|hop}} along the path. [[icmp|ICMP]] is arguably the most universally used protocol in network troubleshooting. Unlike [[tcp|TCP]] or [[udp|UDP]], [[icmp|ICMP]] doesn't use {{port|ports}}. It's {{encapsulation|encapsulated}} directly in [[ip|IP]] {{packet|packets}} with protocol number 1 β€” sitting at the network layer, not the transport layer. This means [[icmp|ICMP]] can report problems that [[tcp|TCP]] and [[udp|UDP]] can't even see: unreachable networks, expired {{ttl|TTLs}}, {{fragmentation|fragmentation}} issues, and routing redirects. @@ -90,7 +91,8 @@ def ping(host): reply = sock.recv(1024) rtt = (time.time() - start) * 1000 print(f"Reply from {host}: time={rtt:.1f}ms")`, - caption: '[[icmp|ICMP]] requires raw sockets β€” it operates at the network layer, below [[tcp|TCP]]/[[udp|UDP]]', + caption: + '[[icmp|ICMP]] requires raw sockets β€” it operates at the network layer, below [[tcp|TCP]]/[[udp|UDP]]', alternatives: [ { language: 'cli', diff --git a/src/lib/data/protocols/imap.ts b/src/lib/data/protocols/imap.ts index 86206ec..0f12181 100644 --- a/src/lib/data/protocols/imap.ts +++ b/src/lib/data/protocols/imap.ts @@ -67,7 +67,8 @@ with imaplib.IMAP4_SSL('imap.example.com') as mail: print(data[0][1]) mail.logout()`, - caption: '[[imap|IMAP]] lets you search and {{imap-fetch|fetch}} email on the server β€” no need to download everything', + caption: + '[[imap|IMAP]] lets you search and {{imap-fetch|fetch}} email on the server β€” no need to download everything', alternatives: [ { language: 'javascript', diff --git a/src/lib/data/protocols/ip.ts b/src/lib/data/protocols/ip.ts index 9ebf681..0eabf2a 100644 --- a/src/lib/data/protocols/ip.ts +++ b/src/lib/data/protocols/ip.ts @@ -177,7 +177,18 @@ sudo tcpdump -i eth0 -v -c 5 ip` overhead: '20-byte header minimum (no options); 24-60 bytes with options. Every packet on the internet carries this.' }, - connections: ['tcp', 'udp', 'ethernet', 'arp', 'dns', 'wifi', 'ipv6', 'ospf', 'ipsec', 'nat-traversal'], + connections: [ + 'tcp', + 'udp', + 'ethernet', + 'arp', + 'dns', + 'wifi', + 'ipv6', + 'ospf', + 'ipsec', + 'nat-traversal' + ], links: { wikipedia: 'https://en.wikipedia.org/wiki/Internet_Protocol', rfc: 'https://datatracker.ietf.org/doc/html/rfc791' diff --git a/src/lib/data/protocols/ipsec.ts b/src/lib/data/protocols/ipsec.ts index 0ecc95b..7c7b50d 100644 --- a/src/lib/data/protocols/ipsec.ts +++ b/src/lib/data/protocols/ipsec.ts @@ -9,7 +9,7 @@ export const ipsec: Protocol = { year: 1995, rfc: 'RFC 4301 / 7296', oneLiner: - 'The {{ietf|IETF}}\'s Layer-3 cryptographic envelope β€” every site-to-site {{vpn|VPN}}, every {{3gpp|3GPP}} mobile-core backhaul, every {{ikev2|IKEv2}} client tunnel on macOS / iOS / Windows / {{android|Android}} runs IPsec.', + "The {{ietf|IETF}}'s Layer-3 cryptographic envelope β€” every site-to-site {{vpn|VPN}}, every {{3gpp|3GPP}} mobile-core backhaul, every {{ikev2|IKEv2}} client tunnel on macOS / iOS / Windows / {{android|Android}} runs IPsec.", overview: `[[ipsec|IPsec]] is the {{ietf|IETF}}'s **network-layer** security architecture. Where [[tls|TLS]] wraps a single [[tcp|TCP]] stream and [[ssh|SSH]] wraps a single remote session, [[ipsec|IPsec]] {{encryption|encrypts}} entire [[ip|IP]] {{packet|packets}} β€” host-to-host, gateway-to-gateway, or both β€” and is the only mainstream cryptographic protocol that lives *inside* the network stack rather than above it. **{{ah-authentication-header|AH}}** ([[rfc:4302|RFC 4302]]) authenticates the [[ip|IP]] {{header|header}} and {{payload|payload}}; **{{esp|ESP}}** ([[rfc:4303|RFC 4303]], the part everyone actually deploys) encrypts and authenticates payloads using {{aead|AEAD ciphers}} like {{aes-gcm|AES-GCM}} and {{chacha20-poly1305|ChaCha20-Poly1305}}. **{{ike|IKEv2}}** ([[rfc:7296|RFC 7296]], the modern key-management protocol, edited across decades by [[pioneer:charlie-kaufman|Charlie Kaufman]] and [[pioneer:tero-kivinen|Tero Kivinen]]) negotiates the {{cipher-suite|cipher suite}} and establishes the {{security-association|Security Associations}} the data plane uses. The architecture began in 1995 with [[pioneer:randall-atkinson|Randall Atkinson]] at the U.S. Naval Research Lab ({{rfc-doc|RFC}} 1825/1826/1827); [[pioneer:phil-karn|Phil Karn]] influenced the design from Qualcomm and was, in parallel, the plaintiff in *Karn v. U.S. State Department* β€” the export-control case that helped establish "code is speech." [[ipsec|IPsec]] has been re-architected twice ([[rfc:4301|RFC 4301]], 2005) and survived a 2003 architectural critique from Ferguson and Schneier (whose paper concluded it was, despite its complexity, "the best [[ip|IP]] security protocol available at the moment"). It is the **only** widely-deployed {{vpn|VPN}} that natively carries [[bgp|BGP]] / [[ospf|OSPF]] / {{multicast|multicast}} on tunnel interfaces β€” the reason {{3gpp|3GPP}} picked it for {{lte|LTE}} S1/X2 and 5G N2/N3 backhaul, and the reason every carrier on Earth runs it whether they want to or not. @@ -29,7 +29,7 @@ As of May 2026, [[ipsec|IPsec]] is also the first mainstream {{vpn|VPN}} with a { title: 'ESP β€” encrypt and authenticate every packet', description: - "Once the {{child-sa|Child SA}} is up, every outbound [[ip|IP]] {{packet|packet}} matching the Security Policy Database (SPD) is wrapped in an **{{esp|ESP}} {{header|header}}** (32-bit {{spi|SPI}} + 32-bit {{sequence-number|sequence number}}), {{aead|AEAD-encrypted}} with the negotiated key, and forwarded. In **tunnel mode** (the default for gateways) the original [[ip|IP]] packet is {{encapsulation|encapsulated}} inside a new outer [[ip|IP]] header. In **transport mode** (host-to-host) the [[ip|IP]] header is preserved and only the {{payload|payload}} is encrypted." + 'Once the {{child-sa|Child SA}} is up, every outbound [[ip|IP]] {{packet|packet}} matching the Security Policy Database (SPD) is wrapped in an **{{esp|ESP}} {{header|header}}** (32-bit {{spi|SPI}} + 32-bit {{sequence-number|sequence number}}), {{aead|AEAD-encrypted}} with the negotiated key, and forwarded. In **tunnel mode** (the default for gateways) the original [[ip|IP]] packet is {{encapsulation|encapsulated}} inside a new outer [[ip|IP]] header. In **transport mode** (host-to-host) the [[ip|IP]] header is preserved and only the {{payload|payload}} is encrypted.' }, { title: 'Anti-replay window', @@ -44,7 +44,7 @@ As of May 2026, [[ipsec|IPsec]] is also the first mainstream {{vpn|VPN}} with a { title: 'NAT-T, MOBIKE, MOBIKE-X β€” survive the real internet', description: - 'Once outside the lab, {{nat|NAT}} and mobility appear. **{{nat|NAT}}-T** (UDP/4500) wraps {{esp|ESP}} in [[udp|UDP]] so home routers don\'t corrupt the packet. **MOBIKE** ([[rfc:4555|RFC 4555]]) lets a roadwarrior survive Wi-Fi-to-{{lte|LTE}} handoff. **{{rfc-doc|RFC}} 8229 ({{ike|IKE}}/{{esp|ESP}} over [[tcp|TCP]])** is the last-resort fallback for hostile networks (hotel Wi-Fi, captive portals) that drop [[udp|UDP]].' + "Once outside the lab, {{nat|NAT}} and mobility appear. **{{nat|NAT}}-T** (UDP/4500) wraps {{esp|ESP}} in [[udp|UDP]] so home routers don't corrupt the packet. **MOBIKE** ([[rfc:4555|RFC 4555]]) lets a roadwarrior survive Wi-Fi-to-{{lte|LTE}} handoff. **{{rfc-doc|RFC}} 8229 ({{ike|IKE}}/{{esp|ESP}} over [[tcp|TCP]])** is the last-resort fallback for hostile networks (hotel Wi-Fi, captive portals) that drop [[udp|UDP]]." } ], useCases: [ @@ -89,7 +89,8 @@ swanctl --initiate --child office-net swanctl --list-sas ip -s xfrm state # kernel data-plane counters ip -s xfrm policy # SPD entries`, - caption: 'A site-to-site [[ipsec|IPsec]] tunnel in strongSwan with **{{ml-kem|ML-KEM}}-768 hybrid post-quantum** key {{exchange|exchange}} β€” production-deployable today on {{linux|Linux}} 6.x.', + caption: + 'A site-to-site [[ipsec|IPsec]] tunnel in strongSwan with **{{ml-kem|ML-KEM}}-768 hybrid post-quantum** key {{exchange|exchange}} β€” production-deployable today on {{linux|Linux}} 6.x.', alternatives: [ { language: 'python', @@ -233,7 +234,7 @@ Payloads: src: 'https://upload.wikimedia.org/wikipedia/commons/thumb/a/a8/Ipsec-ah.svg/500px-Ipsec-ah.svg.png', alt: 'IPsec Authentication Header (AH) format diagram showing the fields that authenticate every IP packet', caption: - 'IPsec\'s **Authentication Header ({{ah-authentication-header|AH}})** β€” the simpler half of the architecture. Authenticates the [[ip|IP]] header *and* {{payload|payload}}, but encrypts nothing. Almost no production deployment uses {{ah-authentication-header|AH}} alone in 2026; **{{esp|ESP}}** ([[rfc:4303|RFC 4303]]) β€” which encrypts *and* authenticates β€” has won the architecture debate.', + "IPsec's **Authentication Header ({{ah-authentication-header|AH}})** β€” the simpler half of the architecture. Authenticates the [[ip|IP]] header *and* {{payload|payload}}, but encrypts nothing. Almost no production deployment uses {{ah-authentication-header|AH}} alone in 2026; **{{esp|ESP}}** ([[rfc:4303|RFC 4303]]) β€” which encrypts *and* authenticates β€” has won the architecture debate.", credit: 'Image: Wikimedia Commons / CC BY-SA' }, @@ -323,7 +324,7 @@ Payloads: }, { title: 'WireGuard is ~4,000 lines; the IPsec stack is six digits', - text: '[[pioneer:jason-donenfeld|Jason Donenfeld]]\'s 2017 {{ndss-conf|NDSS}} WireGuard paper counted 116,730 LoC across OpenVPN + {{linux|Linux}} {{xfrm|XFRM}} + strongSwan + SoftEther. The comparison is biased β€” {{xfrm|XFRM}} does more β€” but the order of magnitude is correct. WireGuard\'s minimalism is a direct response to [[ipsec|IPsec]]\'s architectural sprawl; [[ipsec|IPsec]]\'s sprawl is a direct response to thirty years of interop requirements no clean-slate design has yet had to face.' + text: "[[pioneer:jason-donenfeld|Jason Donenfeld]]'s 2017 {{ndss-conf|NDSS}} WireGuard paper counted 116,730 LoC across OpenVPN + {{linux|Linux}} {{xfrm|XFRM}} + strongSwan + SoftEther. The comparison is biased β€” {{xfrm|XFRM}} does more β€” but the order of magnitude is correct. WireGuard's minimalism is a direct response to [[ipsec|IPsec]]'s architectural sprawl; [[ipsec|IPsec]]'s sprawl is a direct response to thirty years of interop requirements no clean-slate design has yet had to face." } ], @@ -339,7 +340,7 @@ Payloads: }, { title: 'Roadwarriors die on Wi-Fi β†’ LTE handoff without MOBIKE', - text: 'A roadwarrior session that comes up on hotel Wi-Fi will tear down the moment the laptop switches to {{lte|LTE}} β€” the {{ike-sa|IKE SA}} is bound to the source `ip:port` and reconnects from scratch. **Cure:** enable **MOBIKE** ([[rfc:4555|RFC 4555]]) on both ends (`mobike=yes` in strongSwan). The session migrates seamlessly to the new {{ip-address|address}} without re-authenticating. Built into {{apple|Apple}}\'s native client; opt-in on strongSwan/Libreswan.' + text: "A roadwarrior session that comes up on hotel Wi-Fi will tear down the moment the laptop switches to {{lte|LTE}} β€” the {{ike-sa|IKE SA}} is bound to the source `ip:port` and reconnects from scratch. **Cure:** enable **MOBIKE** ([[rfc:4555|RFC 4555]]) on both ends (`mobike=yes` in strongSwan). The session migrates seamlessly to the new {{ip-address|address}} without re-authenticating. Built into {{apple|Apple}}'s native client; opt-in on strongSwan/Libreswan." } ] } diff --git a/src/lib/data/protocols/ipv6.ts b/src/lib/data/protocols/ipv6.ts index 954e42d..a316f09 100644 --- a/src/lib/data/protocols/ipv6.ts +++ b/src/lib/data/protocols/ipv6.ts @@ -76,7 +76,8 @@ sock.send(b'GET / HTTP/1.1\\r\\n' b'Host: example.com\\r\\n\\r\\n') response = sock.recv(4096) print(response.decode()[:200])`, - caption: '[[ipv6|IPv6]] sockets use AF_INET6 and 4-tuple addresses (host, port, flowinfo, scope_id)', + caption: + '[[ipv6|IPv6]] sockets use AF_INET6 and 4-tuple addresses (host, port, flowinfo, scope_id)', alternatives: [ { language: 'cli', diff --git a/src/lib/data/protocols/kerberos.ts b/src/lib/data/protocols/kerberos.ts index 1c30b24..0396527 100644 --- a/src/lib/data/protocols/kerberos.ts +++ b/src/lib/data/protocols/kerberos.ts @@ -21,17 +21,17 @@ The famous architectural decision: Kerberos requires **time synchronisation** ac { title: 'AS-REQ β†’ AS-REP β€” get a Ticket Granting Ticket', description: - 'Client sends an **AS-REQ** to the {{kerberos-kdc|KDC}}\'s Authentication Service with its principal name (`alice@EXAMPLE.COM`). {{kerberos-kdc|KDC}} looks up Alice\'s long-term key in its database, generates a fresh session key, and returns an **{{kerberos-as-rep-acr|AS-REP}}** containing: (a) a **Ticket Granting Ticket ({{kerberos-tgt|TGT}})** {{encryption|encrypted}} under the **{{kerberos-krbtgt|krbtgt}}** principal\'s key (so only the {{kerberos-kdc|KDC}} can later decrypt it), and (b) the session key encrypted under Alice\'s long-term key (so only Alice can decrypt it). Alice never sends her password.' + "Client sends an **AS-REQ** to the {{kerberos-kdc|KDC}}'s Authentication Service with its principal name (`alice@EXAMPLE.COM`). {{kerberos-kdc|KDC}} looks up Alice's long-term key in its database, generates a fresh session key, and returns an **{{kerberos-as-rep-acr|AS-REP}}** containing: (a) a **Ticket Granting Ticket ({{kerberos-tgt|TGT}})** {{encryption|encrypted}} under the **{{kerberos-krbtgt|krbtgt}}** principal's key (so only the {{kerberos-kdc|KDC}} can later decrypt it), and (b) the session key encrypted under Alice's long-term key (so only Alice can decrypt it). Alice never sends her password." }, { title: 'Pre-authentication (the modern default)', description: - "Modern KDCs reject an unauthenticated AS-REQ. The client must include a **{{kerberos-pa-enc-timestamp|PA-ENC-TIMESTAMP}}** β€” a fresh timestamp encrypted under its long-term key β€” so the {{kerberos-kdc|KDC}} can verify the client actually knows the password before issuing a {{kerberos-tgt|TGT}}. (The old behaviour of returning the {{kerberos-as-rep-acr|AS-REP}} without pre-auth is what enables **{{kerberos-as-rep-acr|AS-REP}} roasting** β€” an attacker harvests the {{encryption|encrypted}} blob and brute-forces it offline.)" + 'Modern KDCs reject an unauthenticated AS-REQ. The client must include a **{{kerberos-pa-enc-timestamp|PA-ENC-TIMESTAMP}}** β€” a fresh timestamp encrypted under its long-term key β€” so the {{kerberos-kdc|KDC}} can verify the client actually knows the password before issuing a {{kerberos-tgt|TGT}}. (The old behaviour of returning the {{kerberos-as-rep-acr|AS-REP}} without pre-auth is what enables **{{kerberos-as-rep-acr|AS-REP}} roasting** β€” an attacker harvests the {{encryption|encrypted}} blob and brute-forces it offline.)' }, { title: 'TGS-REQ β†’ TGS-REP β€” get a service ticket', description: - 'When Alice wants to access \`HTTP/web1.example.com\`, she sends a **TGS-REQ** to the {{kerberos-kdc|KDC}}\'s {{kerberos-tgs|Ticket Granting Service}}, presenting her {{kerberos-tgt|TGT}} plus a fresh authenticator (an {{anti-replay|anti-replay}} timestamp encrypted under the {{kerberos-tgt|TGT}} session key). {{kerberos-kdc|KDC}} decrypts the {{kerberos-tgt|TGT}} (it knows {{kerberos-krbtgt|krbtgt}}\'s key), validates the authenticator, mints a new session key for Alice↔web1, and returns a **TGS-REP** with a **service ticket** encrypted under web1\'s long-term key.' + "When Alice wants to access `HTTP/web1.example.com`, she sends a **TGS-REQ** to the {{kerberos-kdc|KDC}}'s {{kerberos-tgs|Ticket Granting Service}}, presenting her {{kerberos-tgt|TGT}} plus a fresh authenticator (an {{anti-replay|anti-replay}} timestamp encrypted under the {{kerberos-tgt|TGT}} session key). {{kerberos-kdc|KDC}} decrypts the {{kerberos-tgt|TGT}} (it knows {{kerberos-krbtgt|krbtgt}}'s key), validates the authenticator, mints a new session key for Alice↔web1, and returns a **TGS-REP** with a **service ticket** encrypted under web1's long-term key." }, { title: 'AP-REQ β€” present the service ticket', @@ -41,21 +41,21 @@ The famous architectural decision: Kerberos requires **time synchronisation** ac { title: 'Cross-realm referrals', description: - "When Alice in EXAMPLE.COM wants to access a service in PARTNER.COM, her {{kerberos-kdc|KDC}} issues a **referral {{kerberos-tgt|TGT}}** for the {{kerberos-krbtgt|krbtgt}}/PARTNER.COM principal (encrypted under a cross-realm shared key). Alice presents that to the PARTNER.COM {{kerberos-kdc|KDC}}, gets a service ticket. The trust topology is a graph of shared keys between {{kerberos-krbtgt|krbtgt}} principals β€” the same mechanism Active Directory uses to scale to forests." + 'When Alice in EXAMPLE.COM wants to access a service in PARTNER.COM, her {{kerberos-kdc|KDC}} issues a **referral {{kerberos-tgt|TGT}}** for the {{kerberos-krbtgt|krbtgt}}/PARTNER.COM principal (encrypted under a cross-realm shared key). Alice presents that to the PARTNER.COM {{kerberos-kdc|KDC}}, gets a service ticket. The trust topology is a graph of shared keys between {{kerberos-krbtgt|krbtgt}} principals β€” the same mechanism Active Directory uses to scale to forests.' }, { title: 'GSS-API and SPNEGO β€” the application bindings', description: - 'Applications rarely speak Kerberos directly. They speak **GSS-{{api|API}}** (Generic Security Service {{api|API}}, [[rfc:2743|RFC 2743]]), which abstracts authentication mechanisms behind \`gss_init_sec_context\` / \`gss_accept_sec_context\`. **SPNEGO** ([[rfc:4178|RFC 4178]]) is the protocol negotiation layer that lets [[http1|HTTP]] (`Authorization: Negotiate <base64>`), SMB, LDAP, and other applications transparently use Kerberos when available and fall back to [[oauth2|OAuth]] / {{ntlm|NTLM}} otherwise. Every "Windows Integrated Authentication" prompt in Internet Explorer / Edge / Chrome is SPNEGO over {{http-method|HTTP}} wrapping a {{kerberos-ap-req|Kerberos AP-REQ}}.' + 'Applications rarely speak Kerberos directly. They speak **GSS-{{api|API}}** (Generic Security Service {{api|API}}, [[rfc:2743|RFC 2743]]), which abstracts authentication mechanisms behind `gss_init_sec_context` / `gss_accept_sec_context`. **SPNEGO** ([[rfc:4178|RFC 4178]]) is the protocol negotiation layer that lets [[http1|HTTP]] (`Authorization: Negotiate <base64>`), SMB, LDAP, and other applications transparently use Kerberos when available and fall back to [[oauth2|OAuth]] / {{ntlm|NTLM}} otherwise. Every "Windows Integrated Authentication" prompt in Internet Explorer / Edge / Chrome is SPNEGO over {{http-method|HTTP}} wrapping a {{kerberos-ap-req|Kerberos AP-REQ}}.' } ], useCases: [ '**Active Directory** β€” every Microsoft AD domain on Earth, primary authentication since Windows 2000', '**Hadoop / Spark / Kafka** in enterprise β€” sec=krb5 is the only way to authenticate jobs at scale', '**NFSv4** with `sec=krb5` / `sec=krb5i` / `sec=krb5p` β€” the only path to integrity + confidentiality on NFS', - '**FreeIPA** β€” Red Hat\'s integrated identity solution (Kerberos + LDAP + DNS + CA)', + "**FreeIPA** β€” Red Hat's integrated identity solution (Kerberos + LDAP + DNS + CA)", '**MIT Athena** β€” still operational at MIT in 2026, four decades after the protocol was designed there', - '**SSH with GSSAPIAuthentication** β€” passwordless SSH within a Kerberos realm via the user\'s TGT' + "**SSH with GSSAPIAuthentication** β€” passwordless SSH within a Kerberos realm via the user's TGT" ], codeExample: { language: 'cli', @@ -99,7 +99,8 @@ slot KVNO Principal Encryption type ---- ---- ------------------------------------ ------------------ 1 2 HTTP/web1.example.com@EXAMPLE.COM aes256-cts-hmac-sha384-192 2 2 HTTP/web1.example.com@EXAMPLE.COM aes128-cts-hmac-sha256-128`, - caption: 'A full [[kerberos|Kerberos]] {{login-auth|login}} + service-ticket flow on {{mit|MIT}} krb5 β€” the toolchain that has powered {{mit|MIT}} Athena since 1988.', + caption: + 'A full [[kerberos|Kerberos]] {{login-auth|login}} + service-ticket flow on {{mit|MIT}} krb5 β€” the toolchain that has powered {{mit|MIT}} Athena since 1988.', alternatives: [ { language: 'python', @@ -275,7 +276,7 @@ server.listen(443);` src: 'https://upload.wikimedia.org/wikipedia/commons/thumb/2/25/Cerberus-Blake.jpeg/500px-Cerberus-Blake.jpeg', alt: 'William Blake painting of Cerberus, the three-headed dog of Greek mythology that the Kerberos protocol is named after', caption: - "William Blake\'s **Cerberus** (c.1825). The three-headed dog from Greek mythology that guards the gates of Hades is the namesake of the protocol designed at {{mit|MIT}} Project Athena in 1983 β€” three heads for *client*, *server*, and *Key Distribution Center*. The protocol\'s motto could be the same as Cerberus's: nothing in, nothing out, without showing me a ticket.", + "William Blake's **Cerberus** (c.1825). The three-headed dog from Greek mythology that guards the gates of Hades is the namesake of the protocol designed at {{mit|MIT}} Project Athena in 1983 β€” three heads for *client*, *server*, and *Key Distribution Center*. The protocol's motto could be the same as Cerberus's: nothing in, nothing out, without showing me a ticket.", credit: 'Image: Wikimedia Commons / Public Domain (William Blake, c.1825)' }, @@ -285,14 +286,20 @@ server.listen(443);` title: 'MIT krb5 1.21.3 β€” CVE-2024-37370 / CVE-2024-37371', description: 'Critical GSS message-token handling bugs in the {{mit|MIT}} codebase. {{cve|CVE}}-2024-37370 was an out-of-bounds write in `gss_unwrap` triggerable by a malformed token; {{cve|CVE}}-2024-37371 was a related integrity-bypass. Patched in 1.21.3, picked up downstream by every {{linux|Linux}} distro within days.', - source: { url: 'https://nvd.nist.gov/vuln/detail/CVE-2024-37370', label: 'NVD CVE-2024-37370' } + source: { + url: 'https://nvd.nist.gov/vuln/detail/CVE-2024-37370', + label: 'NVD CVE-2024-37370' + } }, { date: '2025-08', title: 'MIT krb5 1.22 β€” PKINIT ECDH, IAKerb, Unix-domain transport', description: '5 August 2025 release. Headline features: **PKINIT {{ecdh|ECDH}}/EC certs** (smart-card auth on {{curve25519|Curve25519}} / P-384), **paChecksum2** support (longer FAST-armored {{checksum|checksum}} to retire {{sha1|SHA-1}}), **IAKerb** for realm discovery without [[dns|DNS]], and the first **Unix-domain socket transport** for in-host {{kerberos-kdc|KDC}} traffic. Initial release was withdrawn on 17 August for a critical vuln; re-issued as 1.22.2.', - source: { url: 'https://web.mit.edu/kerberos/krb5-1.22/', label: 'MIT krb5 1.22 release notes' } + source: { + url: 'https://web.mit.edu/kerberos/krb5-1.22/', + label: 'MIT krb5 1.22 release notes' + } }, { date: '2025-09', @@ -308,7 +315,7 @@ server.listen(443);` date: '2026-04', title: 'Windows Server 2025 / Win11 24H2 β€” IAKerb + Local KDC GA', description: - 'Phase 2 of {{microsoft|Microsoft}}\'s {{ntlm|NTLM}} phase-out. **IAKerb** (Initial and Pass-Through Authentication using Kerberos) lets clients authenticate through a proxy when they cannot reach a {{kerberos-kdc|KDC}} directly. **Local {{kerberos-kdc|KDC}}** for workgroup machines (no domain join needed). Together they cover the residual use cases {{ntlm|NTLM}} was holding onto.', + "Phase 2 of {{microsoft|Microsoft}}'s {{ntlm|NTLM}} phase-out. **IAKerb** (Initial and Pass-Through Authentication using Kerberos) lets clients authenticate through a proxy when they cannot reach a {{kerberos-kdc|KDC}} directly. **Local {{kerberos-kdc|KDC}}** for workgroup machines (no domain join needed). Together they cover the residual use cases {{ntlm|NTLM}} was holding onto.", source: { url: 'https://techcommunity.microsoft.com/t5/windows-it-pro-blog/the-evolution-of-windows-authentication/ba-p/3926341', label: 'Microsoft Windows IT Pro blog' @@ -331,7 +338,7 @@ server.listen(443);` org: 'Microsoft Active Directory', scale: 'Every AD domain on Earth (>500M Windows endpoints, every Fortune 1000)', description: - 'Kerberos has been {{ad-active-directory|AD}}\'s primary authentication since Windows 2000. Every domain-joined Windows machine, every {{ad-active-directory|AD}}-integrated {{exchange|Exchange}} / Outlook, every SharePoint, every {{sql|SQL}} Server with Windows Authentication runs Kerberos under the hood. The single largest [[kerberos|Kerberos]] deployment ever.' + "Kerberos has been {{ad-active-directory|AD}}'s primary authentication since Windows 2000. Every domain-joined Windows machine, every {{ad-active-directory|AD}}-integrated {{exchange|Exchange}} / Outlook, every SharePoint, every {{sql|SQL}} Server with Windows Authentication runs Kerberos under the hood. The single largest [[kerberos|Kerberos]] deployment ever." }, { org: 'MIT Kerberos (krb5)', @@ -341,7 +348,7 @@ server.listen(443);` }, { org: 'Heimdal', - scale: 'Apple\'s macOS, Samba, FreeBSD', + scale: "Apple's macOS, Samba, FreeBSD", description: '{{bsd|BSD}}-licensed alternative to {{mit|MIT}} Kerberos, originated at SU/KTH in Sweden. {{apple|Apple}} shipped Heimdal in every macOS from 10.5 (2007) onward; Samba 4 uses it for {{ad-active-directory|AD}} compatibility. Love HΓΆrnquist Γ…strand has been the long-running maintainer.' }, @@ -349,14 +356,14 @@ server.listen(443);` org: 'Hadoop / Spark / Kafka', scale: 'Every Cloudera CDH / Hortonworks HDP / Confluent Platform install', description: - "`hadoop.security.authentication = kerberos` is the only path to authenticated jobs at scale in a Hadoop cluster. The 2015–2025 enterprise-Hadoop era ran on krb5 keytabs distributed via Ambari/Cloudera Manager. Spark, Hive, Impala, HBase, ZooKeeper all bind to the same {{kerberos-kdc|KDC}}." + '`hadoop.security.authentication = kerberos` is the only path to authenticated jobs at scale in a Hadoop cluster. The 2015–2025 enterprise-Hadoop era ran on krb5 keytabs distributed via Ambari/Cloudera Manager. Spark, Hive, Impala, HBase, ZooKeeper all bind to the same {{kerberos-kdc|KDC}}.' } ], funFacts: [ { title: 'Named after the three-headed dog that guards Hades', - text: '**Cerberus** in Greek mythology had three heads β€” one for *past*, *present*, and *future*, or for *birth*, *youth*, and *old age*, depending on the source. The {{mit|MIT}} team picked the name to evoke three principals β€” **client**, **server**, **{{kerberos-kdc|KDC}}** β€” with the dog\'s job: nothing crosses without a ticket. Pronounced *KER-ber-os* in English; *KEHR-ber-os* in modern Greek.' + text: "**Cerberus** in Greek mythology had three heads β€” one for *past*, *present*, and *future*, or for *birth*, *youth*, and *old age*, depending on the source. The {{mit|MIT}} team picked the name to evoke three principals β€” **client**, **server**, **{{kerberos-kdc|KDC}}** β€” with the dog's job: nothing crosses without a ticket. Pronounced *KER-ber-os* in English; *KEHR-ber-os* in modern Greek." }, { title: 'V4 was held back by US export controls', @@ -364,11 +371,11 @@ server.listen(443);` }, { title: '"AS-REP roasting" is when you forget pre-auth', - text: 'A principal with `DONT_REQUIRE_PREAUTH` flag set can be queried by *anyone* with a network path to the {{kerberos-kdc|KDC}} β€” no password required. The {{kerberos-kdc|KDC}} returns an {{kerberos-as-rep-acr|AS-REP}} encrypted under the principal\'s long-term key, which the attacker can then brute-force offline. **{{kerberos-as-rep-acr|AS-REP}} roasting** (Tim Medin, 2014) is the standard penetration-test move against {{ad-active-directory|AD}} environments where service-account pre-auth was accidentally disabled. Sister technique: **Kerberoasting** (also Tim Medin, 2014) requests TGS-REPs for service principals and brute-forces those.' + text: "A principal with `DONT_REQUIRE_PREAUTH` flag set can be queried by *anyone* with a network path to the {{kerberos-kdc|KDC}} β€” no password required. The {{kerberos-kdc|KDC}} returns an {{kerberos-as-rep-acr|AS-REP}} encrypted under the principal's long-term key, which the attacker can then brute-force offline. **{{kerberos-as-rep-acr|AS-REP}} roasting** (Tim Medin, 2014) is the standard penetration-test move against {{ad-active-directory|AD}} environments where service-account pre-auth was accidentally disabled. Sister technique: **Kerberoasting** (also Tim Medin, 2014) requests TGS-REPs for service principals and brute-forces those." }, { title: 'Clock skew is the silent killer', - text: 'Default `clockskew` in `krb5.conf` is **Β±5 minutes**. If a client\'s clock drifts more than that, every authentication fails with `KRB_AP_ERR_SKEW`. Every enterprise Kerberos outage of the 2010s eventually traced back to [[ntp|NTP]] β€” broken [[ntp|NTP]] servers, firewalls blocking UDP/123, virtualised {{hosts-bare|hosts}} with drift. The protocol\'s most operationally fragile dependency isn\'t crypto; it\'s time.' + text: "Default `clockskew` in `krb5.conf` is **Β±5 minutes**. If a client's clock drifts more than that, every authentication fails with `KRB_AP_ERR_SKEW`. Every enterprise Kerberos outage of the 2010s eventually traced back to [[ntp|NTP]] β€” broken [[ntp|NTP]] servers, firewalls blocking UDP/123, virtualised {{hosts-bare|hosts}} with drift. The protocol's most operationally fragile dependency isn't crypto; it's time." } ], @@ -384,7 +391,7 @@ server.listen(443);` }, { title: 'Weak encryption types still lurk in old keytabs', - text: "Every keytab includes a list of {{encryption|encryption}} types the principal supports. Old {{ad-active-directory|AD}} environments have **{{rc4|RC4}} (NEA1)** still enabled β€” the {{encryption|encryption}} type **Kerberoasting** specifically targets, because {{rc4|RC4}} keys are derived from NT hash and brute-force in hours. **Cure:** set `default_tkt_enctypes = aes256-cts-{{hmac|hmac}}-sha384-192 aes128-cts-{{hmac|hmac}}-sha256-128` in `krb5.conf`; remove {{rc4|RC4}} from the supported list with `Set-ADUser -KerberosEncryptionType AES128,AES256`; audit with {{wireshark|Wireshark}} filter `kerberos.etype == 23` to find any remaining {{rc4|RC4}} traffic." + text: 'Every keytab includes a list of {{encryption|encryption}} types the principal supports. Old {{ad-active-directory|AD}} environments have **{{rc4|RC4}} (NEA1)** still enabled β€” the {{encryption|encryption}} type **Kerberoasting** specifically targets, because {{rc4|RC4}} keys are derived from NT hash and brute-force in hours. **Cure:** set `default_tkt_enctypes = aes256-cts-{{hmac|hmac}}-sha384-192 aes128-cts-{{hmac|hmac}}-sha256-128` in `krb5.conf`; remove {{rc4|RC4}} from the supported list with `Set-ADUser -KerberosEncryptionType AES128,AES256`; audit with {{wireshark|Wireshark}} filter `kerberos.etype == 23` to find any remaining {{rc4|RC4}} traffic.' } ] } diff --git a/src/lib/data/protocols/mdns-dns-sd.ts b/src/lib/data/protocols/mdns-dns-sd.ts index 9346b63..80edd76 100644 --- a/src/lib/data/protocols/mdns-dns-sd.ts +++ b/src/lib/data/protocols/mdns-dns-sd.ts @@ -24,7 +24,7 @@ Stuart Cheshire and Marc Krochmal at {{apple|Apple}} shipped this as **Rendezvou { title: 'Announce β€” two responses with cache-flush', description: - "On winning the probe, the host sends two Response messages 1 second apart, each with the **cache-flush** bit set on its A/{{aaaa-record|AAAA}}/{{srv-record|SRV}}/{{txt-record|TXT}} records. Every receiver replaces any stale entries for that name with the new ones. The host is now *live* on the link." + 'On winning the probe, the host sends two Response messages 1 second apart, each with the **cache-flush** bit set on its A/{{aaaa-record|AAAA}}/{{srv-record|SRV}}/{{txt-record|TXT}} records. Every receiver replaces any stale entries for that name with the new ones. The host is now *live* on the link.' }, { title: 'Respond β€” multicast queries, 20–120 ms random delay', @@ -83,7 +83,8 @@ try: input("Press Enter to stop browsing...\\n") finally: zc.close()`, - caption: 'A [[mdns-dns-sd|DNS-SD]] browser in 25 lines of Python. Same code finds Chromecasts (`_googlecast._tcp.`), printers (`_ipp._tcp.`), or {{matter|Matter}} devices (`_matter._tcp.`).', + caption: + 'A [[mdns-dns-sd|DNS-SD]] browser in 25 lines of Python. Same code finds Chromecasts (`_googlecast._tcp.`), printers (`_ipp._tcp.`), or {{matter|Matter}} devices (`_matter._tcp.`).', alternatives: [ { language: 'javascript', @@ -280,7 +281,7 @@ Each RR's CLASS field: org: 'Google Chromecast + Cast ecosystem', scale: '100+ million Cast devices (Google, 2018)', description: - "Every Chromecast, Cast-enabled TV, and Cast-enabled speaker announces `_googlecast._tcp.local` via [[mdns-dns-sd|mDNS]]. {{google|Google}} last published an installed-base figure (\"100 million\") at I/O 2018; the actual number today is presumably much higher." + 'Every Chromecast, Cast-enabled TV, and Cast-enabled speaker announces `_googlecast._tcp.local` via [[mdns-dns-sd|mDNS]]. {{google|Google}} last published an installed-base figure ("100 million") at I/O 2018; the actual number today is presumably much higher.' }, { org: 'Matter ecosystem (CSA)', @@ -293,11 +294,11 @@ Each RR's CLASS field: funFacts: [ { title: 'The name was almost "OpenTalk"', - text: 'AppleInsider\'s exclusive of 18 February 2005 revealed {{apple|Apple}} had filed for the *OpenTalk* trademark before settling on **Bonjour**. Internal {{apple|Apple}} logic: *"naturally, when Rendezvous-enabled computers and devices come within range of each other, they say \'hello\' β€” hence the name \'Bonjour.\'"* The rebrand was forced by a trademark dispute with Tibco, which had held *TIBCO Rendezvous* for its enterprise messaging product since 1994.' + text: "AppleInsider's exclusive of 18 February 2005 revealed {{apple|Apple}} had filed for the *OpenTalk* trademark before settling on **Bonjour**. Internal {{apple|Apple}} logic: *\"naturally, when Rendezvous-enabled computers and devices come within range of each other, they say 'hello' β€” hence the name 'Bonjour.'\"* The rebrand was forced by a trademark dispute with Tibco, which had held *TIBCO Rendezvous* for its enterprise messaging product since 1994." }, { title: '`.local` is an act of IETF jurisdiction over ICANN', - text: '{{rfc-doc|RFC}} 6761 (February 2013) uses {{iana|IANA}}\'s Special-Use Domain Names registry to *take a {{tld|TLD}} off the table* permanently. There is no legal way for {{icann|ICANN}} to delegate `.local` to a registry β€” this is one of the cleanest examples of the {{ietf|IETF}} asserting authority over names {{icann|ICANN}} normally controls. The legitimisation of a de-facto practice that had been running on every Mac for 11 years.' + text: "{{rfc-doc|RFC}} 6761 (February 2013) uses {{iana|IANA}}'s Special-Use Domain Names registry to *take a {{tld|TLD}} off the table* permanently. There is no legal way for {{icann|ICANN}} to delegate `.local` to a registry β€” this is one of the cleanest examples of the {{ietf|IETF}} asserting authority over names {{icann|ICANN}} normally controls. The legitimisation of a de-facto practice that had been running on every Mac for 11 years." }, { title: 'Stuart Cheshire also wrote a tank game', @@ -305,15 +306,15 @@ Each RR's CLASS field: }, { title: 'The Avahi name is a lemur', - text: 'Trent Lloyd suggested *Avahi* (genus *Avahi*, woolly lemur, endemic to Madagascar) when the project was founded in 2004, following freedesktop.org\'s pattern of whimsical animal codenames. The Avahi project logo is a stylised lemur. Sometimes mis-translated from Latin β€” *Avahi laniger* is the proper binomial; *avahi* is the Malagasy root.' + text: "Trent Lloyd suggested *Avahi* (genus *Avahi*, woolly lemur, endemic to Madagascar) when the project was founded in 2004, following freedesktop.org's pattern of whimsical animal codenames. The Avahi project logo is a stylised lemur. Sometimes mis-translated from Latin β€” *Avahi laniger* is the proper binomial; *avahi* is the Malagasy root." } ], practicalWisdom: { pitfalls: [ { - title: 'IGMP/MLD snooping is mDNS\'s #1 enemy on enterprise Wi-Fi', - text: 'Access points forward {{multicast|multicast}} at the lowest basic rate (often 6 Mbps); managed switches with IGMP snooping enabled drop frames whose listeners haven\'t joined the group; per-{{ssid|SSID}}/per-{{vlan|VLAN}} isolation breaks the link-local scope assumption. **Cure:** deploy an [[mdns-dns-sd|mDNS]] gateway ({{cisco|Cisco}} WLC `mdns-sd` profile, Aruba AirGroup, Aerohive Bonjour Gateway). Whitelist exactly `224.0.0.251` and `FF02::FB`; rate-limit UDP/5353 to ~50 pps per client; never enable {{multicast|multicast}}-to-{{unicast|unicast}} conversion blindly.' + title: "IGMP/MLD snooping is mDNS's #1 enemy on enterprise Wi-Fi", + text: "Access points forward {{multicast|multicast}} at the lowest basic rate (often 6 Mbps); managed switches with IGMP snooping enabled drop frames whose listeners haven't joined the group; per-{{ssid|SSID}}/per-{{vlan|VLAN}} isolation breaks the link-local scope assumption. **Cure:** deploy an [[mdns-dns-sd|mDNS]] gateway ({{cisco|Cisco}} WLC `mdns-sd` profile, Aruba AirGroup, Aerohive Bonjour Gateway). Whitelist exactly `224.0.0.251` and `FF02::FB`; rate-limit UDP/5353 to ~50 pps per client; never enable {{multicast|multicast}}-to-{{unicast|unicast}} conversion blindly." }, { title: 'mDNS responders exposed to the WAN are a DDoS reflector', diff --git a/src/lib/data/protocols/mptcp.ts b/src/lib/data/protocols/mptcp.ts index 9f966d3..e3a675a 100644 --- a/src/lib/data/protocols/mptcp.ts +++ b/src/lib/data/protocols/mptcp.ts @@ -62,7 +62,8 @@ sock.sendall(b'GET / HTTP/1.1\\r\\nHost: example.com\\r\\n\\r\\n') response = sock.recv(4096) print(response.decode()) sock.close()`, - caption: '[[mptcp|MPTCP]] in Python β€” same {{api|API}} as [[tcp|TCP]], but the kernel routes data over multiple paths', + caption: + '[[mptcp|MPTCP]] in Python β€” same {{api|API}} as [[tcp|TCP]], but the kernel routes data over multiple paths', alternatives: [ { language: 'javascript', diff --git a/src/lib/data/protocols/mqtt.ts b/src/lib/data/protocols/mqtt.ts index cee8d2f..f46df39 100644 --- a/src/lib/data/protocols/mqtt.ts +++ b/src/lib/data/protocols/mqtt.ts @@ -59,7 +59,8 @@ client.on_message = on_message # client.publish("home/kitchen/temperature", "22.5") client.loop_forever()`, - caption: '{{mqtt-subscribe|Subscribe}} to temperature readings from any room β€” the broker handles routing', + caption: + '{{mqtt-subscribe|Subscribe}} to temperature readings from any room β€” the broker handles routing', alternatives: [ { language: 'javascript', diff --git a/src/lib/data/protocols/nat-traversal.ts b/src/lib/data/protocols/nat-traversal.ts index 000db1f..f053bc8 100644 --- a/src/lib/data/protocols/nat-traversal.ts +++ b/src/lib/data/protocols/nat-traversal.ts @@ -29,17 +29,17 @@ All three protocols share the same 20-byte {{stun|STUN}} header, transaction IDs { title: 'TURN: allocate a relay (fallback)', description: - "If direct paths might fail, the agent also `Allocate`s a port on a {{turn|TURN}} server using long-term credentials. The {{turn|TURN}} server returns `{{xor-relayed-address|XOR-RELAYED-ADDRESS}}` β€” a public `ip:port` the {{peer|peer}} can hit. The default allocation lifetime is 600 seconds; clients refresh at ~450 s." + 'If direct paths might fail, the agent also `Allocate`s a port on a {{turn|TURN}} server using long-term credentials. The {{turn|TURN}} server returns `{{xor-relayed-address|XOR-RELAYED-ADDRESS}}` β€” a public `ip:port` the {{peer|peer}} can hit. The default allocation lifetime is 600 seconds; clients refresh at ~450 s.' }, { title: 'Trickle and pair', description: - 'Candidates are signalled to the other {{peer|peer}} as they arrive ([[rfc:8838|RFC 8838]] Trickle {{ice|ICE}}) over the application\'s signalling channel ([[websockets|WebSocket]], [[sip|SIP]], etc.). Each side pairs every local candidate with every remote candidate and assigns a priority β€” host (126) > {{peer|peer}}-reflexive (110) > server-reflexive (100) > relay (0).' + "Candidates are signalled to the other {{peer|peer}} as they arrive ([[rfc:8838|RFC 8838]] Trickle {{ice|ICE}}) over the application's signalling channel ([[websockets|WebSocket]], [[sip|SIP]], etc.). Each side pairs every local candidate with every remote candidate and assigns a priority β€” host (126) > {{peer|peer}}-reflexive (110) > server-reflexive (100) > relay (0)." }, { title: 'Connectivity checks', description: - "Both agents send {{stun|STUN}} Binding Requests across every pair using short-term {{ice|ICE}} credentials (`ufrag`/`pwd` from the [[sdp|SDP]]). The first pair to round-trip successfully becomes a *valid pair*; the controlling agent then nominates one with `{{use-candidate|USE-CANDIDATE}}`." + 'Both agents send {{stun|STUN}} Binding Requests across every pair using short-term {{ice|ICE}} credentials (`ufrag`/`pwd` from the [[sdp|SDP]]). The first pair to round-trip successfully becomes a *valid pair*; the controlling agent then nominates one with `{{use-candidate|USE-CANDIDATE}}`.' }, { title: 'Keep the path alive', @@ -78,7 +78,7 @@ const offer = await pc.createOffer(); await pc.setLocalDescription(offer); signal({ sdp: offer });`, caption: - "A browser {{ice|ICE}} agent: {{stun|STUN}} + {{turn|TURN}} URLs go in, candidates trickle out. The {{nat|NAT traversal}} is invisible β€” but every event firing here corresponds to a {{stun|STUN}} message on the wire.", + 'A browser {{ice|ICE}} agent: {{stun|STUN}} + {{turn|TURN}} URLs go in, candidates trickle out. The {{nat|NAT traversal}} is invisible β€” but every event firing here corresponds to a {{stun|STUN}} message on the wire.', alternatives: [ { language: 'python', @@ -215,7 +215,7 @@ Attributes: date: '2024-09', title: 'Cloudflare Realtime TURN GA', description: - '{{cloudflare|Cloudflare}} opened its {{anycast|anycast}} {{turn|TURN}} service (`{{turn|turn}}.{{cloudflare|cloudflare}}.com`) at 335+ locations with $0.05/GB egress and 1 TB free per month β€” the first major price drop in managed [[nat-traversal|NAT traversal]] in years. Free entirely when paired with {{cloudflare|Cloudflare}}\'s {{sfu|SFU}}.', + "{{cloudflare|Cloudflare}} opened its {{anycast|anycast}} {{turn|TURN}} service (`{{turn|turn}}.{{cloudflare|cloudflare}}.com`) at 335+ locations with $0.05/GB egress and 1 TB free per month β€” the first major price drop in managed [[nat-traversal|NAT traversal]] in years. Free entirely when paired with {{cloudflare|Cloudflare}}'s {{sfu|SFU}}.", source: { url: 'https://developers.cloudflare.com/realtime/turn/', label: 'Cloudflare Realtime TURN docs' @@ -270,7 +270,7 @@ Attributes: org: 'Tailscale', scale: '>90% direct-path success via STUN hole-punching', description: - 'Tailscale\'s WireGuard overlay uses {{stun|STUN}}-style probes to find a direct path between peers; their proprietary **DERP** relays absorb the rest as a {{turn|TURN}}-analogue. Public engineering posts in 2024–25 detailed multi-part improvements to [[udp|UDP]] hole-punching.' + "Tailscale's WireGuard overlay uses {{stun|STUN}}-style probes to find a direct path between peers; their proprietary **DERP** relays absorb the rest as a {{turn|TURN}}-analogue. Public engineering posts in 2024–25 detailed multi-part improvements to [[udp|UDP]] hole-punching." }, { org: 'coturn', @@ -283,7 +283,7 @@ Attributes: funFacts: [ { title: 'The magic cookie spells "STUN"', - text: '{{stun|STUN}}\'s `0x2112A442` is the {{ietf|IETF}}\'s nod to the {{ip-address|IP}} version field, but the **FINGERPRINT** attribute {{checksum|checksum}} is XORed with `0x5354554E` β€” the {{ascii|ASCII}} bytes for `{{stun|STUN}}`. The protocol literally signs its own name on every packet.' + text: "{{stun|STUN}}'s `0x2112A442` is the {{ietf|IETF}}'s nod to the {{ip-address|IP}} version field, but the **FINGERPRINT** attribute {{checksum|checksum}} is XORed with `0x5354554E` β€” the {{ascii|ASCII}} bytes for `{{stun|STUN}}`. The protocol literally signs its own name on every packet." }, { title: 'STUN changed what its own acronym means', diff --git a/src/lib/data/protocols/nfc.ts b/src/lib/data/protocols/nfc.ts index 8b2f59f..ea88cbd 100644 --- a/src/lib/data/protocols/nfc.ts +++ b/src/lib/data/protocols/nfc.ts @@ -19,7 +19,7 @@ The hinge of the modern story is **9 September 2014**, when Tim Cook announced { { title: '13.56 MHz inductive coupling in the ISM band', description: - "All NFC variants operate at a carrier of 13.56 MHz Β± 7 kHz, the unlicensed {{ism-band|ISM}} allocation that is the legacy of {{iso|ISO}} 14443. Coupling is *inductive* (magnetic) between two loop antennas β€” the magnetic field falls off as 1/rΒ³, vs 1/rΒ² for far-field radiative coupling. Effective range is ≀10 cm for {{iso|ISO}} 14443 (NFC-A/B/F) and historically ≀1 m for {{iso|ISO}} 15693 ({{nfc-v|NFC-V}}). The {{pcd|PCD}} (Proximity Coupling Device β€” the reader) energises its loop antenna; the passive {{picc|PICC}} (Proximity Integrated Circuit Card) harvests power from the field and communicates back via {{load-modulation|load modulation}} β€” switching a resistor on its own antenna at an 847.5 kHz subcarrier (13.56 MHz/16), perceived by the reader as small amplitude/phase changes in its own resonant loop. Modern phones use *active {{load-modulation|load modulation}}* (ALM) instead, generating a small reflected carrier β€” which is why an iPhone can be read across a metal-backed case where a plain plastic card cannot." + 'All NFC variants operate at a carrier of 13.56 MHz Β± 7 kHz, the unlicensed {{ism-band|ISM}} allocation that is the legacy of {{iso|ISO}} 14443. Coupling is *inductive* (magnetic) between two loop antennas β€” the magnetic field falls off as 1/rΒ³, vs 1/rΒ² for far-field radiative coupling. Effective range is ≀10 cm for {{iso|ISO}} 14443 (NFC-A/B/F) and historically ≀1 m for {{iso|ISO}} 15693 ({{nfc-v|NFC-V}}). The {{pcd|PCD}} (Proximity Coupling Device β€” the reader) energises its loop antenna; the passive {{picc|PICC}} (Proximity Integrated Circuit Card) harvests power from the field and communicates back via {{load-modulation|load modulation}} β€” switching a resistor on its own antenna at an 847.5 kHz subcarrier (13.56 MHz/16), perceived by the reader as small amplitude/phase changes in its own resonant loop. Modern phones use *active {{load-modulation|load modulation}}* (ALM) instead, generating a small reflected carrier β€” which is why an iPhone can be read across a metal-backed case where a plain plastic card cannot.' }, { title: 'Three flavours of NFC on the air', @@ -29,22 +29,22 @@ The hinge of the modern story is **9 September 2014**, when Tim Cook announced { { title: 'Anti-collision: REQA β†’ ATQA β†’ SEL/NVB β†’ SAK', description: - "When a {{picc|PICC}} enters the field it begins in {{imap-idle|IDLE}}. The reader broadcasts a 7-bit {{reqa|REQA}} (0x26) or WUPA (0x52) short frame; the card responds with **{{atqa|ATQA}}** (2 bytes) declaring its {{uid|UID}} size (4/7/10 bytes) and {{anti-collision|anti-collision}} support. The reader then runs the **bit-frame {{anti-collision|anti-collision}}** loop with {{sel-iso|SEL}}+NVB frames ({{sel-iso|SEL}}=0x93 for cascade level 1, 0x95 for CL2, 0x97 for CL3), converging on each byte of the {{uid|UID}} a bit at a time when multiple cards are in the field. When the {{uid|UID}} is complete the card answers with **{{sak|SAK}}**; if bit 6 of {{sak|SAK}} is set, the card supports {{iso|ISO}} 14443-4 and the reader proceeds with {{rats|RATS}}β†’{{ats-nfc|ATS}} to negotiate frame size (FSCI) and timing (FWI). T2T cards skip {{rats|RATS}} and go straight to T2T {{read-record|READ}} commands." + 'When a {{picc|PICC}} enters the field it begins in {{imap-idle|IDLE}}. The reader broadcasts a 7-bit {{reqa|REQA}} (0x26) or WUPA (0x52) short frame; the card responds with **{{atqa|ATQA}}** (2 bytes) declaring its {{uid|UID}} size (4/7/10 bytes) and {{anti-collision|anti-collision}} support. The reader then runs the **bit-frame {{anti-collision|anti-collision}}** loop with {{sel-iso|SEL}}+NVB frames ({{sel-iso|SEL}}=0x93 for cascade level 1, 0x95 for CL2, 0x97 for CL3), converging on each byte of the {{uid|UID}} a bit at a time when multiple cards are in the field. When the {{uid|UID}} is complete the card answers with **{{sak|SAK}}**; if bit 6 of {{sak|SAK}} is set, the card supports {{iso|ISO}} 14443-4 and the reader proceeds with {{rats|RATS}}β†’{{ats-nfc|ATS}} to negotiate frame size (FSCI) and timing (FWI). T2T cards skip {{rats|RATS}} and go straight to T2T {{read-record|READ}} commands.' }, { title: 'Card Emulation: SELECT PPSE β†’ SELECT AID β†’ GET PROCESSING OPTIONS β†’ GENERATE AC', description: - "For card-emulation mode ({{apple|Apple}} Pay, {{transit|transit}}, access), once 14443-4 is established the reader speaks **{{iso|ISO}} 7816-4 APDUs**: 4-byte header `CLA INS P1 P2` + optional command body. The first command is *{{imap-select|SELECT}} {{ppse|PPSE}}* β€” the Proximity Payment System Environment {{aid|AID}} `2PAY.SYS.DDF01` β€” and the card returns an FCI listing all supported {{aid|payment AIDs}} in priority order. The reader picks one (e.g. Mastercard `A0000000041010`), SELECTs it, gets back a {{pdol|PDOL}} listing parameters the card needs (amount, currency, country, terminal-type, unpredictable number), then sends *GET PROCESSING OPTIONS* with those parameters. The card returns AIP+{{afl|AFL}} telling the reader which files to read; {{read-record|READ}} RECORDs pull the {{pan-id|PAN}}, expiry, and public-key {{certificate-chain|certificate chain}}. Finally *{{generate-ac|GENERATE AC}}* with CDOL1 data asks the card for an {{emv-cryptogram|Application Cryptogram}} β€” either an {{arqc|ARQC}} (online) or TC (offline). The cryptogram is signed in the eSE/{{hce|HCE}} app and is what proves the transaction to the issuer." + 'For card-emulation mode ({{apple|Apple}} Pay, {{transit|transit}}, access), once 14443-4 is established the reader speaks **{{iso|ISO}} 7816-4 APDUs**: 4-byte header `CLA INS P1 P2` + optional command body. The first command is *{{imap-select|SELECT}} {{ppse|PPSE}}* β€” the Proximity Payment System Environment {{aid|AID}} `2PAY.SYS.DDF01` β€” and the card returns an FCI listing all supported {{aid|payment AIDs}} in priority order. The reader picks one (e.g. Mastercard `A0000000041010`), SELECTs it, gets back a {{pdol|PDOL}} listing parameters the card needs (amount, currency, country, terminal-type, unpredictable number), then sends *GET PROCESSING OPTIONS* with those parameters. The card returns AIP+{{afl|AFL}} telling the reader which files to read; {{read-record|READ}} RECORDs pull the {{pan-id|PAN}}, expiry, and public-key {{certificate-chain|certificate chain}}. Finally *{{generate-ac|GENERATE AC}}* with CDOL1 data asks the card for an {{emv-cryptogram|Application Cryptogram}} β€” either an {{arqc|ARQC}} (online) or TC (offline). The cryptogram is signed in the eSE/{{hce|HCE}} app and is what proves the transaction to the issuer.' }, { title: 'NDEF: the data format for everything that is not a payment', description: - "NFC Forum **{{ndef|NDEF}}** (NFC Data {{exchange|Exchange}} Format) is the binary record container that lives in tags and rides over {{llcp|LLCP}}/{{snep|SNEP}}. Each record begins with a 1-byte header β€” bits MB/ME (Message Begin/End), CF (Chunk Flag), SR (Short Record β€” 1-byte length vs 4), IL ({{id-identifier|ID}} Length present), and a 3-bit TNF (Type Name Format: 0=Empty, 1=Well-Known like `U` for {{uri|URI}} or `T` for Text, 2={{mime|MIME}} media, 3=Absolute {{uri|URI}}, 4=External, 5=Unknown). The {{uri|URI}} Well-Known record uses a single-byte prefix shorthand β€” 0x03 for `https://` saves 8 bytes per record on tags as small as 48 bytes. {{ndef|NDEF}} was formally adopted as an IEC standard in **March 2026** alongside NFC-WLC." + 'NFC Forum **{{ndef|NDEF}}** (NFC Data {{exchange|Exchange}} Format) is the binary record container that lives in tags and rides over {{llcp|LLCP}}/{{snep|SNEP}}. Each record begins with a 1-byte header β€” bits MB/ME (Message Begin/End), CF (Chunk Flag), SR (Short Record β€” 1-byte length vs 4), IL ({{id-identifier|ID}} Length present), and a 3-bit TNF (Type Name Format: 0=Empty, 1=Well-Known like `U` for {{uri|URI}} or `T` for Text, 2={{mime|MIME}} media, 3=Absolute {{uri|URI}}, 4=External, 5=Unknown). The {{uri|URI}} Well-Known record uses a single-byte prefix shorthand β€” 0x03 for `https://` saves 8 bytes per record on tags as small as 48 bytes. {{ndef|NDEF}} was formally adopted as an IEC standard in **March 2026** alongside NFC-WLC.' }, { title: 'Three transports, one tap: Connection Handover to Bluetooth / Wi-Fi / Matter', description: - "For higher-throughput sessions NFC is almost always a *bootstrap*. The **Connection Handover** spec (v1.5) defines {{ndef|NDEF}} records of TNF=0x02 with {{mime|MIME}} `application/vnd.bluetooth.le.oob` carrying the [[bluetooth|Bluetooth]] {{mac-address|MAC address}}, name, and Security Manager {{oob|OOB}} key β€” a single tap replaces a discovery/pairing dialog. The parallel Wi-Fi handover record carries {{ssid|SSID}}/key/security mode β€” used for tap-to-join on printers and some smart-plug commissioning. **{{matter|Matter}} 1.3+** adds NFC as one of the three permitted commissioning paths alongside QR and {{ble|BLE}}. **{{ccc-digital-key|CCC Digital Key}} 3.0/4.0** uses NFC to bootstrap a credential into a phone, then {{ble|BLE}} for proximity and [[uwb|UWB]] for centimetre-accurate ranging. {{aliro|Aliro}} 1.0 likewise spans NFC tap-to-access + {{ble|BLE}} proximity + {{ble|BLE}}/UWB ranged β€” three transports, one credential." + 'For higher-throughput sessions NFC is almost always a *bootstrap*. The **Connection Handover** spec (v1.5) defines {{ndef|NDEF}} records of TNF=0x02 with {{mime|MIME}} `application/vnd.bluetooth.le.oob` carrying the [[bluetooth|Bluetooth]] {{mac-address|MAC address}}, name, and Security Manager {{oob|OOB}} key β€” a single tap replaces a discovery/pairing dialog. The parallel Wi-Fi handover record carries {{ssid|SSID}}/key/security mode β€” used for tap-to-join on printers and some smart-plug commissioning. **{{matter|Matter}} 1.3+** adds NFC as one of the three permitted commissioning paths alongside QR and {{ble|BLE}}. **{{ccc-digital-key|CCC Digital Key}} 3.0/4.0** uses NFC to bootstrap a credential into a phone, then {{ble|BLE}} for proximity and [[uwb|UWB]] for centimetre-accurate ranging. {{aliro|Aliro}} 1.0 likewise spans NFC tap-to-access + {{ble|BLE}} proximity + {{ble|BLE}}/UWB ranged β€” three transports, one credential.' }, { title: 'Tokenisation: why your real card number never leaves the bank', @@ -293,7 +293,7 @@ Total airtime from field-on to ARQC: ~300–800 ms on a real terminal.` date: '2024-03', title: 'iOS 17.4 opens NFC HCE to EEA wallets (DMA)', description: - "On 25 January 2024 {{apple|Apple}} announced β€” and in March 2024 iOS 17.4 shipped β€” the **NFC & Secure Element Platform** entitlement for the European Economic Area. For the first time on iPhone, third-party wallets can do {{hce|Host Card Emulation}} contactless payments without going through {{apple|Apple}} Pay. PayPal Germany was the first to ship; the entitlement covers {{hce|HCE}} access, side-button shortcut, Face/Touch {{id-identifier|ID}}, and Field-Detect. Available **only inside the EEA** (27 EU states + Iceland, Liechtenstein, Norway) and **only on iPhone** β€” not {{apple|Apple}} Watch, not iPad.", + 'On 25 January 2024 {{apple|Apple}} announced β€” and in March 2024 iOS 17.4 shipped β€” the **NFC & Secure Element Platform** entitlement for the European Economic Area. For the first time on iPhone, third-party wallets can do {{hce|Host Card Emulation}} contactless payments without going through {{apple|Apple}} Pay. PayPal Germany was the first to ship; the entitlement covers {{hce|HCE}} access, side-button shortcut, Face/Touch {{id-identifier|ID}}, and Field-Detect. Available **only inside the EEA** (27 EU states + Iceland, Liechtenstein, Norway) and **only on iPhone** β€” not {{apple|Apple}} Watch, not iPad.', source: { url: 'https://www.apple.com/newsroom/2024/01/apple-announces-changes-to-ios-safari-and-the-app-store-in-the-european-union/', label: 'Apple newsroom, 25 Jan 2024' @@ -301,7 +301,7 @@ Total airtime from field-on to ARQC: ~300–800 ms on a real terminal.` }, { date: '2024-07', - title: 'EU Commission accepts Apple\'s 10-year NFC opening commitments', + title: "EU Commission accepts Apple's 10-year NFC opening commitments", description: "On **17 July 2024** the European Commission's commitments decision {{ip-address|IP}}/24/3706 made {{apple|Apple}}'s NFC opening legally binding for **ten years**, monitored by an independent trustee. The first time any regulator has compelled an {{oem|OEM}} to open NFC card emulation. The pattern is now templated and the watch-items are the UK CMA, Japan JFTC, and Australian ACCC.", source: { @@ -323,7 +323,7 @@ Total airtime from field-on to ARQC: ~300–800 ms on a real terminal.` date: '2025-07', title: 'CCC Digital Key 4.0 announced', description: - "The Car Connectivity Consortium announced **Digital Key 4.0** in July 2025 and tested it at the 13th Plugfest, hosted by {{apple|Apple}}. Headline: *cross-version compatibility* β€” a DK3 phone unlocks a DK4 car and vice versa. **115 vehicle/module products** were certified in 2025 alone, including the first Chinese OEMs (NIO, XPENG, Geely group brands). Devices must support at least one of NFC, {{ble|BLE}}, or [[uwb|UWB]]; NFC remains the fallback that works even on a phone with a dead battery (>5 hours on iPhone reserve power).", + 'The Car Connectivity Consortium announced **Digital Key 4.0** in July 2025 and tested it at the 13th Plugfest, hosted by {{apple|Apple}}. Headline: *cross-version compatibility* β€” a DK3 phone unlocks a DK4 car and vice versa. **115 vehicle/module products** were certified in 2025 alone, including the first Chinese OEMs (NIO, XPENG, Geely group brands). Devices must support at least one of NFC, {{ble|BLE}}, or [[uwb|UWB]]; NFC remains the fallback that works even on a phone with a dead battery (>5 hours on iPhone reserve power).', source: { url: 'https://carconnectivity.org/', label: 'Car Connectivity Consortium' @@ -333,7 +333,7 @@ Total airtime from field-on to ARQC: ~300–800 ms on a real terminal.` date: '2026-02', title: 'Aliro 1.0 finalised β€” "Matter for doors"', description: - "On **26 February 2026** the Connectivity Standards Alliance β€” the same group that runs {{matter|Matter}} β€” finalised {{aliro|Aliro 1.0}}, a {{pki|PKI}}-based access-control credential standard. {{ecdsa|ECDSA}} mutual authentication, support for NFC tap-to-access, {{ble|BLE}} proximity, and {{ble|BLE}}+[[uwb|UWB]] ranged unlock, with credentials provisioned into {{apple|Apple}}/{{google|Google}}/Samsung wallets. First certifications: {{apple|Apple}}, Allegion, Aqara, {{google|Google}}, HID, Kastle, Kwikset, Last Lock, Nordic, Nuki, {{nxp|NXP}}, {{qorvo|Qorvo}}, Samsung, STMicro. Target verticals: corporate, hospitality, residential, multi-family, university.", + 'On **26 February 2026** the Connectivity Standards Alliance β€” the same group that runs {{matter|Matter}} β€” finalised {{aliro|Aliro 1.0}}, a {{pki|PKI}}-based access-control credential standard. {{ecdsa|ECDSA}} mutual authentication, support for NFC tap-to-access, {{ble|BLE}} proximity, and {{ble|BLE}}+[[uwb|UWB]] ranged unlock, with credentials provisioned into {{apple|Apple}}/{{google|Google}}/Samsung wallets. First certifications: {{apple|Apple}}, Allegion, Aqara, {{google|Google}}, HID, Kastle, Kwikset, Last Lock, Nordic, Nuki, {{nxp|NXP}}, {{qorvo|Qorvo}}, Samsung, STMicro. Target verticals: corporate, hospitality, residential, multi-family, university.', source: { url: 'https://csa-iot.org/newsroom/introducing-aliro-1-0/', label: 'CSA: Introducing Aliro 1.0' @@ -354,19 +354,22 @@ Total airtime from field-on to ARQC: ~300–800 ms on a real terminal.` realWorldDeployments: [ { org: 'Apple Pay', - scale: 'Available in 85+ countries; ~$9.4 B revenue 2025 (3.4 % of all Apple); ~54 % share of US in-store mobile wallet', + scale: + 'Available in 85+ countries; ~$9.4 B revenue 2025 (3.4 % of all Apple); ~54 % share of US in-store mobile wallet', description: "Announced 9 September 2014 at Flint Center, Cupertino β€” the same hall where Steve Jobs unveiled the original Macintosh in 1984. Tim Cook held up a leather wallet: 'Our vision is to replace this β€” we're going to start with payments.' Launched in the US on 20 October 2014 with American Express, Bank of America, Capital One, Chase, Citi, and Wells Fargo. The three pillars β€” NFC, {{ese|embedded Secure Element}}, and Touch {{id-identifier|ID}} β€” set the template every mobile wallet has followed since. {{apple|Apple}} Pay generated ~\\$7.6 trillion in annualised transaction volume by 2025." }, { org: 'Tap to Pay on iPhone', - scale: 'More than 50 countries and regions by Q1 2026; available on iPhone XS or newer; no extra hardware', + scale: + 'More than 50 countries and regions by Q1 2026; available on iPhone XS or newer; no extra hardware', description: "{{apple|Apple}} acquired Mobeewave in 2020 and launched Tap to Pay on iPhone in the US in February 2022 via Stripe. By April 2026 {{apple|Apple}} stated availability in **more than 50 countries and regions** β€” 18 European countries on 27 May 2025, 5 Nordic + Baltic + Monaco on 23 September 2025, Singapore 2 December 2025, Malaysia 22 April 2026. Turns the merchant's iPhone into a contactless terminal β€” the protocol shift is that the iPhone is now usually on **both ends** of the tap." }, { org: 'JR East Suica + Hong Kong Octopus', - scale: '95.64 M Suica issued (Oct 2023), 6.6 M daily taps; >35 M Octopus cards on a population of 7.5 M', + scale: + '95.64 M Suica issued (Oct 2023), 6.6 M daily taps; >35 M Octopus cards on a population of 7.5 M', description: "Sony's FeliCa team began work in the late 1980s; the protocol shipped commercially as the **Hong Kong Octopus card on 1 September 1997** β€” four years before NFC was named, seven before the NFC Forum existed. **Suica** launched on **18 November 2001** at 424 metropolitan Tokyo stations. {{apple|Apple}} Pay Suica became available on 7 September 2016 with the iPhone 7 (Japan-only), then went global on the iPhone 8. By 2021 Japan had ~200 M IC cards across nine mutually-usable regional schemes β€” more cards than people." }, @@ -378,9 +381,10 @@ Total airtime from field-on to ARQC: ~300–800 ms on a real terminal.` }, { org: 'ICAO eMRTD passports + DTC', - scale: '~1 billion electronic passports in circulation worldwide; DTC airport pilots active 2024–26', + scale: + '~1 billion electronic passports in circulation worldwide; DTC airport pilots active 2024–26', description: - "Belgium issued the first {{icao|ICAO}} Doc 9303-compliant eMRTD in **2004**. By 2026 ~1 billion are in circulation. The chip is an {{iso|ISO}} 14443 {{picc|PICC}} running {{iso|ISO}} 7816-4 with a small {{icao|ICAO}} file system (DG1 {{mrz|MRZ}}, DG2 photo, EF.SOD signature, EF.COM index, plus optional DG3 fingerprints / DG4 iris). The reader cannot get any data without **BAC** (legacy 3DES from MRZ) or **PACE** (modern {{ecdh|ECDH}} from MRZ or 6-digit CAN). The Digital Travel Credential (DTC-PC/VC) β€” passport on phone β€” is in airport pilots in Finland, the Netherlands, and Singapore." + 'Belgium issued the first {{icao|ICAO}} Doc 9303-compliant eMRTD in **2004**. By 2026 ~1 billion are in circulation. The chip is an {{iso|ISO}} 14443 {{picc|PICC}} running {{iso|ISO}} 7816-4 with a small {{icao|ICAO}} file system (DG1 {{mrz|MRZ}}, DG2 photo, EF.SOD signature, EF.COM index, plus optional DG3 fingerprints / DG4 iris). The reader cannot get any data without **BAC** (legacy 3DES from MRZ) or **PACE** (modern {{ecdh|ECDH}} from MRZ or 6-digit CAN). The Digital Travel Credential (DTC-PC/VC) β€” passport on phone β€” is in airport pilots in Finland, the Netherlands, and Singapore.' }, { org: 'NXP MIFARE family', @@ -390,7 +394,8 @@ Total airtime from field-on to ARQC: ~300–800 ms on a real terminal.` }, { org: 'CCC Digital Key', - scale: '115 vehicle/module products certified in 2025; BMW first to certify (late 2024); first Chinese OEMs in 2025', + scale: + '115 vehicle/module products certified in 2025; BMW first to certify (late 2024); first Chinese OEMs in 2025', description: "The Car Connectivity Consortium's Digital Key turns a phone into a vehicle key. v1.0 was proprietary; v2.0 standardised NFC; v3.0 added {{ble|BLE}} proximity + [[uwb|UWB]] ranging (so the car can tell *which side* of the door you are on); **v4.0** (announced July 2025) brings cross-version interoperability. BMW + {{nxp|NXP}} were the first to certify (late 2024). 115 products certified in 2025 alone; Mercedes, Hyundai/Kia/Genesis, Audi (new in 2025), Volvo, Porsche, GM, Ford, plus a wave of Chinese OEMs (NIO, XPENG, Geely group β€” Volvo, Polestar, ZEEKR, Lynk & Co., smart, Lotus)." } @@ -399,7 +404,7 @@ Total airtime from field-on to ARQC: ~300–800 ms on a real terminal.` funFacts: [ { title: 'Charles Walton died the same year Google Wallet launched', - text: "[[pioneer:charles-walton|Charles Walton]], the {{ibm|IBM}} disk-drive engineer who founded **Proximity Devices in 1970** and holds the canonical {{rfid|RFID}} ancestor patent (US 4,384,288, 1983, *Portable Radio Frequency Emitting Identifier*) plus 50+ others, earned several million dollars in royalties before the bulk of his patents expired in the mid-1990s β€” just before the wave of {{rfid|RFID}} adoption from Walmart and the US Department of Defense. He died in Los Gatos on **6 November 2011**, three months after {{google|Google}} launched **{{google|Google}} Wallet 1.0** on the Nexus S 4G in May 2011. Two pioneers of the same field, separated by 60 years, in the same calendar year." + text: '[[pioneer:charles-walton|Charles Walton]], the {{ibm|IBM}} disk-drive engineer who founded **Proximity Devices in 1970** and holds the canonical {{rfid|RFID}} ancestor patent (US 4,384,288, 1983, *Portable Radio Frequency Emitting Identifier*) plus 50+ others, earned several million dollars in royalties before the bulk of his patents expired in the mid-1990s β€” just before the wave of {{rfid|RFID}} adoption from Walmart and the US Department of Defense. He died in Los Gatos on **6 November 2011**, three months after {{google|Google}} launched **{{google|Google}} Wallet 1.0** on the Nexus S 4G in May 2011. Two pioneers of the same field, separated by 60 years, in the same calendar year.' }, { title: 'FeliCa beat the NFC Forum to commercial deployment by seven years', @@ -419,7 +424,7 @@ Total airtime from field-on to ARQC: ~300–800 ms on a real terminal.` }, { title: 'The "switch off NFC to save battery" myth', - text: "{{imap-idle|Idle}} NFC controllers draw on the order of **single-digit microamps** in their lowest poll states β€” orders of magnitude less than the display, baseband, or {{ap-access-point|AP}}. Disabling NFC has no measurable battery effect on any modern phone. The option survives in {{os|OS}} settings only as a *security/privacy* toggle, not a power one. If you have ever turned NFC off to make your phone last longer, you have done exactly nothing for your battery." + text: '{{imap-idle|Idle}} NFC controllers draw on the order of **single-digit microamps** in their lowest poll states β€” orders of magnitude less than the display, baseband, or {{ap-access-point|AP}}. Disabling NFC has no measurable battery effect on any modern phone. The option survives in {{os|OS}} settings only as a *security/privacy* toggle, not a power one. If you have ever turned NFC off to make your phone last longer, you have done exactly nothing for your battery.' } ], diff --git a/src/lib/data/protocols/ospf.ts b/src/lib/data/protocols/ospf.ts index e348a75..9a59c83 100644 --- a/src/lib/data/protocols/ospf.ts +++ b/src/lib/data/protocols/ospf.ts @@ -19,7 +19,7 @@ export const ospf: Protocol = { { title: 'Hello β€” discover neighbours', description: - 'Each [[ospf|OSPF]]-enabled interface multicasts Hello {{packet|packets}} to `224.0.0.5` ([[ipv6|IPv6]]: `FF02::5`) every HelloInterval (default 10 s on point-to-point, 30 s on NBMA). Hellos carry the router\'s {{id-identifier|ID}}, options, and the list of neighbours it currently sees on this link β€” bidirectional visibility is established as soon as a Hello lists *you* in its neighbours field.' + "Each [[ospf|OSPF]]-enabled interface multicasts Hello {{packet|packets}} to `224.0.0.5` ([[ipv6|IPv6]]: `FF02::5`) every HelloInterval (default 10 s on point-to-point, 30 s on NBMA). Hellos carry the router's {{id-identifier|ID}}, options, and the list of neighbours it currently sees on this link β€” bidirectional visibility is established as soon as a Hello lists *you* in its neighbours field." }, { title: 'Adjacency state machine', @@ -29,7 +29,7 @@ export const ospf: Protocol = { { title: 'Synchronise the LSDB', description: - 'Routers {{exchange|exchange}} **Database Description ({{dbd|DBD}})** packets carrying {{lsa|LSA}} *headers* (sequence/age/length), then send **Link State Request ({{lsr|LSR}})** packets asking for the LSAs they don\'t have, and receive them in **Link State {{bgp-update|Update}} ({{lsu|LSU}})** packets. **{{lsack|LSAck}}** packets explicitly acknowledge receipt β€” [[ospf|OSPF]] has {{retransmission|reliable delivery}} without [[tcp|TCP]].' + "Routers {{exchange|exchange}} **Database Description ({{dbd|DBD}})** packets carrying {{lsa|LSA}} *headers* (sequence/age/length), then send **Link State Request ({{lsr|LSR}})** packets asking for the LSAs they don't have, and receive them in **Link State {{bgp-update|Update}} ({{lsu|LSU}})** packets. **{{lsack|LSAck}}** packets explicitly acknowledge receipt β€” [[ospf|OSPF]] has {{retransmission|reliable delivery}} without [[tcp|TCP]]." }, { title: 'Flood, throttle, age', @@ -81,7 +81,8 @@ vtysh -c 'show ip ospf neighbor' vtysh -c 'show ip ospf database' vtysh -c 'show ip ospf interface eth0' vtysh -c 'show ip route ospf'`, - caption: 'A minimal [[ospf|OSPF]] speaker on {{frr|FRR}} β€” three commands set up Area 0, {{md5|MD5}} authentication, and sub-second {{bfd|BFD}}-style failure detection.', + caption: + 'A minimal [[ospf|OSPF]] speaker on {{frr|FRR}} β€” three commands set up Area 0, {{md5|MD5}} authentication, and sub-second {{bfd|BFD}}-style failure detection.', alternatives: [ { language: 'python', @@ -230,7 +231,10 @@ Total time on a tuned network: < 100 ms.` title: 'Junos OS Evolved 24.2R1 ships HMAC-SHA-2 keychains + Flex-Algo on hardware', description: 'Juniper\'s {{junos|Junos}} {{os|OS}} Evolved 24.2R1 (Aug 2024) added [[ospf|OSPFv2]] {{hmac|HMAC}}-{{sha2|SHA-2}} keychain authentication, Flex-Algo FAD with {{srlg|SRLG}}-exclude, and link-delay normalisation on ACX/PTX hardware β€” bringing Flex-Algo from "shipped in {{ios-xr|IOS-XR}}" to "shipped at multi-vendor parity."', - source: { url: 'https://supportportal.juniper.net/s/article/Junos-OS-Evolved-24-2R1-Release-Notes', label: 'Junos OS Evolved 24.2R1' } + source: { + url: 'https://supportportal.juniper.net/s/article/Junos-OS-Evolved-24-2R1-Release-Notes', + label: 'Junos OS Evolved 24.2R1' + } }, { date: '2025-10', @@ -258,7 +262,7 @@ Total time on a tuned network: < 100 ms.` org: 'FRRouting', scale: 'The dominant open-source IGP implementation', description: - "Forked from Quagga in 2017 and now stewarded by the {{linux|Linux}} Foundation. Ships [[ospf|OSPFv2]] and [[ospf|OSPFv3]] daemons (`ospfd`, `ospf6d`) used everywhere from Vyatta/VyOS edge routers to enterprise SD-{{wan|WAN}} appliances. Public {{cve|CVE}} traffic (e.g. {{cve|CVE}}-2025-61103) tracks its prevalence." + 'Forked from Quagga in 2017 and now stewarded by the {{linux|Linux}} Foundation. Ships [[ospf|OSPFv2]] and [[ospf|OSPFv3]] daemons (`ospfd`, `ospf6d`) used everywhere from Vyatta/VyOS edge routers to enterprise SD-{{wan|WAN}} appliances. Public {{cve|CVE}} traffic (e.g. {{cve|CVE}}-2025-61103) tracks its prevalence.' }, { org: 'Cisco IOS-XR / Juniper Junos', @@ -291,7 +295,7 @@ Total time on a tuned network: < 100 ms.` pitfalls: [ { title: 'Mismatched HelloInterval / DeadInterval = no adjacency', - text: 'Two routers will sit in `Init` forever if their Hello or Dead intervals differ by even one second. There is no negotiation. **Cure:** standardise per-interface in your template; use `show ip ospf interface eth0` to dump both sides\' actual values before opening tickets. The state machine\'s most common stuck-state.' + text: "Two routers will sit in `Init` forever if their Hello or Dead intervals differ by even one second. There is no negotiation. **Cure:** standardise per-interface in your template; use `show ip ospf interface eth0` to dump both sides' actual values before opening tickets. The state machine's most common stuck-state." }, { title: 'Default 40-second DeadInterval is a 1990s artefact', diff --git a/src/lib/data/protocols/quic.ts b/src/lib/data/protocols/quic.ts index eefeb1f..187c056 100644 --- a/src/lib/data/protocols/quic.ts +++ b/src/lib/data/protocols/quic.ts @@ -66,7 +66,8 @@ async def main(): print(f"Response: {response}") asyncio.run(main())`, - caption: '[[quic|QUIC]] combines transport + {{encryption|encryption}} in one step, enabling faster connections', + caption: + '[[quic|QUIC]] combines transport + {{encryption|encryption}} in one step, enabling faster connections', alternatives: [ { language: 'javascript', @@ -185,7 +186,7 @@ sudo tcpdump -i any udp port 443` date: '2024-09', title: 'Multipath QUIC reaches stable IETF draft', description: - 'draft-{{ietf|ietf}}-quic-{{multipath|multipath}} progressed to stable; {{multipath|multipath}} [[quic|QUIC]] inherits [[mptcp|MPTCP]]\'s algorithmic ideas inside a transport that actually traverses middleboxes. {{apple|Apple}}, {{google|Google}}, and several mobile carriers are running interop events.', + "draft-{{ietf|ietf}}-quic-{{multipath|multipath}} progressed to stable; {{multipath|multipath}} [[quic|QUIC]] inherits [[mptcp|MPTCP]]'s algorithmic ideas inside a transport that actually traverses middleboxes. {{apple|Apple}}, {{google|Google}}, and several mobile carriers are running interop events.", source: { url: 'https://datatracker.ietf.org/doc/draft-ietf-quic-multipath/', label: 'IETF Datatracker' @@ -210,13 +211,13 @@ sudo tcpdump -i any udp port 443` org: 'Meta', scale: '>75% of web/mobile bytes', description: - 'Facebook, Instagram, WhatsApp serve majority of traffic via [[quic|QUIC]]. mvfst ({{meta|Meta}}\'s [[quic|QUIC]] implementation) is open-source.' + "Facebook, Instagram, WhatsApp serve majority of traffic via [[quic|QUIC]]. mvfst ({{meta|Meta}}'s [[quic|QUIC]] implementation) is open-source." }, { org: 'Cloudflare', scale: 'All HTTPS traffic', description: - 'quiche library powers [[quic|QUIC]] at {{cloudflare|Cloudflare}}\'s edge for every HTTPS site behind their {{cdn|CDN}}. Connection-coalescing and {{zero-rtt|0-RTT}} enabled by default.' + "quiche library powers [[quic|QUIC]] at {{cloudflare|Cloudflare}}'s edge for every HTTPS site behind their {{cdn|CDN}}. Connection-coalescing and {{zero-rtt|0-RTT}} enabled by default." }, { org: 'Apple', @@ -249,7 +250,7 @@ sudo tcpdump -i any udp port 443` }, { title: 'Connection migration breaks middleboxes', - text: 'Some {{stateful|stateful}} middleboxes ({{nat|NAT}} routers, transparent proxies) drop a connection when its source [[ip|IP]] suddenly changes β€” they assume it\'s a new flow. [[quic|QUIC]]\'s Path Validation fixes this when both endpoints support it; the path-probing {{handshake|handshake}} is [[rfc:9000|RFC 9000]] Β§8.' + text: "Some {{stateful|stateful}} middleboxes ({{nat|NAT}} routers, transparent proxies) drop a connection when its source [[ip|IP]] suddenly changes β€” they assume it's a new flow. [[quic|QUIC]]'s Path Validation fixes this when both endpoints support it; the path-probing {{handshake|handshake}} is [[rfc:9000|RFC 9000]] Β§8." }, { title: 'Higher CPU than kernel TCP', diff --git a/src/lib/data/protocols/sctp.ts b/src/lib/data/protocols/sctp.ts index 8244043..1d5f30c 100644 --- a/src/lib/data/protocols/sctp.ts +++ b/src/lib/data/protocols/sctp.ts @@ -8,7 +8,8 @@ export const sctp: Protocol = { port: undefined, year: 2000, rfc: 'RFC 9260', - oneLiner: "Multi-streaming, {{multi-homing|multi-homing}} transport β€” [[tcp|TCP]]'s more capable but less popular cousin.", + oneLiner: + "Multi-streaming, {{multi-homing|multi-homing}} transport β€” [[tcp|TCP]]'s more capable but less popular cousin.", overview: `[[sctp|SCTP]] was designed for telecom {{signaling|signaling}} but offers features that both [[tcp|TCP]] and [[udp|UDP]] lack. It supports {{multiplexing|multiple independent streams}} within a single connection (like [[quic|QUIC]], but decades earlier), {{multi-homing|multi-homing}} (a connection can span multiple network interfaces for redundancy), and message boundaries (unlike [[tcp|TCP]]'s byte stream). Despite its technical superiority in many aspects, [[sctp|SCTP]] never gained widespread adoption on the public internet because {{nat|NATs}} and {{firewall|firewalls}} typically don't understand it. However, it's widely used in telecom infrastructure (4G/5G networks use it extensively) and is used by [[webrtc|WebRTC]]'s data channels β€” though in [[webrtc|WebRTC]], [[sctp|SCTP]] doesn't run as a raw {{os|OS}}-level transport; instead it runs over {{dtls|DTLS}} over [[udp|UDP]], with the [[sctp|SCTP]] implementation in userspace. diff --git a/src/lib/data/protocols/sdp.ts b/src/lib/data/protocols/sdp.ts index b693e7c..a8f660c 100644 --- a/src/lib/data/protocols/sdp.ts +++ b/src/lib/data/protocols/sdp.ts @@ -74,7 +74,8 @@ async def main(): await pc.setRemoteDescription(answer) asyncio.run(main())`, - caption: '[[webrtc|WebRTC]] [[sdp|SDP]] offer/answer β€” [[sdp|SDP]] is generated automatically from your media tracks', + caption: + '[[webrtc|WebRTC]] [[sdp|SDP]] offer/answer β€” [[sdp|SDP]] is generated automatically from your media tracks', alternatives: [ { language: 'javascript', diff --git a/src/lib/data/protocols/sip.ts b/src/lib/data/protocols/sip.ts index 066eec9..cb3e897 100644 --- a/src/lib/data/protocols/sip.ts +++ b/src/lib/data/protocols/sip.ts @@ -8,7 +8,8 @@ export const sip: Protocol = { port: 5060, year: 1999, rfc: 'RFC 3261', - oneLiner: 'The "dialing" protocol for {{voip|VoIP}} β€” establishes, modifies, and tears down calls.', + oneLiner: + 'The "dialing" protocol for {{voip|VoIP}} β€” establishes, modifies, and tears down calls.', overview: `[[sip|SIP]] is the {{signaling|signaling}} {{protocol|protocol}} that makes {{voip|VoIP}} calls happen. It doesn't carry the actual audio or video (that's [[rtp|RTP]]'s job). Instead, [[sip|SIP]] handles the "control plane": inviting someone to a call, ringing, answering, putting on hold, transferring, and hanging up. [[sip|SIP]]'s design was inspired by [[http1|HTTP]] β€” it uses text-based {{request-response|request/response}} messages with methods like {{sip-invite|INVITE}}, {{ack|ACK}}, BYE, and REGISTER. URIs identify users (sip:alice@example.com). This [[http1|HTTP]]-like design made it easier to implement and debug compared to the ITU's H.323 alternative. @@ -69,7 +70,8 @@ acfg.sipConfig.authCreds.append( account = pj.Account() account.create(acfg) # Sends SIP REGISTER`, - caption: 'PJSIP registers with a [[sip|SIP]] server β€” the {{sip-invite|INVITE}}/200 OK/{{ack|ACK}} flow handles call setup', + caption: + 'PJSIP registers with a [[sip|SIP]] server β€” the {{sip-invite|INVITE}}/200 OK/{{ack|ACK}} flow handles call setup', alternatives: [ { language: 'javascript', diff --git a/src/lib/data/protocols/smtp.ts b/src/lib/data/protocols/smtp.ts index 14c9ab8..e707da8 100644 --- a/src/lib/data/protocols/smtp.ts +++ b/src/lib/data/protocols/smtp.ts @@ -57,7 +57,8 @@ with smtplib.SMTP("smtp.example.com", 587) as server: server.starttls() server.login("sender@example.com", "password") server.send_message(msg)`, - caption: '[[smtp|SMTP]] delivers email hop by hop β€” {{starttls|STARTTLS}} encrypts the connection.', + caption: + '[[smtp|SMTP]] delivers email hop by hop β€” {{starttls|STARTTLS}} encrypts the connection.', alternatives: [ { language: 'javascript', diff --git a/src/lib/data/protocols/ssh.ts b/src/lib/data/protocols/ssh.ts index aed7201..cf008e9 100644 --- a/src/lib/data/protocols/ssh.ts +++ b/src/lib/data/protocols/ssh.ts @@ -8,7 +8,8 @@ export const ssh: Protocol = { port: 22, year: 1995, rfc: 'RFC 4253', - oneLiner: 'Encrypted remote access β€” how developers securely {{mqtt-connect|connect}} to servers.', + oneLiner: + 'Encrypted remote access β€” how developers securely {{mqtt-connect|connect}} to servers.', overview: `[[ssh|SSH]] replaced the insecure telnet and rlogin protocols by providing {{encryption|encrypted}} remote shell access. When you {{mqtt-connect|connect}} to a server, push code to GitHub, or tunnel a database connection, you're likely using [[ssh|SSH]]. [[ssh|SSH]] provides an encrypted tunnel between {{client-server|client and server}} that can carry interactive shell sessions, file transfers ({{scp-copy|SCP}}/{{sftp|SFTP}}), and {{port-forwarding|port forwarding}}. Authentication can use passwords, but the preferred method is {{public-key|public key}} authentication: your {{private-key|private key}} stays on your machine, and the server has your {{public-key|public key}} β€” no passwords transmitted over the network. diff --git a/src/lib/data/protocols/stomp.ts b/src/lib/data/protocols/stomp.ts index 8fc9eec..9bf8adb 100644 --- a/src/lib/data/protocols/stomp.ts +++ b/src/lib/data/protocols/stomp.ts @@ -8,7 +8,8 @@ export const stomp: Protocol = { port: 61613, year: 2003, rfc: undefined, - oneLiner: 'A dead-simple text protocol for message brokers β€” the {{http-method|HTTP}} of messaging.', + oneLiner: + 'A dead-simple text protocol for message brokers β€” the {{http-method|HTTP}} of messaging.', overview: `[[stomp|STOMP]] is to message queuing what [[http1|HTTP]] is to the web β€” a simple, text-based protocol that any language can implement easily. While [[amqp|AMQP]] has complex {{binary-framing|binary framing}} and [[mqtt|MQTT]] has its binary headers, [[stomp|STOMP]] uses plain text commands like {{mqtt-connect|CONNECT}}, {{mqtt-subscribe|SUBSCRIBE}}, SEND, and {{ack|ACK}}. This simplicity is [[stomp|STOMP]]'s superpower. You can literally telnet to a [[stomp|STOMP]] {{broker|broker}} and type messages by hand. It's supported by most major message brokers (RabbitMQ, ActiveMQ, Apollo) as an alternative to their native protocols, making it a great choice when you need messaging but don't want to learn a complex protocol. diff --git a/src/lib/data/protocols/tcp.ts b/src/lib/data/protocols/tcp.ts index 76008e7..a435c58 100644 --- a/src/lib/data/protocols/tcp.ts +++ b/src/lib/data/protocols/tcp.ts @@ -64,7 +64,8 @@ print(f"Connected by {addr}") data = conn.recv(1024) # Reliable, ordered delivery conn.sendall(b"Hello back!") conn.close() # FIN sequence`, - caption: 'A minimal [[tcp|TCP]] server β€” the 3-way {{handshake|handshake}} happens automatically inside accept()', + caption: + 'A minimal [[tcp|TCP]] server β€” the 3-way {{handshake|handshake}} happens automatically inside accept()', alternatives: [ { language: 'javascript', @@ -200,7 +201,10 @@ Client β†’ Server [ACK] title: 'Comcast launches L4S in production', description: 'Sub-millisecond queuing {{latency|latency}} for cooperating flows in six US metros, with {{apple|Apple}}, {{nvidia|NVIDIA}} GeForce NOW, {{meta|Meta}}, and Valve as launch partners. The first large-scale deployment of the {{l4s|L4S}} architecture ([[rfc:9330|RFC 9330]]/9331/9332) on a production access network.', - source: { url: 'https://www.rcrwireless.com/20250129/uncategorized/comcast-l4s', label: 'RCR Wireless' } + source: { + url: 'https://www.rcrwireless.com/20250129/uncategorized/comcast-l4s', + label: 'RCR Wireless' + } }, { date: '2025-06', @@ -232,13 +236,13 @@ Client β†’ Server [ACK] org: 'Google', scale: 'BBR for google.com / YouTube', description: - 'BBRv1 deployed in 2016, {{bbrv3|BBRv3}} has rolled out as the default since 2024. Replaces {{cubic|CUBIC}} for outbound traffic from {{google|Google}}\'s edge.' + "BBRv1 deployed in 2016, {{bbrv3|BBRv3}} has rolled out as the default since 2024. Replaces {{cubic|CUBIC}} for outbound traffic from {{google|Google}}'s edge." }, { org: 'Meta', scale: '>50% of traffic still TCP', description: - 'Despite >75% of {{meta|Meta}}\'s internet-facing traffic moving to [[quic|QUIC]], [[tcp|TCP]] remains the default for service-to-service inside the datacenter and for backwards-compatible client paths.' + "Despite >75% of {{meta|Meta}}'s internet-facing traffic moving to [[quic|QUIC]], [[tcp|TCP]] remains the default for service-to-service inside the datacenter and for backwards-compatible client paths." }, { org: 'Apple', @@ -251,11 +255,11 @@ Client β†’ Server [ACK] funFacts: [ { title: 'RFC 793 was the spec for 41 years', - text: 'From September 1981 until [[rfc:9293|RFC 9293]] (August 2022), [[pioneer:jon-postel|Jon Postel]]\'s [[rfc:9293|RFC 793]] was the canonical [[tcp|TCP]] specification β€” almost certainly the longest unmodified {{ietf|IETF}} spec ever. [[rfc:9293|RFC 9293]] finally consolidated 13 errata documents into a single readable document, edited by Wesley Eddy.' + text: "From September 1981 until [[rfc:9293|RFC 9293]] (August 2022), [[pioneer:jon-postel|Jon Postel]]'s [[rfc:9293|RFC 793]] was the canonical [[tcp|TCP]] specification β€” almost certainly the longest unmodified {{ietf|IETF}} spec ever. [[rfc:9293|RFC 9293]] finally consolidated 13 errata documents into a single readable document, edited by Wesley Eddy." }, { - title: 'TCP\'s sequence numbers used to be guessable', - text: 'Early [[tcp|TCP]] picked the initial {{sequence-number|sequence number}} from a counter incremented at a fixed rate per second. Kevin Mitnick used this in 1994 to forge a connection to Tsutomu Shimomura\'s host. Modern stacks use a cryptographically-random {{isn|ISN}} per [[rfc:9293|RFC 9293]] Β§3.4.1.' + title: "TCP's sequence numbers used to be guessable", + text: "Early [[tcp|TCP]] picked the initial {{sequence-number|sequence number}} from a counter incremented at a fixed rate per second. Kevin Mitnick used this in 1994 to forge a connection to Tsutomu Shimomura's host. Modern stacks use a cryptographically-random {{isn|ISN}} per [[rfc:9293|RFC 9293]] Β§3.4.1." }, { title: 'The window field is only 16 bits', @@ -271,7 +275,7 @@ Client β†’ Server [ACK] pitfalls: [ { title: 'Nagle + Delayed ACK = 200ms latency', - text: 'Nagle\'s algorithm coalesces small writes; {{delayed-ack|delayed ACK}} batches acknowledgements. When both are on (the default), interactive applications writing in small chunks can stall for up to 200 ms waiting for an {{ack|ACK}}. Cure: setsockopt(TCP_NODELAY, 1) for low-{{latency|latency}} apps.' + text: "Nagle's algorithm coalesces small writes; {{delayed-ack|delayed ACK}} batches acknowledgements. When both are on (the default), interactive applications writing in small chunks can stall for up to 200 ms waiting for an {{ack|ACK}}. Cure: setsockopt(TCP_NODELAY, 1) for low-{{latency|latency}} apps." }, { title: 'Ephemeral port exhaustion', diff --git a/src/lib/data/protocols/tls.ts b/src/lib/data/protocols/tls.ts index a6e7776..e7e3362 100644 --- a/src/lib/data/protocols/tls.ts +++ b/src/lib/data/protocols/tls.ts @@ -203,7 +203,10 @@ openssl req -x509 -newkey rsa:2048 -nodes \\ title: 'NIST finalises ML-KEM, ML-DSA, SLH-DSA', description: '{{fips|FIPS}} 203, 204, 205 published β€” the {{post-quantum|post-quantum cryptography}} primitives that [[tls|TLS]] would depend on. {{ml-kem|ML-KEM}}-768 (formerly Kyber-768) becomes the foundation for hybrid key {{exchange|exchange}}.', - source: { url: 'https://csrc.nist.gov/publications/detail/fips/203/final', label: 'NIST FIPS 203' } + source: { + url: 'https://csrc.nist.gov/publications/detail/fips/203/final', + label: 'NIST FIPS 203' + } }, { date: '2024-Q2', @@ -246,7 +249,7 @@ openssl req -x509 -newkey rsa:2048 -nodes \\ 'Hybrid post-quantum key agreement enabled by default. Falls back gracefully when servers do not support it.' }, { - org: 'Let\'s Encrypt', + org: "Let's Encrypt", scale: '~470M certificates active', description: 'The dominant {{certificate-authority|CA}} for the web. All certificates issued via ACME. ~3M certificates renewed daily.' @@ -256,7 +259,7 @@ openssl req -x509 -newkey rsa:2048 -nodes \\ funFacts: [ { title: 'SSL 1.0 was never released', - text: 'Netscape\'s [[pioneer:taher-elgamal|Taher Elgamal]] designed {{ssl|SSL}} 1.0 in 1994 β€” but a flaw was found before public release that let an attacker recover the session key. {{ssl|SSL}} 2.0 (1995) shipped instead. {{ssl|SSL}} 3.0 (1996) was rewritten from scratch by Paul Kocher and survived for over a decade.' + text: "Netscape's [[pioneer:taher-elgamal|Taher Elgamal]] designed {{ssl|SSL}} 1.0 in 1994 β€” but a flaw was found before public release that let an attacker recover the session key. {{ssl|SSL}} 2.0 (1995) shipped instead. {{ssl|SSL}} 3.0 (1996) was rewritten from scratch by Paul Kocher and survived for over a decade." }, { title: 'TLS 1.3 cut every weak cipher', @@ -280,7 +283,7 @@ openssl req -x509 -newkey rsa:2048 -nodes \\ }, { title: 'Mixed content breaks the padlock', - text: 'A page loaded over HTTPS that includes a single script over {{http-method|HTTP}} triggers the browser\'s mixed-content blocker. The page either fails to load assets or shows a warning. Cure: use protocol-relative URLs or strict HTTPS-only resources.' + text: "A page loaded over HTTPS that includes a single script over {{http-method|HTTP}} triggers the browser's mixed-content blocker. The page either fails to load assets or shows a warning. Cure: use protocol-relative URLs or strict HTTPS-only resources." } ] } diff --git a/src/lib/data/protocols/udp.ts b/src/lib/data/protocols/udp.ts index 7f868da..fd83f99 100644 --- a/src/lib/data/protocols/udp.ts +++ b/src/lib/data/protocols/udp.ts @@ -57,7 +57,8 @@ sock.sendto(b"Ping!", ('localhost', 8888)) # Receive β€” might never arrive data, addr = sock.recvfrom(1024) print(f"Got {data} from {addr}")`, - caption: '[[udp|UDP]] is {{connectionless|connectionless}} β€” just bind, send, and hope for the best', + caption: + '[[udp|UDP]] is {{connectionless|connectionless}} β€” just bind, send, and hope for the best', alternatives: [ { language: 'javascript', @@ -142,7 +143,21 @@ ss -un # or: netstat -un` throughput: 'No congestion control β€” can send as fast as the network allows (or can handle)', overhead: '8-byte header only β€” the minimum possible for transport' }, - connections: ['tcp', 'ip', 'ipv6', 'dns', 'quic', 'webrtc', 'dhcp', 'ntp', 'rtp', 'coap', 'sip', 'ipsec', 'nat-traversal'], + connections: [ + 'tcp', + 'ip', + 'ipv6', + 'dns', + 'quic', + 'webrtc', + 'dhcp', + 'ntp', + 'rtp', + 'coap', + 'sip', + 'ipsec', + 'nat-traversal' + ], links: { wikipedia: 'https://en.wikipedia.org/wiki/User_Datagram_Protocol', rfc: 'https://datatracker.ietf.org/doc/html/rfc768' @@ -181,7 +196,7 @@ ss -un # or: netstat -un` org: 'NTP pool', scale: '~25 billion queries/day', description: - 'pool.ntp.org and friends serve tens of billions of [[udp|UDP]] [[ntp|NTP]] queries per day, keeping the world\'s clocks within a few milliseconds.' + "pool.ntp.org and friends serve tens of billions of [[udp|UDP]] [[ntp|NTP]] queries per day, keeping the world's clocks within a few milliseconds." }, { org: 'WebRTC media', @@ -200,11 +215,11 @@ ss -un # or: netstat -un` funFacts: [ { title: 'RFC 768 is three pages long', - text: '[[udp|UDP]]\'s entire spec β€” header format, length field, {{checksum|checksum}}, and a paragraph of prose β€” fits in three pages. [[pioneer:jon-postel|Jon Postel]] wrote it in August 1980. It has not been updated since. There has been nothing to {{bgp-update|update}}.' + text: "[[udp|UDP]]'s entire spec β€” header format, length field, {{checksum|checksum}}, and a paragraph of prose β€” fits in three pages. [[pioneer:jon-postel|Jon Postel]] wrote it in August 1980. It has not been updated since. There has been nothing to {{bgp-update|update}}." }, { title: 'UDP gives you ports β€” that is most of L4', - text: 'The only thing [[udp|UDP]] adds above raw [[ip|IP]] is the source/destination port pair. That is the entire reason multiple applications can share a host\'s network adapter. Everything else (reliability, ordering, congestion) is left to the application above.' + text: "The only thing [[udp|UDP]] adds above raw [[ip|IP]] is the source/destination port pair. That is the entire reason multiple applications can share a host's network adapter. Everything else (reliability, ordering, congestion) is left to the application above." }, { title: 'UDP is what middleboxes already pass', diff --git a/src/lib/data/protocols/uwb.ts b/src/lib/data/protocols/uwb.ts index e2ad9d1..b9a4d72 100644 --- a/src/lib/data/protocols/uwb.ts +++ b/src/lib/data/protocols/uwb.ts @@ -19,7 +19,7 @@ The reason UWB matters more than its raw precision is that it can **prove proxim { title: 'Impulse-radio physical layer β€” Gaussian monocycles, not a carrier', description: - "Instead of modulating a continuous carrier, **IR-UWB** transmits sub-nanosecond Gaussian-monocycle (or doublet) pulses spaced across the available {{spectrum|spectrum}}. A symbol is built from a burst of pulses at one of two time-slot positions (BPM) with chosen polarity ({{bpsk|BPSK}}) β€” *Burst-Position Modulation + Binary Phase-Shift Keying*. The mean pulse-repetition frequency is **{{bprf|BPRF}} β‰ˆ 64 MHz** in the default 802.15.4z mode or **HPRF 124.8 / 249.6 MHz** in higher-power modes. Data rates: 850 kbps, 6.81 Mbps, or 27 Mbps β€” most ranging deployments use **6.81 Mbps** because shorter {{frame|frame}} air-time reduces clock-drift error. The 499.2 MHz channel {{bandwidth|bandwidth}} and the β‰₯0.2 fractional-{{bandwidth|bandwidth}} requirement is what makes a UWB transmitter *legally UWB* under {{fcc|FCC}} Part 15.519." + 'Instead of modulating a continuous carrier, **IR-UWB** transmits sub-nanosecond Gaussian-monocycle (or doublet) pulses spaced across the available {{spectrum|spectrum}}. A symbol is built from a burst of pulses at one of two time-slot positions (BPM) with chosen polarity ({{bpsk|BPSK}}) β€” *Burst-Position Modulation + Binary Phase-Shift Keying*. The mean pulse-repetition frequency is **{{bprf|BPRF}} β‰ˆ 64 MHz** in the default 802.15.4z mode or **HPRF 124.8 / 249.6 MHz** in higher-power modes. Data rates: 850 kbps, 6.81 Mbps, or 27 Mbps β€” most ranging deployments use **6.81 Mbps** because shorter {{frame|frame}} air-time reduces clock-drift error. The 499.2 MHz channel {{bandwidth|bandwidth}} and the β‰₯0.2 fractional-{{bandwidth|bandwidth}} requirement is what makes a UWB transmitter *legally UWB* under {{fcc|FCC}} Part 15.519.' }, { title: 'The four ranging paradigms β€” TWR, DS-TWR, TDoA, AoA', @@ -29,7 +29,7 @@ The reason UWB matters more than its raw precision is that it can **prove proxim { title: 'STS β€” Scrambled Timestamp Sequence, the cryptographic distance bound', description: - "The vulnerability that 802.15.4a (2007) shipped with: its preamble and {{sfd|SFD}} patterns are public, so an attacker can predict the next pulse and inject an early replica that the receiver locks onto, shortening apparent distance β€” the *Cicada* / *Early-Detect / Late-Commit* family. **{{sts|STS}} in 802.15.4z** replaces the predictable preamble-derived timestamp with a 32–2048-chip pulse sequence whose positions are generated by **{{aes-128|AES-128}} in {{aead|Counter mode}}** keyed by a per-session STS_KEY and a per-frame {{nonce|nonce}}. An attacker without the key sees noise; they cannot predict the next chip and cannot reliably early-replay. The receiver, holding the same key, generates the expected sequence locally and cross-correlates β€” sharp autocorrelation peak with a fresh code every frame. This is the **distance commitment** that defeats the {{ble|BLE}}-{{rssi|RSSI}} {{replay-attack|relay}} class of attack." + 'The vulnerability that 802.15.4a (2007) shipped with: its preamble and {{sfd|SFD}} patterns are public, so an attacker can predict the next pulse and inject an early replica that the receiver locks onto, shortening apparent distance β€” the *Cicada* / *Early-Detect / Late-Commit* family. **{{sts|STS}} in 802.15.4z** replaces the predictable preamble-derived timestamp with a 32–2048-chip pulse sequence whose positions are generated by **{{aes-128|AES-128}} in {{aead|Counter mode}}** keyed by a per-session STS_KEY and a per-frame {{nonce|nonce}}. An attacker without the key sees noise; they cannot predict the next chip and cannot reliably early-replay. The receiver, holding the same key, generates the expected sequence locally and cross-correlates β€” sharp autocorrelation peak with a fresh code every frame. This is the **distance commitment** that defeats the {{ble|BLE}}-{{rssi|RSSI}} {{replay-attack|relay}} class of attack.' }, { title: 'BLE bootstraps every UWB session β€” the indispensable on-ramp', @@ -44,7 +44,7 @@ The reason UWB matters more than its raw precision is that it can **prove proxim { title: 'The competition β€” Wi-Fi FTM (802.11mc/11az) and the honest verdict', description: - "**[[wifi|Wi-Fi]] Fine Timing Measurement ({{ftm|FTM}})** in {{ieee-802-15-4|IEEE}} 802.11mc and the security-enhanced **802.11az** is the closest analogue to UWB ranging in mass-market silicon. *Native silicon:* Wi-Fi is already in every phone vs. a dedicated UWB chip. *{{bandwidth|Bandwidth}}:* Wi-Fi 80–160 MHz vs. UWB 499.2 MHz. *Accuracy:* Wi-Fi 1–2 m typical vs. UWB 10–30 cm. *Secure ranging:* Wi-Fi 11az TB/NTB with PASN vs. UWB {{sts|STS}}. *Infrastructure:* Wi-Fi reuses existing APs ({{cisco|Cisco}}/Aruba support) vs. dedicated UWB anchors. **Honest verdict:** FTM is *good enough* for room-level indoor positioning; **UWB wins for proximity-based authentication** (car keys, smart locks) because cm-precision *and* the {{sts|STS}} distance commitment combine to produce a hard distance upper-bound that FTM cannot match today. 802.11az narrows the gap. They will most likely coexist." + '**[[wifi|Wi-Fi]] Fine Timing Measurement ({{ftm|FTM}})** in {{ieee-802-15-4|IEEE}} 802.11mc and the security-enhanced **802.11az** is the closest analogue to UWB ranging in mass-market silicon. *Native silicon:* Wi-Fi is already in every phone vs. a dedicated UWB chip. *{{bandwidth|Bandwidth}}:* Wi-Fi 80–160 MHz vs. UWB 499.2 MHz. *Accuracy:* Wi-Fi 1–2 m typical vs. UWB 10–30 cm. *Secure ranging:* Wi-Fi 11az TB/NTB with PASN vs. UWB {{sts|STS}}. *Infrastructure:* Wi-Fi reuses existing APs ({{cisco|Cisco}}/Aruba support) vs. dedicated UWB anchors. **Honest verdict:** FTM is *good enough* for room-level indoor positioning; **UWB wins for proximity-based authentication** (car keys, smart locks) because cm-precision *and* the {{sts|STS}} distance commitment combine to produce a hard distance upper-bound that FTM cannot match today. 802.11az narrows the gap. They will most likely coexist.' }, { title: 'Regional masks β€” design for the strictest you must support', @@ -332,7 +332,7 @@ Continuous Precision Finding refreshes at ~10 Hz on Apple silicon.` date: '2025-07', title: 'CCC Digital Key 4.0 announced β€” cross-platform key sharing', description: - "The **Car Connectivity Consortium** announced Digital Key 4.0 in July 2025 and validated it at the **13th Plugfest hosted by {{apple|Apple}}**. Adds **device-to-device key sharing across {{android|Android}} and iOS**, validates backward compatibility with 3.0 vehicles, and keeps the requirement that devices support at least one of [[nfc|NFC]], {{ble|BLE}}, or UWB. {{hrp-uwb|HRP}} UWB under 802.15.4z remains the secure default. **115 vehicle/module products** were certified across 2025 alone; BMW (first cert late 2024), Mercedes, Hyundai/Kia, Audi (new for 2025), VW, Porsche, GM, Ford, and Chinese OEMs (NIO, XPENG, Geely brands).", + 'The **Car Connectivity Consortium** announced Digital Key 4.0 in July 2025 and validated it at the **13th Plugfest hosted by {{apple|Apple}}**. Adds **device-to-device key sharing across {{android|Android}} and iOS**, validates backward compatibility with 3.0 vehicles, and keeps the requirement that devices support at least one of [[nfc|NFC]], {{ble|BLE}}, or UWB. {{hrp-uwb|HRP}} UWB under 802.15.4z remains the secure default. **115 vehicle/module products** were certified across 2025 alone; BMW (first cert late 2024), Mercedes, Hyundai/Kia, Audi (new for 2025), VW, Porsche, GM, Ford, and Chinese OEMs (NIO, XPENG, Geely brands).', source: { url: 'https://carconnectivity.org/', label: 'Car Connectivity Consortium' @@ -342,7 +342,7 @@ Continuous Precision Finding refreshes at ~10 Hz on Apple silicon.` date: '2026-02', title: 'Aliro 1.0 finalised β€” "Matter for door locks" with UWB', description: - "On **26 February 2026** the {{sig-bluetooth-acronym|CSA}} published **{{aliro|Aliro 1.0}}**, a {{pki|PKI}}-based access-control credential standard with **[[nfc|NFC]] (tap) + {{ble|BLE}} (proximity) + {{ble|BLE}}+UWB (ranged, hands-free)** as its three transports. {{ecdsa|ECDSA}} mutual authentication; credentials provisioned into {{apple|Apple}}, {{google|Google}}, and Samsung wallets. First products: **Aqara U400** (first smart lock with UWB; {{aliro|Aliro}} coming via firmware {{bgp-update|update}}) and **Kwikset Halo {{imap-select|Select}} Plus**. Launch partners include {{apple|Apple}}, {{google|Google}}, Samsung, ASSA ABLOY, {{nxp|NXP}}, Infineon, STMicroelectronics, Silicon Labs, Nordic Semiconductor, plus smart-lock makers Schlage, Avia, Nuki, Xthings. {{aliro|Aliro}} generalises the {{apple|Apple}} Home Key {{ux|UX}} across {{android|Android}} β€” the most consequential UWB-related deployment of 2026.", + 'On **26 February 2026** the {{sig-bluetooth-acronym|CSA}} published **{{aliro|Aliro 1.0}}**, a {{pki|PKI}}-based access-control credential standard with **[[nfc|NFC]] (tap) + {{ble|BLE}} (proximity) + {{ble|BLE}}+UWB (ranged, hands-free)** as its three transports. {{ecdsa|ECDSA}} mutual authentication; credentials provisioned into {{apple|Apple}}, {{google|Google}}, and Samsung wallets. First products: **Aqara U400** (first smart lock with UWB; {{aliro|Aliro}} coming via firmware {{bgp-update|update}}) and **Kwikset Halo {{imap-select|Select}} Plus**. Launch partners include {{apple|Apple}}, {{google|Google}}, Samsung, ASSA ABLOY, {{nxp|NXP}}, Infineon, STMicroelectronics, Silicon Labs, Nordic Semiconductor, plus smart-lock makers Schlage, Avia, Nuki, Xthings. {{aliro|Aliro}} generalises the {{apple|Apple}} Home Key {{ux|UX}} across {{android|Android}} β€” the most consequential UWB-related deployment of 2026.', source: { url: 'https://csa-iot.org/all-solutions/aliro/', label: 'CSA: Aliro 1.0' @@ -353,27 +353,30 @@ Continuous Precision Finding refreshes at ~10 Hz on Apple silicon.` realWorldDeployments: [ { org: 'Apple AirTag', - scale: 'Tens of millions of units annually 2022–2025 (Apple does not publish official figures)', + scale: + 'Tens of millions of units annually 2022–2025 (Apple does not publish official figures)', description: "Launched **30 April 2021** at $29 single / $99 four-pack. {{ble|BLE}} for the Find My network {{ping|ping}} + {{u1-chip|U1}} UWB for the cm-class Precision Finding when you are within ~5 m. The Find My network of approaching ~1 billion participating {{apple|Apple}} devices is the world's largest crowdsourced locator. AirTag is, per {{apple|Apple}}'s own marketing, the best-selling item tracker on Earth. The second-generation AirTag shipped **January 2026** with {{u2-chip|U2}}, 1.5Γ— longer Precision Finding range, a louder and harder-to-remove speaker (hardware anti-stalking), and {{apple|Apple}} Watch Series 9+ Precision Finding support." }, { org: 'BMW Digital Key Plus', - scale: 'First production CCC Digital Key 3.0 UWB vehicle; available on iX, i7, X5/X6/X7, 7 Series, 5 Series, MINI Countryman', + scale: + 'First production CCC Digital Key 3.0 UWB vehicle; available on iX, i7, X5/X6/X7, 7 Series, 5 Series, MINI Countryman', description: - "Announced **13 January 2021**; customer rollout from early 2022. **First production {{ccc-digital-key|CCC Digital Key}} 3.0 UWB vehicle**. BMW jointly developed the spec with {{apple|Apple}} and the {{ccc-digital-key|CCC}}. BMW Group was the first {{oem|OEM}} to receive {{ccc-digital-key|CCC Digital Key}} Certification for its UWB-based digital vehicle access. The {{ux|UX}}: walk up to the car, the doors unlock as you reach the handle ({{ble|BLE}} detects you, UWB confirms which side of the door you are on); inside, set the phone down anywhere and start the car (no key-fob ritual)." + 'Announced **13 January 2021**; customer rollout from early 2022. **First production {{ccc-digital-key|CCC Digital Key}} 3.0 UWB vehicle**. BMW jointly developed the spec with {{apple|Apple}} and the {{ccc-digital-key|CCC}}. BMW Group was the first {{oem|OEM}} to receive {{ccc-digital-key|CCC Digital Key}} Certification for its UWB-based digital vehicle access. The {{ux|UX}}: walk up to the car, the doors unlock as you reach the handle ({{ble|BLE}} detects you, UWB confirms which side of the door you are on); inside, set the phone down anywhere and start the car (no key-fob ritual).' }, { org: 'Mercedes-Benz EQS / S-Class', scale: 'NFC+UWB CCC Digital Key 3.0 across the flagship lineup', description: - "Mercedes-Benz partnered with {{apple|Apple}} on the Wallet-based Digital Key for the EQS and S-Class from 2022. **{{nxp|NXP}} SR1xx** silicon family in the vehicle anchors. The Mercedes Digital Key was one of the first deployed cases of an NFC-fallback + UWB-precision unlock β€” battery-dead phones still get in via [[nfc|NFC]] tap; otherwise UWB walk-up authentication takes over." + 'Mercedes-Benz partnered with {{apple|Apple}} on the Wallet-based Digital Key for the EQS and S-Class from 2022. **{{nxp|NXP}} SR1xx** silicon family in the vehicle anchors. The Mercedes Digital Key was one of the first deployed cases of an NFC-fallback + UWB-precision unlock β€” battery-dead phones still get in via [[nfc|NFC]] tap; otherwise UWB walk-up authentication takes over.' }, { org: 'Aqara U400 + Apple Home Key + Aliro', - scale: 'First smart lock shipped with UWB support (2025); Aliro 1.0 firmware update post-CES 2026', + scale: + 'First smart lock shipped with UWB support (2025); Aliro 1.0 firmware update post-CES 2026', description: - "**Aqara U400** is the first commercial smart lock to ship with UWB. Initially {{apple|Apple}}-Home-Key-only β€” meaning the experience worked only for iPhone owners. With **{{aliro|Aliro}} 1.0** ({{sig-bluetooth-acronym|CSA}}, 26 February 2026) coming via firmware {{bgp-update|update}} β€” announced at {{ces-show|CES}} 2026 β€” the same lock will work hands-free with {{android|Android}}, Samsung, and any {{aliro|Aliro}}-compliant wallet. The {{apple|Apple}} Home Key experience (tap or walk up; door unlocks if your iPhone is the authenticated bearer) is what {{aliro|Aliro}} generalises across vendors." + '**Aqara U400** is the first commercial smart lock to ship with UWB. Initially {{apple|Apple}}-Home-Key-only β€” meaning the experience worked only for iPhone owners. With **{{aliro|Aliro}} 1.0** ({{sig-bluetooth-acronym|CSA}}, 26 February 2026) coming via firmware {{bgp-update|update}} β€” announced at {{ces-show|CES}} 2026 β€” the same lock will work hands-free with {{android|Android}}, Samsung, and any {{aliro|Aliro}}-compliant wallet. The {{apple|Apple}} Home Key experience (tap or walk up; door unlocks if your iPhone is the authenticated bearer) is what {{aliro|Aliro}} generalises across vendors.' }, { org: 'Samsung Galaxy SmartTag+ + Galaxy S21+ family', @@ -383,26 +386,28 @@ Continuous Precision Finding refreshes at ~10 Hz on Apple silicon.` }, { org: 'Industrial / hospital RTLS β€” Sonitor, Zebra, Apex Locate', - scale: 'TDoA anchor deployments; typical anchor density 1 per ~20–30 mΒ² for cm-class accuracy', + scale: + 'TDoA anchor deployments; typical anchor density 1 per ~20–30 mΒ² for cm-class accuracy', description: "**Sonitor** runs clinical-grade hospital asset tracking (patients, equipment, surgical instruments). **Zebra Technologies** runs warehouse forklift and pallet tracking at high anchor density. **Apex Locate** focuses on manufacturing. These are TDoA-anchor deployments (multiple time-synchronised receivers measure the time difference of arrival of a single tag's pulse) rather than {{peer-to-peer|peer-to-peer}} ranging β€” anchors {{mqtt-connect|connect}} over wired [[ethernet|Ethernet]] with PTP-grade clock distribution. **{{cisco|Cisco}} partnered with Sewio in October 2019** to integrate UWB into wireless access points, but the strategy has been slow to mature." }, { org: 'UWB-equipped iPhone install base', - scale: '>1 B iPhones from iPhone 11 (Sep 2019) onward; ABI projects 27 % β†’ 52 % UWB phone penetration 2025–2030', + scale: + '>1 B iPhones from iPhone 11 (Sep 2019) onward; ABI projects 27 % β†’ 52 % UWB phone penetration 2025–2030', description: - "{{apple|Apple}} shipped >1 billion iPhones from the iPhone 11 (10 September 2019) onward by mid-decade. Not every iPhone has UWB β€” **iPhone {{se-secure-element|SE}} 1/2/3, iPhone 16e, and iPhone 17e** do not include a UWB chip β€” but the FiRa-compatible UWB device install base is the largest of any UWB ecosystem worldwide, dwarfing the Samsung Galaxy UWB-flagship base. The {{u1-chip|U1}} cohort spans iPhone 11 through iPhone 14, AirTag (1st gen), HomePod mini, {{apple|Apple}} Watch Series 6+, and the AirPods Pro 2 case. The {{u2-chip|U2}} cohort: iPhone 15/16/17 (excluding 16e/17e), AirTag 2." + '{{apple|Apple}} shipped >1 billion iPhones from the iPhone 11 (10 September 2019) onward by mid-decade. Not every iPhone has UWB β€” **iPhone {{se-secure-element|SE}} 1/2/3, iPhone 16e, and iPhone 17e** do not include a UWB chip β€” but the FiRa-compatible UWB device install base is the largest of any UWB ecosystem worldwide, dwarfing the Samsung Galaxy UWB-flagship base. The {{u1-chip|U1}} cohort spans iPhone 11 through iPhone 14, AirTag (1st gen), HomePod mini, {{apple|Apple}} Watch Series 6+, and the AirPods Pro 2 case. The {{u2-chip|U2}} cohort: iPhone 15/16/17 (excluding 16e/17e), AirTag 2.' } ], funFacts: [ { - title: 'The FCC adopted UWB regulations on Valentine\'s Day, 14 February 2002', - text: "The First Report and Order in ET Docket 98-153 (**{{fcc|FCC}} 02-48**, 17 {{fcc|FCC}} Rcd 7435), adopted **14 February 2002**, released **22 April 2002**, effective **15 July 2002**, was hard-won against {{gps|GPS}} (operating at L1=1575.42 MHz), avionics, and DoD interests who feared aggregate interference into safety-of-life systems. The **βˆ’41.3 dBm/MHz** EIRP limit is essentially the Β§15.209 background-unintentional-radiator threshold β€” UWB devices may not emit *more than ordinary unintentional radiators do*, despite being intentional transmitters." + title: "The FCC adopted UWB regulations on Valentine's Day, 14 February 2002", + text: 'The First Report and Order in ET Docket 98-153 (**{{fcc|FCC}} 02-48**, 17 {{fcc|FCC}} Rcd 7435), adopted **14 February 2002**, released **22 April 2002**, effective **15 July 2002**, was hard-won against {{gps|GPS}} (operating at L1=1575.42 MHz), avionics, and DoD interests who feared aggregate interference into safety-of-life systems. The **βˆ’41.3 dBm/MHz** EIRP limit is essentially the Β§15.209 background-unintentional-radiator threshold β€” UWB devices may not emit *more than ordinary unintentional radiators do*, despite being intentional transmitters.' }, { title: 'IEEE 802.15.3a is one of the most public failures of an IEEE 802 task group', - text: "After three years of deadlock between **MB-OFDM** ({{intel|Intel}} + WiMedia Alliance) and **DS-UWB** (Freescale + UWB Forum), neither side could win the 75 % supermajority required to ratify. At the Waikoloa, HI interim on **19 January 2006** the task group voted to **recommend its own dissolution**. The joint UWB Forum / WiMedia Alliance statement that *a more prudent course of action is necessary* became a textbook example of standards-body coalition deadlock. WiMedia formally dissolved in 2009, transferring its specs to {{usb|USB}}-IF, Bluetooth {{sig|SIG}}, and the Wireless {{usb|USB}} Promoter Group. What did not die: the 802.15.4a impulse-radio side that became 4z, became FiRa, became every {{u1-chip|U1}}-equipped iPhone." + text: 'After three years of deadlock between **MB-OFDM** ({{intel|Intel}} + WiMedia Alliance) and **DS-UWB** (Freescale + UWB Forum), neither side could win the 75 % supermajority required to ratify. At the Waikoloa, HI interim on **19 January 2006** the task group voted to **recommend its own dissolution**. The joint UWB Forum / WiMedia Alliance statement that *a more prudent course of action is necessary* became a textbook example of standards-body coalition deadlock. WiMedia formally dissolved in 2009, transferring its specs to {{usb|USB}}-IF, Bluetooth {{sig|SIG}}, and the Wireless {{usb|USB}} Promoter Group. What did not die: the 802.15.4a impulse-radio side that became 4z, became FiRa, became every {{u1-chip|U1}}-equipped iPhone.' }, { title: 'The "U" in Apple\'s U1 / U2 stands for Ultra-Wideband', @@ -414,7 +419,7 @@ Continuous Precision Finding refreshes at ~10 Hz on Apple silicon.` }, { title: 'Apple silicon engineers published their security response on arXiv', - text: "**Secure Ranging with {{ieee-802-15-4|IEEE}} 802.15.4z {{hrp-uwb|HRP}} UWB** (Luo, Kalkanli, Zhou, Zhan, Cohen β€” arXiv:2312.03964, December 2023) is a rare instance of {{apple|Apple}} silicon engineers publishing a {{peer|peer}}-reviewable response to academic security research β€” specifically the Singh / Leu / Capkun lineage from ETH Zurich. The paper specifies an {{sts|STS}} receiver design and proves its security and asymptotic optimality under the documented attack model. The cultural significance is almost as large as the technical: {{apple|Apple}} does not normally {{mqtt-publish|publish}} protocol-level threat analysis, and the act of doing so signalled that UWB security was sufficiently competitive to require open {{exchange|exchange}} with academia." + text: '**Secure Ranging with {{ieee-802-15-4|IEEE}} 802.15.4z {{hrp-uwb|HRP}} UWB** (Luo, Kalkanli, Zhou, Zhan, Cohen β€” arXiv:2312.03964, December 2023) is a rare instance of {{apple|Apple}} silicon engineers publishing a {{peer|peer}}-reviewable response to academic security research β€” specifically the Singh / Leu / Capkun lineage from ETH Zurich. The paper specifies an {{sts|STS}} receiver design and proves its security and asymptotic optimality under the documented attack model. The cultural significance is almost as large as the technical: {{apple|Apple}} does not normally {{mqtt-publish|publish}} protocol-level threat analysis, and the act of doing so signalled that UWB security was sufficiently competitive to require open {{exchange|exchange}} with academia.' }, { title: 'FiRa stands for "Fine Ranging"', @@ -422,7 +427,7 @@ Continuous Precision Finding refreshes at ~10 Hz on Apple silicon.` }, { title: 'The iPhone 16e and 17e do not have UWB', - text: "{{apple|Apple}} removed UWB from the *e* line-up as a cost-down. This creates an awkward {{fragmentation|fragmentation}}: **Precision Finding for AirTag works on iPhone 11–17, except the 16e and 17e** (and the pre-iPhone-11 {{se-secure-element|SE}} models). Anti-stalking unwanted-tracker detection still works via {{ble|BLE}} on every iPhone. If you are scoping a UWB feature for an iOS app in 2026, gating on `NISession.isSupported` rather than assuming *modern iPhone implies UWB* will save you a support ticket later." + text: '{{apple|Apple}} removed UWB from the *e* line-up as a cost-down. This creates an awkward {{fragmentation|fragmentation}}: **Precision Finding for AirTag works on iPhone 11–17, except the 16e and 17e** (and the pre-iPhone-11 {{se-secure-element|SE}} models). Anti-stalking unwanted-tracker detection still works via {{ble|BLE}} on every iPhone. If you are scoping a UWB feature for an iOS app in 2026, gating on `NISession.isSupported` rather than assuming *modern iPhone implies UWB* will save you a support ticket later.' } ], @@ -430,7 +435,7 @@ Continuous Precision Finding refreshes at ~10 Hz on Apple silicon.` pitfalls: [ { title: 'Channel choice β€” start with Channel 5, plan for Channel 9', - text: "UWB has 16 {{hrp-uwb|HRP}} channels but only **two see real-world use**: Channel 5 (6489.6 MHz) and Channel 9 (7987.2 MHz), each 499.2 MHz wide. Older silicon ({{qorvo|Qorvo}} DW1000) supports only Channel 5; everything from DW3000 / {{nxp|NXP}} SR150 / {{apple|Apple}} {{u1-chip|U1}} onwards supports both. Japanese regulations restrict 7.25–7.75 GHz, which **clips Channel 9 in Japan**. For interoperability fallback, support Channel 5 β€” it works everywhere. For isolation from 6 GHz Wi-Fi 6E (which is squeezing the 5.925–7.125 GHz band increasingly hard), **prefer Channel 9 where regulation allows and fall back to Channel 5 in Japan and a few other jurisdictions**. {{ccc-digital-key|CCC Digital Key}} 3.0 mandates both. Verify against {{etsi|ETSI}} EN 302 065 (EU) and Japanese radio law before launch." + text: 'UWB has 16 {{hrp-uwb|HRP}} channels but only **two see real-world use**: Channel 5 (6489.6 MHz) and Channel 9 (7987.2 MHz), each 499.2 MHz wide. Older silicon ({{qorvo|Qorvo}} DW1000) supports only Channel 5; everything from DW3000 / {{nxp|NXP}} SR150 / {{apple|Apple}} {{u1-chip|U1}} onwards supports both. Japanese regulations restrict 7.25–7.75 GHz, which **clips Channel 9 in Japan**. For interoperability fallback, support Channel 5 β€” it works everywhere. For isolation from 6 GHz Wi-Fi 6E (which is squeezing the 5.925–7.125 GHz band increasingly hard), **prefer Channel 9 where regulation allows and fall back to Channel 5 in Japan and a few other jurisdictions**. {{ccc-digital-key|CCC Digital Key}} 3.0 mandates both. Verify against {{etsi|ETSI}} EN 302 065 (EU) and Japanese radio law before launch.' }, { title: 'STS / cipher suite β€” turn it on, and watch the receiver', @@ -446,7 +451,7 @@ Continuous Precision Finding refreshes at ~10 Hz on Apple silicon.` }, { title: 'Line-of-sight is everything; NLOS gives you positive distance bias', - text: "UWB resolves {{multipath|multipath}} at ~1 ns = 30 cm, but in **non-line-of-sight (NLOS)** conditions through walls/people/metal, the first path may be heavily attenuated and the receiver locks onto a later, stronger reflection. Result: a **positive distance bias of 10s of cm to a metre**. Use first-path detection algorithms rather than peak-detection β€” modern chips expose first-path index and confidence metrics. Apply NLOS bias correction using channel-impulse-response (CIR) features; recent Adaptive Kalman Filter work shows 30–50 % accuracy improvement. Place infrastructure anchors to maximise LOS to the working volume; ceiling mounts are typical in warehouse/hospital RTLS." + text: 'UWB resolves {{multipath|multipath}} at ~1 ns = 30 cm, but in **non-line-of-sight (NLOS)** conditions through walls/people/metal, the first path may be heavily attenuated and the receiver locks onto a later, stronger reflection. Result: a **positive distance bias of 10s of cm to a metre**. Use first-path detection algorithms rather than peak-detection β€” modern chips expose first-path index and confidence metrics. Apply NLOS bias correction using channel-impulse-response (CIR) features; recent Adaptive Kalman Filter work shows 30–50 % accuracy improvement. Place infrastructure anchors to maximise LOS to the working volume; ceiling mounts are typical in warehouse/hospital RTLS.' }, { title: 'Power consumption β€” UWB ranging is not cheap', diff --git a/src/lib/data/protocols/webrtc.ts b/src/lib/data/protocols/webrtc.ts index 394a11b..1615253 100644 --- a/src/lib/data/protocols/webrtc.ts +++ b/src/lib/data/protocols/webrtc.ts @@ -8,7 +8,8 @@ export const webrtc: Protocol = { port: undefined, year: 2011, rfc: 'RFC 8825', - oneLiner: '{{peer-to-peer|Peer-to-peer}} audio, video, and data β€” directly between browsers, no plugins needed.', + oneLiner: + '{{peer-to-peer|Peer-to-peer}} audio, video, and data β€” directly between browsers, no plugins needed.', overview: `[[webrtc|WebRTC]] is the technology that makes browser-based video calls possible. Before [[webrtc|WebRTC]], real-time communication required plugins (Flash, Java applets) or native apps. Now, two browsers can establish a direct, encrypted, {{peer-to-peer|peer-to-peer}} connection for audio, video, and arbitrary data. The key insight is "{{peer-to-peer|peer-to-peer}}" β€” once the connection is established, data flows directly between users without passing through a server. This reduces {{latency|latency}} and server costs. However, establishing that connection requires a {{signaling|signaling server}} (to {{exchange|exchange}} connection offers) and the [[nat-traversal|STUN / TURN / ICE]] stack to navigate {{nat|NATs}} and {{firewall|firewalls}}. **{{stun|STUN}}** discovers the {{peer|peer}}'s {{public-ip-address|public IP address}}; **{{turn|TURN}}** relays media through a server when a direct connection fails (about 10–15% of cases); **{{ice|ICE}}** coordinates both to find the best working path. See the [[nat-traversal|NAT-traversal]] page for the full wire format and history. diff --git a/src/lib/data/protocols/websockets.ts b/src/lib/data/protocols/websockets.ts index 1c44807..071b267 100644 --- a/src/lib/data/protocols/websockets.ts +++ b/src/lib/data/protocols/websockets.ts @@ -8,7 +8,8 @@ export const websockets: Protocol = { port: 80, year: 2011, rfc: 'RFC 6455', - oneLiner: '{{full-duplex|Full-duplex}}, persistent connection β€” server and client talk freely in real time.', + oneLiner: + '{{full-duplex|Full-duplex}}, persistent connection β€” server and client talk freely in real time.', overview: `[[websockets|WebSockets]] solve a fundamental limitation of [[http1|HTTP]]: the server can't initiate communication. In [[http1|HTTP]], the client always asks and the server always responds. [[websockets|WebSockets]] upgrade an [[http1|HTTP]] connection into a persistent, {{full-duplex|full-duplex}} channel where either side can send messages at any time. This is perfect for real-time applications: chat, live sports scores, collaborative editing, multiplayer games, financial tickers. Instead of the client repeatedly polling "any updates?" (wasteful), the server simply pushes data when it's available. Unlike [[http1|HTTP]]'s {{request-response|request-response}} model, [[websockets|WebSockets]] maintain a {{stateful|stateful}} connection where both sides can track context across messages without re-establishing identity on every {{exchange|exchange}}. @@ -57,7 +58,8 @@ async def chat(): await ws.send('{"type": "msg", "text": "Hello!"}') asyncio.run(chat())`, - caption: '[[websockets|WebSocket]] {{api|API}} is dead simple β€” {{mqtt-connect|connect}}, send, receive. Both sides can initiate.', + caption: + '[[websockets|WebSocket]] {{api|API}} is dead simple β€” {{mqtt-connect|connect}}, send, receive. Both sides can initiate.', alternatives: [ { language: 'javascript', diff --git a/src/lib/data/protocols/wireguard.ts b/src/lib/data/protocols/wireguard.ts index a14c4d5..6fc1c7e 100644 --- a/src/lib/data/protocols/wireguard.ts +++ b/src/lib/data/protocols/wireguard.ts @@ -90,7 +90,8 @@ sudo wg show # latest handshake: 23 seconds ago # transfer: 142.3 KiB received, 89.7 KiB sent # persistent keepalive: every 25 seconds`, - caption: 'A complete [[wireguard|WireGuard]] tunnel in 12 lines of config. Same on {{linux|Linux}}, {{bsd|BSD}}, macOS, {{android|Android}}, Windows. The simplicity is the feature.', + caption: + 'A complete [[wireguard|WireGuard]] tunnel in 12 lines of config. Same on {{linux|Linux}}, {{bsd|BSD}}, macOS, {{android|Android}}, Windows. The simplicity is the feature.', alternatives: [ { language: 'python', @@ -311,15 +312,15 @@ Around 4% data inflation for typical 1400-byte inner packets.` funFacts: [ { title: 'The "4,000 lines of code" number is in the whitepaper itself', - text: "From the [[pioneer:jason-donenfeld|Donenfeld]] {{ndss-conf|NDSS}} 2017 paper: *\"WireGuard can be simply implemented for {{linux|Linux}} in less than 4,000 lines of code, making it easily audited and verified.\"* For comparison, OpenVPN's core (not counting OpenSSL) is north of 100,000 lines, and the equivalent {{linux|Linux}} [[ipsec|IPsec]] stack ({{xfrm|XFRM}} + strongSwan + libraries) is in the six digits. The order-of-magnitude has not changed in the 9 years since." + text: 'From the [[pioneer:jason-donenfeld|Donenfeld]] {{ndss-conf|NDSS}} 2017 paper: *"WireGuard can be simply implemented for {{linux|Linux}} in less than 4,000 lines of code, making it easily audited and verified."* For comparison, OpenVPN\'s core (not counting OpenSSL) is north of 100,000 lines, and the equivalent {{linux|Linux}} [[ipsec|IPsec]] stack ({{xfrm|XFRM}} + strongSwan + libraries) is in the six digits. The order-of-magnitude has not changed in the 9 years since.' }, { title: 'Linus said it was "a work of art"', - text: 'On 2 August 2018, in a postscript to a {{linux|Linux}} 4.18 networking pull-request, Linus Torvalds wrote: *"I see that Jason actually made the pull request to have wireguard included in the kernel. Can I just once again state my love for it and hope it gets merged soon? Maybe the code isn\'t perfect, but I\'ve skimmed it, and compared to the horrors that are OpenVPN and [[ipsec|IPsec]], it\'s a work of art."* It took another 19 months for the merge to land ({{linux|Linux}} 5.6, March 2020) but the endorsement set the trajectory.' + text: "On 2 August 2018, in a postscript to a {{linux|Linux}} 4.18 networking pull-request, Linus Torvalds wrote: *\"I see that Jason actually made the pull request to have wireguard included in the kernel. Can I just once again state my love for it and hope it gets merged soon? Maybe the code isn't perfect, but I've skimmed it, and compared to the horrors that are OpenVPN and [[ipsec|IPsec]], it's a work of art.\"* It took another 19 months for the merge to land ({{linux|Linux}} 5.6, March 2020) but the endorsement set the trajectory." }, { title: 'No IETF RFC β€” by design', - text: '[[pioneer:jason-donenfeld|Donenfeld]] on the *Security Cryptography Whatever* podcast (Dec 2021): *"I have a very low opinion of internet standards, cryptography and internet standards… WireGuard is one of the first times in my career I\'ve seen something get this much adoption without having to get through the filter of the {{ietf|IETF}}. I worry that publishing an {{rfc-doc|RFC}} might send the wrong message where β€” oh, it sends the right bits on the wire, it\'s done β€” that\'s not good enough."* {{rfc-doc|RFC}} 8922 (2020) mentions WireGuard for the Transport Services document but is not normative.' + text: "[[pioneer:jason-donenfeld|Donenfeld]] on the *Security Cryptography Whatever* podcast (Dec 2021): *\"I have a very low opinion of internet standards, cryptography and internet standards… WireGuard is one of the first times in my career I've seen something get this much adoption without having to get through the filter of the {{ietf|IETF}}. I worry that publishing an {{rfc-doc|RFC}} might send the wrong message where β€” oh, it sends the right bits on the wire, it's done β€” that's not good enough.\"* {{rfc-doc|RFC}} 8922 (2020) mentions WireGuard for the Transport Services document but is not normative." }, { title: 'The logo is a snake from Delphi', @@ -332,7 +333,7 @@ Around 4% data inflation for typical 1400-byte inner packets.` { title: 'AllowedIPs is your routing table AND your ACL', text: 'A single `AllowedIPs` field on each {{peer|peer}} does two jobs: outbound it picks which {{peer|peer}} to send packets through for a given destination prefix, and inbound it filters which inner source IPs the {{peer|peer}} is allowed to send. Forgetting this is the most common config bug. **Cure:** when a {{peer|peer}} is supposed to be a "remote {{subnet|subnet}}", put the {{subnet|subnet}} in `AllowedIPs`. When a {{peer|peer}} is supposed to be a "single roadwarrior", put just its `/32`. When a {{peer|peer}} is "default route everything", use `0.0.0.0/0, ::/0` β€” and add `PostUp` rules for masquerading.' - }, + }, { title: 'No dynamic IPs out of the box', text: 'Vanilla WireGuard refuses to do [[dns|DNS]] lookups on `Endpoint =` (the kernel module is keep-it-simple, no [[dns|DNS]]). The plumbing for "the {{peer|peer}}\'s endpoint changed because their {{isp|ISP}} rebooted them" is **not in the kernel**. `wg-quick(8)` resolves hostnames at interface-up time only. **Cure:** for road-warriors, the {{peer|peer}} connects *out* to a fixed endpoint and uses `PersistentKeepalive` to hold the {{nat|NAT}} binding. For dynamic-{{ip-address|IP}} servers, run `reresolve-dns.timer` (Donenfeld\'s own systemd timer) to re-resolve `Endpoint =` periodically.' diff --git a/src/lib/data/protocols/xmpp.ts b/src/lib/data/protocols/xmpp.ts index d50ec5c..a9ea1d1 100644 --- a/src/lib/data/protocols/xmpp.ts +++ b/src/lib/data/protocols/xmpp.ts @@ -72,7 +72,8 @@ class ChatBot(slixmpp.ClientXMPP): bot = ChatBot("alice@example.com", "secret") bot.connect() bot.process()`, - caption: '[[xmpp|XMPP]] client β€” {{mqtt-connect|connect}}, announce presence, and send messages as {{xml|XML}} stanzas', + caption: + '[[xmpp|XMPP]] client β€” {{mqtt-connect|connect}}, announce presence, and send messages as {{xml|XML}} stanzas', alternatives: [ { language: 'javascript', diff --git a/src/lib/data/protocols/zigbee.ts b/src/lib/data/protocols/zigbee.ts index b793526..b8a80e5 100644 --- a/src/lib/data/protocols/zigbee.ts +++ b/src/lib/data/protocols/zigbee.ts @@ -19,7 +19,7 @@ The current spec is **Zigbee PRO 2023 (R23)**, document 05-3474-23, ratified 15 { title: 'IEEE 802.15.4 PHY β€” 2.4 GHz O-QPSK at 250 kbit/s + sub-GHz', description: - "All Zigbee variants ride {{ieee-802-15-4|IEEE 802.15.4-2020}}. The dominant {{phy|PHY}} is **2.4 GHz O-QPSK** with 16 channels (11–26), 5 MHz spacing, 250 kbit/s data rate. Sub-GHz PHYs at 868 MHz (Europe, 20 kbit/s {{bpsk|BPSK}}) and 902–928 MHz (NA, 40 kbit/s {{bpsk|BPSK}}) give better wall penetration and less [[wifi|Wi-Fi]] co-channel interference at lower bit rates; R23 adds FSK PHYs in those same bands. {{frame|Frames}} are bounded at **127 octets PSDU** with a **16-bit {{checksum|FCS}}**. The {{mac-address|MAC}} uses unslotted CSMA-CA in most deployments (FFDs as routers, RFDs as end-devices), with optional beacon-mode for low-power sensor networks." + 'All Zigbee variants ride {{ieee-802-15-4|IEEE 802.15.4-2020}}. The dominant {{phy|PHY}} is **2.4 GHz O-QPSK** with 16 channels (11–26), 5 MHz spacing, 250 kbit/s data rate. Sub-GHz PHYs at 868 MHz (Europe, 20 kbit/s {{bpsk|BPSK}}) and 902–928 MHz (NA, 40 kbit/s {{bpsk|BPSK}}) give better wall penetration and less [[wifi|Wi-Fi]] co-channel interference at lower bit rates; R23 adds FSK PHYs in those same bands. {{frame|Frames}} are bounded at **127 octets PSDU** with a **16-bit {{checksum|FCS}}**. The {{mac-address|MAC}} uses unslotted CSMA-CA in most deployments (FFDs as routers, RFDs as end-devices), with optional beacon-mode for low-power sensor networks.' }, { title: 'NWK layer β€” mesh routing with AODV', @@ -29,7 +29,7 @@ The current spec is **Zigbee PRO 2023 (R23)**, document 05-3474-23, ratified 15 { title: 'APS layer β€” Application Support Sublayer with endpoints and clusters', description: - "The {{aps-layer|APS}} layer {{multiplexing|multiplexes}} application traffic onto **endpoints** (1–240, like sub-addresses on a device β€” endpoint 11 might be a bulb, endpoint 1 a switch). Frames carry a **ProfileID** (Home Automation = 0x0104, Smart Energy = 0x0109), a **ClusterID** (OnOff = 0x0006, Level Control = 0x0008, Color Control = 0x0300, OTA Upgrade = 0x0019), and an **APSCounter** for {{replay-attack|replay protection}}. {{aps-layer|APS}}-level {{aes-128|AES-128}}-{{ccm-mode|CCM}}* {{encryption|encryption}} is layered on top of {{zigbee-nwk|NWK}} {{encryption|encryption}} when sensitive (e.g. {{trust-center|Trust Center}} Transport Key commands). The {{aps-layer|APS}} layer also handles binding tables β€” persistent destination-routing for groupcast lights and similar." + 'The {{aps-layer|APS}} layer {{multiplexing|multiplexes}} application traffic onto **endpoints** (1–240, like sub-addresses on a device β€” endpoint 11 might be a bulb, endpoint 1 a switch). Frames carry a **ProfileID** (Home Automation = 0x0104, Smart Energy = 0x0109), a **ClusterID** (OnOff = 0x0006, Level Control = 0x0008, Color Control = 0x0300, OTA Upgrade = 0x0019), and an **APSCounter** for {{replay-attack|replay protection}}. {{aps-layer|APS}}-level {{aes-128|AES-128}}-{{ccm-mode|CCM}}* {{encryption|encryption}} is layered on top of {{zigbee-nwk|NWK}} {{encryption|encryption}} when sensitive (e.g. {{trust-center|Trust Center}} Transport Key commands). The {{aps-layer|APS}} layer also handles binding tables β€” persistent destination-routing for groupcast lights and similar.' }, { title: 'ZCL β€” the Zigbee Cluster Library data model', @@ -245,7 +245,7 @@ That entire on-the-wire dump fits in roughly 40 bytes β€” a single Hue bulb comm }, image: { src: 'https://upload.wikimedia.org/wikipedia/commons/thumb/1/1e/Zigbee_logo.svg/330px-Zigbee_logo.svg.png', - alt: 'The Zigbee logo β€” a stylised honey-bee evoking the waggle dance, the Alliance\'s metaphor for mesh routing.', + alt: "The Zigbee logo β€” a stylised honey-bee evoking the waggle dance, the Alliance's metaphor for mesh routing.", caption: 'The Zigbee name comes from the **honey-bee waggle dance** β€” the figure-eight a foraging bee performs to communicate the direction and distance of food. The Alliance picked the metaphor for the mesh: thousands of small, low-power messengers cooperatively routing information to where it is needed.', credit: 'Image: Wikimedia Commons / Connectivity Standards Alliance trademark' @@ -256,7 +256,7 @@ That entire on-the-wire dump fits in roughly 40 bytes β€” a single Hue bulb comm date: '2023-03', title: 'Zigbee PRO 2023 (R23) ratified', description: - "Document 05-3474-23, ratified **15 March 2023** by the {{sig-bluetooth-acronym|CSA}}. Headline additions: **{{dynamic-link-key|Dynamic Link Key}}** negotiation using SPEKE over {{curve25519|Curve25519}} with {{aes|AES}}-MMO-128 (kills the *ZigBeeAlliance09* default-key sniff-at-join attack), **{{trust-center|Trust Center}} Swap-Out** (a failed Coordinator can be replaced without re-joining every device), **Device Interview** (TC policy gate before granting full access), **Works With All Hubs** phase 1, sub-GHz support for Europe (863–870 MHz) and North America (902–928 MHz), and absorbs **Zigbee Direct**. Silicon Labs, Texas Instruments, and ubisys are the named *golden units*. Backward-compatible with Zigbee 3.0 certification.", + 'Document 05-3474-23, ratified **15 March 2023** by the {{sig-bluetooth-acronym|CSA}}. Headline additions: **{{dynamic-link-key|Dynamic Link Key}}** negotiation using SPEKE over {{curve25519|Curve25519}} with {{aes|AES}}-MMO-128 (kills the *ZigBeeAlliance09* default-key sniff-at-join attack), **{{trust-center|Trust Center}} Swap-Out** (a failed Coordinator can be replaced without re-joining every device), **Device Interview** (TC policy gate before granting full access), **Works With All Hubs** phase 1, sub-GHz support for Europe (863–870 MHz) and North America (902–928 MHz), and absorbs **Zigbee Direct**. Silicon Labs, Texas Instruments, and ubisys are the named *golden units*. Backward-compatible with Zigbee 3.0 certification.', source: { url: 'https://csa-iot.org/newsroom/zigbee-pro-2023-released/', label: 'CSA: Zigbee PRO 2023 release announcement' @@ -266,7 +266,7 @@ That entire on-the-wire dump fits in roughly 40 bytes β€” a single Hue bulb comm date: '2023-09', title: 'Philips Hue Bridge ships Matter firmware β€” 30M+ bulbs become Matter accessories', description: - "Public rollout **19/20 September 2023** of {{matter|Matter}} firmware for the second-generation square Hue Bridge after a Q1 2023 target slipped. The {{bgp-update|update}} exposes existing Hue Zigbee bulbs to {{apple|Apple}} Home, {{google|Google}} Home, Amazon Alexa, and SmartThings over {{ip-address|IP}}, while preserving the Zigbee mesh underneath. This single {{bgp-update|update}} made the Hue Bridge by far the largest {{matter|Matter}} Bridge installation in the world. Signify has continued to ship Bridge and Bridge Pro firmware updates through 2024–26.", + 'Public rollout **19/20 September 2023** of {{matter|Matter}} firmware for the second-generation square Hue Bridge after a Q1 2023 target slipped. The {{bgp-update|update}} exposes existing Hue Zigbee bulbs to {{apple|Apple}} Home, {{google|Google}} Home, Amazon Alexa, and SmartThings over {{ip-address|IP}}, while preserving the Zigbee mesh underneath. This single {{bgp-update|update}} made the Hue Bridge by far the largest {{matter|Matter}} Bridge installation in the world. Signify has continued to ship Bridge and Bridge Pro firmware updates through 2024–26.', source: { url: 'https://www.hueblog.com/2023/09/19/the-day-has-come-philips-hue-bridge-now-supports-matter/', label: 'Hueblog: Hue Bridge Matter release' @@ -276,7 +276,7 @@ That entire on-the-wire dump fits in roughly 40 bytes β€” a single Hue bulb comm date: '2024-05', title: 'Aqara Hub M3 ships globally β€” Zigbee + Thread + Matter in one box', description: - "Announced at {{ces-show|CES}} on **8 January 2024**; shipped **8 May 2024**. Triple-protocol β€” **Zigbee 3.0 + {{thread|Thread}} {{border-router|border router}} + {{matter|Matter}} controller + {{matter|Matter}} Bridge** β€” with dual-band [[wifi|Wi-Fi]], Power-over-Ethernet, {{usb|USB}}-C, IR blaster, **8 GB encrypted local storage**, and *no microphone or camera* (deliberate privacy stance). Up to 127 Zigbee + 127 {{thread|Thread}} devices. Aqara published a multi-hub-{{failover|failover}} architecture (up to 10 M3s mirroring automations) in mid-2024 β€” the canonical 2024–25 form factor for a privacy-forward smart-home bridge.", + 'Announced at {{ces-show|CES}} on **8 January 2024**; shipped **8 May 2024**. Triple-protocol β€” **Zigbee 3.0 + {{thread|Thread}} {{border-router|border router}} + {{matter|Matter}} controller + {{matter|Matter}} Bridge** β€” with dual-band [[wifi|Wi-Fi]], Power-over-Ethernet, {{usb|USB}}-C, IR blaster, **8 GB encrypted local storage**, and *no microphone or camera* (deliberate privacy stance). Up to 127 Zigbee + 127 {{thread|Thread}} devices. Aqara published a multi-hub-{{failover|failover}} architecture (up to 10 M3s mirroring automations) in mid-2024 β€” the canonical 2024–25 form factor for a privacy-forward smart-home bridge.', source: { url: 'https://www.aqara.com/en/news/aqara-hub-m3-globally', label: 'Aqara: Hub M3 global launch' @@ -296,7 +296,7 @@ That entire on-the-wire dump fits in roughly 40 bytes β€” a single Hue bulb comm date: '2025-08', title: 'Matter 1.4.2 β€” Wi-Fi-only commissioning (BLE optional)', description: - "Released **11 August 2025**. {{matter|Matter}} 1.4.2 adds **Wi-Fi-only commissioning** β€” devices can be set up without a Bluetooth Low Energy radio, reducing BOM cost for cheaper {{matter|Matter}}-bridged accessories. Also adds **Quieter Reporting** (battery-saving data-model change) and admin verification. For the Zigbee story, this means a {{matter|Matter}} Bridge for Zigbee no longer needs {{ble|BLE}} silicon β€” accelerating low-cost bridges from secondary brands.", + 'Released **11 August 2025**. {{matter|Matter}} 1.4.2 adds **Wi-Fi-only commissioning** β€” devices can be set up without a Bluetooth Low Energy radio, reducing BOM cost for cheaper {{matter|Matter}}-bridged accessories. Also adds **Quieter Reporting** (battery-saving data-model change) and admin verification. For the Zigbee story, this means a {{matter|Matter}} Bridge for Zigbee no longer needs {{ble|BLE}} silicon β€” accelerating low-cost bridges from secondary brands.', source: { url: 'https://csa-iot.org/newsroom/matter-1-4-2-released/', label: 'CSA: Matter 1.4.2 release' @@ -306,7 +306,7 @@ That entire on-the-wire dump fits in roughly 40 bytes β€” a single Hue bulb comm date: '2025-11', title: 'Matter 1.5 β€” camera streaming closes the last Zigbee gap', description: - "Released **20 November 2025**. {{matter|Matter}} 1.5 adds **camera streaming** via an RTSP side-channel β€” the long-awaited piece for {{matter|Matter}} to fully displace Zigbee in new home-security deployments. For Zigbee, this is the moment new device categories (cameras, video doorbells) no longer have a reason to go through a Zigbee bridge β€” they can go directly on [[wifi|Wi-Fi]] or {{thread|Thread}} with {{matter|Matter}} from day one.", + 'Released **20 November 2025**. {{matter|Matter}} 1.5 adds **camera streaming** via an RTSP side-channel β€” the long-awaited piece for {{matter|Matter}} to fully displace Zigbee in new home-security deployments. For Zigbee, this is the moment new device categories (cameras, video doorbells) no longer have a reason to go through a Zigbee bridge β€” they can go directly on [[wifi|Wi-Fi]] or {{thread|Thread}} with {{matter|Matter}} from day one.', source: { url: 'https://matteralpha.com/matter-timeline', label: 'MatterAlpha: Matter timeline' @@ -319,7 +319,7 @@ That entire on-the-wire dump fits in roughly 40 bytes β€” a single Hue bulb comm org: 'Signify (Philips Hue)', scale: '~30M+ bulbs lifetime; largest Matter Bridge installation in the world', description: - "Launched **30 October 2012** exclusively at {{apple|Apple}} Stores for $199/starter kit. The Philips press release mentioned *ZigBee LightLink* exactly once, in the technical body; the in-store materials and iOS app deliberately avoided the term. The Hue inventor George Yianni built the first prototype as a {{ui|UI}} experiment on an iPhone. Hue migrated to Zigbee 3.0 via a Q1 2018 Bridge firmware {{bgp-update|update}}; the second-generation square Bridge gained {{matter|Matter}} support on 19 September 2023, turning the entire installed base into {{matter|Matter}} accessories overnight. The Hue Bridge is the canonical answer to *how does my smart-home ecosystem talk to Zigbee?*" + 'Launched **30 October 2012** exclusively at {{apple|Apple}} Stores for $199/starter kit. The Philips press release mentioned *ZigBee LightLink* exactly once, in the technical body; the in-store materials and iOS app deliberately avoided the term. The Hue inventor George Yianni built the first prototype as a {{ui|UI}} experiment on an iPhone. Hue migrated to Zigbee 3.0 via a Q1 2018 Bridge firmware {{bgp-update|update}}; the second-generation square Bridge gained {{matter|Matter}} support on 19 September 2023, turning the entire installed base into {{matter|Matter}} accessories overnight. The Hue Bridge is the canonical answer to *how does my smart-home ecosystem talk to Zigbee?*' }, { org: 'IKEA TrΓ₯dfri', @@ -331,19 +331,19 @@ That entire on-the-wire dump fits in roughly 40 bytes β€” a single Hue bulb comm org: 'Aqara / Lumi United (Hub M3)', scale: '127 Zigbee + 127 Thread devices per hub; 100+ device models; multi-hub failover', description: - "Shenzhen-based, originally an {{apple|Apple}} HomeKit ecosystem partner. The **Aqara Hub M3** (announced {{ces-show|CES}} 8 January 2024, shipping 8 May 2024) is the textbook modern multi-protocol bridge: Zigbee 3.0 + {{thread|Thread}} {{border-router|border router}} + {{matter|Matter}} controller and bridge, dual-band [[wifi|Wi-Fi]] (2.4/5 GHz, {{wpa3|WPA3}}), PoE, {{usb|USB}}-C, 8 GB encrypted local storage, **no microphone or camera**. The M3 supersedes older Aqara hubs and runs automations locally β€” an Edge-Hub model that does not depend on the Aqara cloud." + 'Shenzhen-based, originally an {{apple|Apple}} HomeKit ecosystem partner. The **Aqara Hub M3** (announced {{ces-show|CES}} 8 January 2024, shipping 8 May 2024) is the textbook modern multi-protocol bridge: Zigbee 3.0 + {{thread|Thread}} {{border-router|border router}} + {{matter|Matter}} controller and bridge, dual-band [[wifi|Wi-Fi]] (2.4/5 GHz, {{wpa3|WPA3}}), PoE, {{usb|USB}}-C, 8 GB encrypted local storage, **no microphone or camera**. The M3 supersedes older Aqara hubs and runs automations locally β€” an Edge-Hub model that does not depend on the Aqara cloud.' }, { org: 'Samsung SmartThings', scale: 'Tens of millions of hubs across Hub v1–v3 and Station', description: - "SmartThings shipped the original Hub in 2013; Samsung acquired the company in August 2014. Carries Zigbee + Z-Wave from day one; later generations added {{thread|Thread}} and {{matter|Matter}}. SmartThings is the most common single {{zigbee-coordinator|Zigbee Coordinator}} outside of Hue. Samsung sits on the {{sig-bluetooth-acronym|CSA}} board." + 'SmartThings shipped the original Hub in 2013; Samsung acquired the company in August 2014. Carries Zigbee + Z-Wave from day one; later generations added {{thread|Thread}} and {{matter|Matter}}. SmartThings is the most common single {{zigbee-coordinator|Zigbee Coordinator}} outside of Hue. Samsung sits on the {{sig-bluetooth-acronym|CSA}} board.' }, { org: 'Amazon Echo Plus / Echo 4th gen / Echo Hub', scale: 'Tens of millions of units 2017+', description: - "Amazon shipped a built-in {{zigbee-coordinator|Zigbee Coordinator}} inside the Echo Plus in 2017 β€” the first time a mass-market smart speaker pretended to be a Zigbee hub. Echo (4th gen) and Echo Show 10 also carry a Zigbee radio; the Echo Hub (2024) is positioned as a smart-home control panel with Zigbee inside. Amazon Sidewalk overlaps mostly at sub-GHz (900 MHz) rather than competing with Zigbee directly." + 'Amazon shipped a built-in {{zigbee-coordinator|Zigbee Coordinator}} inside the Echo Plus in 2017 β€” the first time a mass-market smart speaker pretended to be a Zigbee hub. Echo (4th gen) and Echo Show 10 also carry a Zigbee radio; the Echo Hub (2024) is positioned as a smart-home control panel with Zigbee inside. Amazon Sidewalk overlaps mostly at sub-GHz (900 MHz) rather than competing with Zigbee directly.' }, { org: 'Acuity Brands nLight AIR + Atrius', @@ -355,14 +355,14 @@ That entire on-the-wire dump fits in roughly 40 bytes β€” a single Hue bulb comm org: 'VusionGroup electronic shelf labels', scale: '350M ESLs shipped in 2023 alone; Walmart US 4,600-store rollout from 2024', description: - "The under-reported Zigbee deployment that dwarfs every consumer brand by unit volume. VusionGroup (formerly SES-imagotag) runs a Zigbee-family radio in its EdgeSense / VusionCloud platform. The 23 December 2024 Walmart contract extension after a successful 500-store pilot will roll out across **all 4,600 US Walmart stores**. Carrefour, Lidl, Edeka, Tesco, and the UK Co-operative are parallel customers β€” cumulative Zigbee-family ESL deployments are well into the billion-device lifetime range." + 'The under-reported Zigbee deployment that dwarfs every consumer brand by unit volume. VusionGroup (formerly SES-imagotag) runs a Zigbee-family radio in its EdgeSense / VusionCloud platform. The 23 December 2024 Walmart contract extension after a successful 500-store pilot will roll out across **all 4,600 US Walmart stores**. Carrefour, Lidl, Edeka, Tesco, and the UK Co-operative are parallel customers β€” cumulative Zigbee-family ESL deployments are well into the billion-device lifetime range.' } ], funFacts: [ { title: 'The name comes from the honey-bee waggle dance', - text: "Foraging bees returning to the hive perform a figure-eight dance whose orientation and duration communicate the direction and distance of food β€” an organic mesh routing protocol, in effect. The Alliance picked the name and the bee logo for exactly this metaphor: thousands of small, low-power messengers cooperatively routing information to where it is needed." + text: 'Foraging bees returning to the hive perform a figure-eight dance whose orientation and duration communicate the direction and distance of food β€” an organic mesh routing protocol, in effect. The Alliance picked the name and the bee logo for exactly this metaphor: thousands of small, low-power messengers cooperatively routing information to where it is needed.' }, { title: 'Philips Hue\'s 2012 Apple Store launch never said "Zigbee" out loud', @@ -374,15 +374,15 @@ That entire on-the-wire dump fits in roughly 40 bytes β€” a single Hue bulb comm }, { title: 'zigbee2mqtt supports 5,390 devices from 568 vendors', - text: "A single GPL-licensed Node.js project β€” maintained primarily by Koen Kanters β€” keeps a more complete decoder database of Zigbee Cluster Library quirks than any single commercial hub vendor. zigbee2mqtt is the de-facto interoperability spec for the FOSS smart-home community. The most common {{zigbee-coordinator|Zigbee Coordinator}} in 2026 is a $20 Sonoff ZBDongle-E plugged into a Raspberry Pi running Home Assistant." + text: 'A single GPL-licensed Node.js project β€” maintained primarily by Koen Kanters β€” keeps a more complete decoder database of Zigbee Cluster Library quirks than any single commercial hub vendor. zigbee2mqtt is the de-facto interoperability spec for the FOSS smart-home community. The most common {{zigbee-coordinator|Zigbee Coordinator}} in 2026 is a $20 Sonoff ZBDongle-E plugged into a Raspberry Pi running Home Assistant.' }, { - title: 'Walmart\'s shelf labels will outnumber every Hue bulb ever sold', - text: "When the 4,600-store Walmart US expansion completes, the total number of Zigbee-family devices on Walmart shelves alone will be roughly an order of magnitude larger than the total installed base of Philips Hue bulbs ever sold. The next time someone asks *is Zigbee dead?*, the right answer is: it is invisible because it is behind every price tag in your supermarket." + title: "Walmart's shelf labels will outnumber every Hue bulb ever sold", + text: 'When the 4,600-store Walmart US expansion completes, the total number of Zigbee-family devices on Walmart shelves alone will be roughly an order of magnitude larger than the total installed base of Philips Hue bulbs ever sold. The next time someone asks *is Zigbee dead?*, the right answer is: it is invisible because it is behind every price tag in your supermarket.' }, { title: 'Bob Heile was a founding member of IEEE 802.11 *and* the Zigbee Alliance', - text: "Robert F. Heile (1945–2020) chaired the Zigbee Alliance from its founding in 2002 through 2013, was a founding member of {{ieee-802-15-4|IEEE}} [[wifi|802.11]] (Wi-Fi) in 1990, chaired {{ieee-802-15-4|IEEE}} 802.15 for two decades, and later directed standards at the Wi-SUN Alliance. Almost every low-power 802.15.4-based protocol you can name β€” Zigbee, {{thread|Thread}}, WirelessHART, Wi-SUN β€” traces directly back through Bob. He died of prostate cancer on 24 September 2020; his {{ieee-802-15-4|IEEE}} 802.15 chair role was passed days before his death." + text: 'Robert F. Heile (1945–2020) chaired the Zigbee Alliance from its founding in 2002 through 2013, was a founding member of {{ieee-802-15-4|IEEE}} [[wifi|802.11]] (Wi-Fi) in 1990, chaired {{ieee-802-15-4|IEEE}} 802.15 for two decades, and later directed standards at the Wi-SUN Alliance. Almost every low-power 802.15.4-based protocol you can name β€” Zigbee, {{thread|Thread}}, WirelessHART, Wi-SUN β€” traces directly back through Bob. He died of prostate cancer on 24 September 2020; his {{ieee-802-15-4|IEEE}} 802.15 chair role was passed days before his death.' } ], @@ -398,7 +398,7 @@ That entire on-the-wire dump fits in roughly 40 bytes β€” a single Hue bulb comm }, { title: 'Router density and child-table limits', - text: "Mains-powered Zigbee devices act as routers and adopt sleepy end-devices as children. The child-table size on a typical CC2652 / EFR32 firmware is **32**; the Sonoff ZBDongle-E reliably hits trouble around 50 directly-associated devices because of memory. The fix is *more routers, not a beefier coordinator* β€” every smart plug, ceiling switch, and powered bulb is a free router. Aim for at least one router per 8–10 metres in every direction from the Coordinator, and one router per sleepy-end-device cluster (a bedroom full of battery sensors should have a mains-powered plug or bulb acting as their parent)." + text: 'Mains-powered Zigbee devices act as routers and adopt sleepy end-devices as children. The child-table size on a typical CC2652 / EFR32 firmware is **32**; the Sonoff ZBDongle-E reliably hits trouble around 50 directly-associated devices because of memory. The fix is *more routers, not a beefier coordinator* β€” every smart plug, ceiling switch, and powered bulb is a free router. Aim for at least one router per 8–10 metres in every direction from the Coordinator, and one router per sleepy-end-device cluster (a bedroom full of battery sensors should have a mains-powered plug or bulb acting as their parent).' }, { title: 'Install codes vs. default key β€” pick a stance at deployment time', diff --git a/src/lib/data/rfcs.ts b/src/lib/data/rfcs.ts index f88e2cb..0f11a20 100644 --- a/src/lib/data/rfcs.ts +++ b/src/lib/data/rfcs.ts @@ -177,7 +177,10 @@ Edited by Wesley Eddy in August 2022, this RFC consolidated **41 years of errata { ref: 'Β§3.1', description: '[[tcp|TCP]] header format' }, { ref: 'Β§3.4', description: 'Sequence numbers' }, { ref: 'Β§3.5', description: '{{three-way-handshake|Three-way handshake}}' }, - { ref: 'Β§3.8', description: '{{sliding-window|Sliding window}} {{flow-control|flow control}}' } + { + ref: 'Β§3.8', + description: '{{sliding-window|Sliding window}} {{flow-control|flow control}}' + } ] }, { @@ -218,7 +221,10 @@ The math originated in [[pioneer:van-jacobson|Van Jacobson]] and Karels's 1988 S Originally published as RFC 1323 in 1992 by [[pioneer:van-jacobson|Van Jacobson]] et al.; refined and republished here. Both options are negotiated in the SYN β€” they're either there from the start or never.`, notableSections: [ - { ref: '{{window-scale|Window Scale}}', description: 'Lets the 16-bit receive window represent up to 2³⁰ bytes' }, + { + ref: '{{window-scale|Window Scale}}', + description: 'Lets the 16-bit receive window represent up to 2³⁰ bytes' + }, { ref: 'Timestamps + PAWS', description: 'Protection Against Wrapped Sequence numbers' } ] }, @@ -383,7 +389,7 @@ Internally cleaner than 1.0–1.2; externally indistinguishable on the wire from notableSections: [ { ref: 'Β§5', description: 'Record Protocol' }, { ref: 'Β§7.1', description: 'Key schedule (HKDF-Extract / HKDF-Expand-Label)' }, - { ref: 'Β§D.4', description: "Middlebox-compatibility hacks (\"looks like [[tls|TLS]] 1.2\")" } + { ref: 'Β§D.4', description: 'Middlebox-compatibility hacks ("looks like [[tls|TLS]] 1.2")' } ] }, { @@ -885,7 +891,8 @@ Co-authored by Paul Hoffman and Patrick McManus (then Mozilla). DoH is now ubiqu }, { number: '9460', - title: 'Service Binding and Parameter Specification via the DNS (SVCB and HTTPS Resource Records)', + title: + 'Service Binding and Parameter Specification via the DNS (SVCB and HTTPS Resource Records)', year: 2023, authors: 'B. Schwartz, M. Bishop, E. Nygren', status: 'proposed-standard', @@ -961,7 +968,8 @@ If your mail client is configured to send via your provider, it's almost certain }, { number: '8314', - title: 'Cleartext Considered Obsolete: Use of Transport Layer Security (TLS) for Email Submission and Access', + title: + 'Cleartext Considered Obsolete: Use of Transport Layer Security (TLS) for Email Submission and Access', year: 2018, authors: 'K. Moore, C. Newman', status: 'proposed-standard', @@ -1528,9 +1536,7 @@ Edited across decades by [[pioneer:charlie-kaufman|Charlie Kaufman]] (Microsoft) abstract: `The first deployable **post-quantum** extension to [[ipsec|IPsec]]. Adds a **Post-quantum Preshared Key (PPK)** to the IKEv2 key derivation so that even if classical Diffie-Hellman is broken later by a quantum adversary, recorded traffic remains unrecoverable (the "harvest-now-decrypt-later" defence). Compatible with the IKEv2 state machine; only the KDF inputs change. Co-authored by Cisco (Scott Fluhrer, David McGrew), AWS (Panos Kampanakis), and ELVIS-PLUS (Valery Smyslov) β€” illustrating that [[ipsec|IPsec]] is always a multi-vendor, multi-government project. Superseded for new deployments by [[rfc:9242|RFC 9242]] + [[rfc:9370|RFC 9370]] + the draft-ietf-ipsecme-ikev2-mlkem draft, but still the only PQ option for legacy stacks that can't be upgraded.`, - notableSections: [ - { ref: 'Β§3', description: 'PPK_IDENTITY notify and KDF mixing' } - ] + notableSections: [{ ref: 'Β§3', description: 'PPK_IDENTITY notify and KDF mixing' }] }, { number: '9242', @@ -1541,9 +1547,7 @@ Compatible with the IKEv2 state machine; only the KDF inputs change. Co-authored url: 'https://www.rfc-editor.org/rfc/rfc9242', protocols: ['ipsec'], abstract: `Adds a new **IKE_INTERMEDIATE** exchange between IKE_SA_INIT and IKE_AUTH so that large post-quantum public keys (ML-KEM-768 is 1,184 bytes; ML-KEM-1024 is 1,568 bytes) can be transferred *after* the IKE SA is protected but *before* the identity is revealed. Without this, the IKE_SA_INIT message would exceed common UDP MTU limits and force fragmentation that NATs and firewalls regularly mangle.`, - notableSections: [ - { ref: 'Β§3', description: 'IKE_INTERMEDIATE message format and rules' } - ] + notableSections: [{ ref: 'Β§3', description: 'IKE_INTERMEDIATE message format and rules' }] }, { number: '9370', @@ -1592,7 +1596,10 @@ Compatible with the IKEv2 state machine; only the KDF inputs change. Co-authored Independent of the transport. Works equally well over multicast DNS on the link or over unicast DNS for wide-area discovery (the latter now formalised by SRP, RFC 9665, 2025). The wire-protocol substrate for every AirPlay receiver, AirPrint printer, Chromecast, Sonos speaker, and Matter device on the planet.`, notableSections: [ - { ref: 'Β§4', description: 'Service Instance Names (the `Instance._service._proto.domain` pattern)' }, + { + ref: 'Β§4', + description: 'Service Instance Names (the `Instance._service._proto.domain` pattern)' + }, { ref: 'Β§7', description: 'Service Names registered with IANA' }, { ref: 'Β§6', description: 'Data syntax for DNS-SD TXT records' } ] @@ -1628,7 +1635,7 @@ The protocol foundation for Discord's **DAVE** end-to-end-encrypted voice (deplo // ── Congestion control ──────────────────────────────────────────── { number: '6582', - title: 'The NewReno Modification to TCP\'s Fast Recovery Algorithm', + title: "The NewReno Modification to TCP's Fast Recovery Algorithm", year: 2012, authors: 'T. Henderson, S. Floyd, A. Gurtov, Y. Nishida', status: 'proposed-standard', diff --git a/src/lib/data/subcategories.ts b/src/lib/data/subcategories.ts index 4c7d374..be20ed8 100644 --- a/src/lib/data/subcategories.ts +++ b/src/lib/data/subcategories.ts @@ -16,8 +16,7 @@ export const subcategories: Subcategory[] = [ name: 'Internet Layer', categoryId: 'network-foundations', protocolIds: ['ip', 'ipv6', 'icmp'], - description: - 'Best-effort packet delivery across networks β€” the narrow waist of the hourglass.', + description: 'Best-effort packet delivery across networks β€” the narrow waist of the hourglass.', icon: 'internet-layer' }, { @@ -54,8 +53,7 @@ export const subcategories: Subcategory[] = [ name: 'Datagram Transport', categoryId: 'transport', protocolIds: ['udp', 'quic'], - description: - 'When you go raw β€” or build something better in user space β€” on top of datagrams.', + description: 'When you go raw β€” or build something better in user space β€” on top of datagrams.', icon: 'datagram-transport' }, @@ -83,8 +81,7 @@ export const subcategories: Subcategory[] = [ name: 'RPC Styles', categoryId: 'web-api', protocolIds: ['soap', 'json-rpc', 'grpc'], - description: - 'Calling a remote function like a local one β€” the RPC dream and its iterations.', + description: 'Calling a remote function like a local one β€” the RPC dream and its iterations.', icon: 'rpc-styles' }, { @@ -92,8 +89,7 @@ export const subcategories: Subcategory[] = [ name: 'Realtime Web', categoryId: 'web-api', protocolIds: ['sse', 'websockets'], - description: - 'Breaking out of request/response β€” server push and full-duplex on the web.', + description: 'Breaking out of request/response β€” server push and full-duplex on the web.', icon: 'realtime-web' }, { diff --git a/src/lib/data/subcategory-stories/agent-protocols.ts b/src/lib/data/subcategory-stories/agent-protocols.ts index 83af88d..f3cb1df 100644 --- a/src/lib/data/subcategory-stories/agent-protocols.ts +++ b/src/lib/data/subcategory-stories/agent-protocols.ts @@ -3,12 +3,12 @@ import type { SubcategoryStory } from './types'; export const agentProtocolsStory: SubcategoryStory = { subcategoryId: 'agent-protocols', tagline: - "Protocols emerging in real time for AI agents β€” designed in public, in months instead of years", + 'Protocols emerging in real time for AI agents β€” designed in public, in months instead of years', sections: [ { type: 'narrative', title: 'A New Family, Designed in Public', - text: `Almost every protocol in this app was designed by an IETF working group across years of drafts. **[[mcp|MCP]]** (Model Context Protocol) and **[[a2a|A2A]]** (Agent-to-Agent) are different. They emerged in 2024–2025, driven by single companies (Anthropic for MCP, Google for A2A), iterated in GitHub repos in weeks rather than working groups over years, and reached widespread adoption faster than any networking protocol in living memory.\n\nThey answer two adjacent but different questions:\n\n- **[[mcp|MCP]]** asks: *how does a single AI agent connect to its tools, data, and resources?* Anthropic published the spec in November 2024 as a JSON-RPC-based protocol for "letting models reach the world." A model wants to read a file? Call an MCP server that exposes filesystem operations. Query a database? Talk to a database MCP server. Read GitHub issues? GitHub ships an MCP server. The protocol standardizes the shape of "tool" so any model can use any tool that speaks the protocol.\n- **[[a2a|A2A]]** asks: *how do multiple AI agents work together?* Google announced it in April 2025 to handle the cross-agent case MCP intentionally doesn\'t address. A travel-planning agent needs to delegate flight booking to a flight-booking agent owned by a different vendor. A2A defines how agents discover each other, describe their capabilities, exchange messages, and hand off tasks.\n\nNeither protocol is finished. Both are likely to look quite different in two years. What\'s notable is *how fast* β€” and how visibly β€” they\'re being built. The repos are public; the design discussions are public; the implementations land within days of the spec changing. This is what protocol design looks like when speed-of-shipping matters as much as careful design.` + text: `Almost every protocol in this app was designed by an IETF working group across years of drafts. **[[mcp|MCP]]** (Model Context Protocol) and **[[a2a|A2A]]** (Agent-to-Agent) are different. They emerged in 2024–2025, driven by single companies (Anthropic for MCP, Google for A2A), iterated in GitHub repos in weeks rather than working groups over years, and reached widespread adoption faster than any networking protocol in living memory.\n\nThey answer two adjacent but different questions:\n\n- **[[mcp|MCP]]** asks: *how does a single AI agent connect to its tools, data, and resources?* Anthropic published the spec in November 2024 as a JSON-RPC-based protocol for "letting models reach the world." A model wants to read a file? Call an MCP server that exposes filesystem operations. Query a database? Talk to a database MCP server. Read GitHub issues? GitHub ships an MCP server. The protocol standardizes the shape of "tool" so any model can use any tool that speaks the protocol.\n- **[[a2a|A2A]]** asks: *how do multiple AI agents work together?* Google announced it in April 2025 to handle the cross-agent case MCP intentionally doesn't address. A travel-planning agent needs to delegate flight booking to a flight-booking agent owned by a different vendor. A2A defines how agents discover each other, describe their capabilities, exchange messages, and hand off tasks.\n\nNeither protocol is finished. Both are likely to look quite different in two years. What's notable is *how fast* β€” and how visibly β€” they're being built. The repos are public; the design discussions are public; the implementations land within days of the spec changing. This is what protocol design looks like when speed-of-shipping matters as much as careful design.` }, { type: 'pioneers', @@ -20,7 +20,7 @@ export const agentProtocolsStory: SubcategoryStory = { title: 'MCP Lead Designer', org: 'Anthropic', contribution: - "Led the [[mcp|MCP]] design and initial implementation at Anthropic, drawing on the Language Server Protocol (LSP) as a structural model β€” LSP standardized editor-to-language-server communication a decade ago, and MCP applies the same client-server-via-[[json-rpc|JSON-RPC]] pattern to AI tools. The November 2024 launch shipped reference servers (filesystem, GitHub, Slack, Postgres) alongside the spec, which mattered: people could *use* MCP the day it was announced." + 'Led the [[mcp|MCP]] design and initial implementation at Anthropic, drawing on the Language Server Protocol (LSP) as a structural model β€” LSP standardized editor-to-language-server communication a decade ago, and MCP applies the same client-server-via-[[json-rpc|JSON-RPC]] pattern to AI tools. The November 2024 launch shipped reference servers (filesystem, GitHub, Slack, Postgres) alongside the spec, which mattered: people could *use* MCP the day it was announced.' }, { name: 'Justin Hill', @@ -65,7 +65,7 @@ export const agentProtocolsStory: SubcategoryStory = { year: 2025, title: 'MCP Adoption Explodes (Q1)', description: - "Within months, MCP servers exist for GitHub, Slack, Linear, Notion, Postgres, Sentry, Figma, Stripe, Datadog, and ~hundreds more. Claude Desktop and Cursor ship MCP support. The protocol is shipping in production before the spec hits 1.0." + 'Within months, MCP servers exist for GitHub, Slack, Linear, Notion, Postgres, Sentry, Figma, Stripe, Datadog, and ~hundreds more. Claude Desktop and Cursor ship MCP support. The protocol is shipping in production before the spec hits 1.0.' }, { year: 2025, @@ -77,19 +77,19 @@ export const agentProtocolsStory: SubcategoryStory = { year: 2025, title: 'OpenAI Adopts MCP (March)', description: - 'OpenAI announces MCP support in the Agents SDK and ChatGPT desktop. Even Anthropic\'s competitor ships the Anthropic-designed protocol β€” a sign of how strong the network effect already is.' + "OpenAI announces MCP support in the Agents SDK and ChatGPT desktop. Even Anthropic's competitor ships the Anthropic-designed protocol β€” a sign of how strong the network effect already is." }, { year: 2025, title: 'MCP Spec Becomes 2025-06-18 / SEP Process', description: - "The protocol moves from rapid-iteration to a Specification Enhancement Proposal (SEP) process β€” explicit versioning, formal change control, multi-vendor governance discussions. Growing-up begins." + 'The protocol moves from rapid-iteration to a Specification Enhancement Proposal (SEP) process β€” explicit versioning, formal change control, multi-vendor governance discussions. Growing-up begins.' }, { year: 2025, title: 'A2A v0.2 (June)', description: - "A2A 0.2 adds richer streaming via [[sse|SSE]], improved task state model (submitted β†’ working β†’ completed/canceled/failed), and standardized agent cards for capability discovery. The first iteration that companies are running across vendor boundaries in production." + 'A2A 0.2 adds richer streaming via [[sse|SSE]], improved task state model (submitted β†’ working β†’ completed/canceled/failed), and standardized agent cards for capability discovery. The first iteration that companies are running across vendor boundaries in production.' } ] }, @@ -105,7 +105,7 @@ export const agentProtocolsStory: SubcategoryStory = { '[[json-rpc|JSON-RPC]] over stdio or HTTP+SSE', 'Resources, tools, prompts', 'Static config or registry; each client lists servers', - "~1 year old (Nov 2024); ecosystem of hundreds of servers" + '~1 year old (Nov 2024); ecosystem of hundreds of servers' ] }, { @@ -115,7 +115,7 @@ export const agentProtocolsStory: SubcategoryStory = { 'HTTP + SSE for streaming, JSON-RPC for messages', 'Tasks, messages, agent cards', 'Agent cards advertise capabilities (similar to OpenAPI)', - "~6 months old (Apr 2025); rapid early adoption" + '~6 months old (Apr 2025); rapid early adoption' ] } ], @@ -153,27 +153,27 @@ export const agentProtocolsStory: SubcategoryStory = { 5: 'Server returns a **list of available tools** with their JSON Schema input definitions. The host now knows exactly what the model can ask for.', 6: 'Host passes the **user message + tool catalog** to the model in a single LLM call. The model sees the available tools as if they were its own functions.', 7: 'Model decides to call **list_files**. This is a structured "tool_use" output β€” not free text β€” including the argument values.', - 8: 'Host translates the model\'s decision into **tools/call** on the MCP server. The model itself never sees the server.', + 8: "Host translates the model's decision into **tools/call** on the MCP server. The model itself never sees the server.", 9: 'Server executes the tool (reads the filesystem) and returns the **result** as text or structured content.', 10: 'Host feeds the **tool_result** back to the model as if completing the function call.', 11: 'Model produces a **natural-language response** describing the result. ("Your Documents folder has report.pdf, notes.md, ...")', - 12: 'Host delivers the **assistant message** to the user. From the user\'s perspective, it was one conversation.' + 12: "Host delivers the **assistant message** to the user. From the user's perspective, it was one conversation." } }, { type: 'callout', title: 'Why MCP Looks Like LSP', - text: `[[mcp|MCP]]\'s design is unusually clean for a year-old protocol. The reason is that it isn\'t really new. It\'s the **Language Server Protocol** (LSP) β€” the standard that lets VS Code use the same language servers as Vim, Sublime, Emacs, and JetBrains β€” with the editor swapped out for an AI model.\n\nLSP defines client/server roles, [[json-rpc|JSON-RPC]] message framing, capability negotiation during initialization, lifecycle methods (initialize, shutdown), notification vs request semantics, transport-agnostic operation (stdio or socket). MCP defines the same things with slightly different vocabulary: "tools" instead of "code actions," "resources" instead of "text documents," "prompts" instead of "snippets." The structural similarity is intentional.\n\nLSP shipped in 2016 and is now standard across every modern editor. The bet behind MCP is that the same architectural pattern β€” *standardize the protocol, let everyone implement their side* β€” will work for AI tools. So far the bet is paying off: an MCP server written for Claude works in Cursor, in GPT-4o\'s desktop client, in custom agents, and in third-party hosts, without any per-host adaptation. That is the LSP playbook running again.` + text: `[[mcp|MCP]]'s design is unusually clean for a year-old protocol. The reason is that it isn't really new. It's the **Language Server Protocol** (LSP) β€” the standard that lets VS Code use the same language servers as Vim, Sublime, Emacs, and JetBrains β€” with the editor swapped out for an AI model.\n\nLSP defines client/server roles, [[json-rpc|JSON-RPC]] message framing, capability negotiation during initialization, lifecycle methods (initialize, shutdown), notification vs request semantics, transport-agnostic operation (stdio or socket). MCP defines the same things with slightly different vocabulary: "tools" instead of "code actions," "resources" instead of "text documents," "prompts" instead of "snippets." The structural similarity is intentional.\n\nLSP shipped in 2016 and is now standard across every modern editor. The bet behind MCP is that the same architectural pattern β€” *standardize the protocol, let everyone implement their side* β€” will work for AI tools. So far the bet is paying off: an MCP server written for Claude works in Cursor, in GPT-4o's desktop client, in custom agents, and in third-party hosts, without any per-host adaptation. That is the LSP playbook running again.` }, { type: 'narrative', title: 'The Failure Modes', - text: `[[mcp|MCP]]\'s failure mode is **security**. The protocol gives models broad capability to take action β€” read files, call APIs, send emails. A model that has been prompt-injected (a malicious string in a document it reads) can use that capability against the user. The standard mitigations β€” user confirmation for sensitive actions, sandboxing, capability scoping β€” are not in the protocol; they\'re left to host apps to implement. Quality varies wildly. The category that the protocol enables β€” universal tool access for models β€” is exactly the category most ripe for abuse.\n\n[[a2a|A2A]]\'s failure mode is **delegation chains**. An agent delegates to another agent, which delegates to a third, which calls back to the first. Tracking what user authorized what, what data flows where, and who is liable when something goes wrong is genuinely unsolved. A2A\'s OAuth-based auth gives the basics β€” each delegation can be scoped β€” but the operational reality of "this prompt crossed five agent boundaries; which one hallucinated?" is hard.\n\nBoth families also share a **spec-velocity** failure mode: the protocol changes monthly, and implementations split between "current spec" and "the spec from when I wrote this." For a year or two this will continue; eventually the protocols will stabilize the way HTTP did, but we\'re not there yet.` + text: `[[mcp|MCP]]'s failure mode is **security**. The protocol gives models broad capability to take action β€” read files, call APIs, send emails. A model that has been prompt-injected (a malicious string in a document it reads) can use that capability against the user. The standard mitigations β€” user confirmation for sensitive actions, sandboxing, capability scoping β€” are not in the protocol; they're left to host apps to implement. Quality varies wildly. The category that the protocol enables β€” universal tool access for models β€” is exactly the category most ripe for abuse.\n\n[[a2a|A2A]]'s failure mode is **delegation chains**. An agent delegates to another agent, which delegates to a third, which calls back to the first. Tracking what user authorized what, what data flows where, and who is liable when something goes wrong is genuinely unsolved. A2A's OAuth-based auth gives the basics β€” each delegation can be scoped β€” but the operational reality of "this prompt crossed five agent boundaries; which one hallucinated?" is hard.\n\nBoth families also share a **spec-velocity** failure mode: the protocol changes monthly, and implementations split between "current spec" and "the spec from when I wrote this." For a year or two this will continue; eventually the protocols will stabilize the way HTTP did, but we're not there yet.` }, { type: 'narrative', - title: 'What\'s Next', - text: `Active work in 2025:\n\n- **MCP authorization** β€” the November 2024 spec was light on auth. The 2025-06 spec introduces standardized OAuth 2.1 flows for HTTP-transported MCP servers. Expect this to be a major focus through 2026.\n- **MCP for non-text resources** β€” current MCP is text-centric. Audio, images, structured binary, and streaming media are early targets. The protocol\'s extensibility (resources can be any MIME type) is the right shape; tooling has to catch up.\n- **A2A registries** β€” early A2A is mostly statically configured. A registry β€” a "DNS for agents" β€” is the obvious next step but raises hard governance questions about who runs it.\n- **Cross-protocol bridges** β€” agents that speak A2A to other agents and MCP to their own tools. The composition is the point; the bridges are non-trivial.\n- **Standards-body uptake** β€” both protocols are currently single-vendor. Anthropic and Google have both signaled openness to formal standards-body governance (W3C, IETF). Whether that happens, and when, will shape whether agent protocols become *the* interoperability layer or just *an* interoperability layer.\n\nThis is the first new protocol family in this app where the next chapter is genuinely unwritten. Check back in a year.` + title: "What's Next", + text: `Active work in 2025:\n\n- **MCP authorization** β€” the November 2024 spec was light on auth. The 2025-06 spec introduces standardized OAuth 2.1 flows for HTTP-transported MCP servers. Expect this to be a major focus through 2026.\n- **MCP for non-text resources** β€” current MCP is text-centric. Audio, images, structured binary, and streaming media are early targets. The protocol's extensibility (resources can be any MIME type) is the right shape; tooling has to catch up.\n- **A2A registries** β€” early A2A is mostly statically configured. A registry β€” a "DNS for agents" β€” is the obvious next step but raises hard governance questions about who runs it.\n- **Cross-protocol bridges** β€” agents that speak A2A to other agents and MCP to their own tools. The composition is the point; the bridges are non-trivial.\n- **Standards-body uptake** β€” both protocols are currently single-vendor. Anthropic and Google have both signaled openness to formal standards-body governance (W3C, IETF). Whether that happens, and when, will shape whether agent protocols become *the* interoperability layer or just *an* interoperability layer.\n\nThis is the first new protocol family in this app where the next chapter is genuinely unwritten. Check back in a year.` } ] }; diff --git a/src/lib/data/subcategory-stories/authentication.ts b/src/lib/data/subcategory-stories/authentication.ts index e0e4417..912c178 100644 --- a/src/lib/data/subcategory-stories/authentication.ts +++ b/src/lib/data/subcategory-stories/authentication.ts @@ -2,13 +2,12 @@ import type { SubcategoryStory } from './types'; export const authenticationStory: SubcategoryStory = { subcategoryId: 'authentication', - tagline: - "Proving who you are β€” tickets vs tokens, centralized realms vs federated delegation", + tagline: 'Proving who you are β€” tickets vs tokens, centralized realms vs federated delegation', sections: [ { type: 'narrative', title: 'Two Models, Forty Years Apart', - text: `Authentication has had two great architectural moments in computing history. The first was 1988 at MIT. The second was 2007 at Twitter.\n\n**MIT Project Athena** in the mid-1980s faced a problem few institutions faced at the time: tens of thousands of students, hundreds of shared workstations, dozens of services (mail, print, file storage, login). How does a workstation prove you\'re you to all those services without sending your password over the network β€” and without each service needing to know your password? The answer was **[[kerberos|Kerberos]]** (1988), a three-party protocol with a Key Distribution Center, time-stamped *tickets*, and mutual authentication. Kerberos was so good at the campus-scale problem that it became the basis for Windows Active Directory (1999) and remains the authentication backbone of every Windows enterprise environment today.\n\nNineteen years later, Twitter, Flickr, and Magnolia faced a different problem: how does a third-party app (a desktop Twitter client, a photo-uploading tool) get permission to act on behalf of a user *without that user handing over their password*? Users were giving the password directly to the third-party app, which would then call the API as the user β€” terrifying from a security perspective and impossible to audit. **[[oauth2|OAuth]]** (1.0 in 2010, 2.0 in 2012) is the protocol for *delegated authorization*: the user logs in to the service, grants specific permissions to the app, and the app receives a scoped *token* that lets it act within those limits.\n\nThese are different problems with the same name. Kerberos answers "is this user really alice@example.edu?" in a trusted realm. OAuth2 answers "did alice grant this app permission to read her tweets?" in an untrusted world of third-party developers. Both are alive in 2025; most enterprise login flows touch both β€” Kerberos for the SSO inside the corporate network, OAuth2 (and OIDC on top of it) for the SaaS apps the SSO federates out to.` + text: `Authentication has had two great architectural moments in computing history. The first was 1988 at MIT. The second was 2007 at Twitter.\n\n**MIT Project Athena** in the mid-1980s faced a problem few institutions faced at the time: tens of thousands of students, hundreds of shared workstations, dozens of services (mail, print, file storage, login). How does a workstation prove you're you to all those services without sending your password over the network β€” and without each service needing to know your password? The answer was **[[kerberos|Kerberos]]** (1988), a three-party protocol with a Key Distribution Center, time-stamped *tickets*, and mutual authentication. Kerberos was so good at the campus-scale problem that it became the basis for Windows Active Directory (1999) and remains the authentication backbone of every Windows enterprise environment today.\n\nNineteen years later, Twitter, Flickr, and Magnolia faced a different problem: how does a third-party app (a desktop Twitter client, a photo-uploading tool) get permission to act on behalf of a user *without that user handing over their password*? Users were giving the password directly to the third-party app, which would then call the API as the user β€” terrifying from a security perspective and impossible to audit. **[[oauth2|OAuth]]** (1.0 in 2010, 2.0 in 2012) is the protocol for *delegated authorization*: the user logs in to the service, grants specific permissions to the app, and the app receives a scoped *token* that lets it act within those limits.\n\nThese are different problems with the same name. Kerberos answers "is this user really alice@example.edu?" in a trusted realm. OAuth2 answers "did alice grant this app permission to read her tweets?" in an untrusted world of third-party developers. Both are alive in 2025; most enterprise login flows touch both β€” Kerberos for the SSO inside the corporate network, OAuth2 (and OIDC on top of it) for the SaaS apps the SSO federates out to.` }, { type: 'pioneers', @@ -30,7 +29,7 @@ export const authenticationStory: SubcategoryStory = { title: 'MIT Kerberos Lead', org: 'MIT', contribution: - 'Long-time maintainer of the MIT Kerberos reference implementation β€” the codebase that powers Active Directory, Hadoop, NFSv4 secure mode, and many enterprise SSO deployments. Hudson\'s sustained engineering on the protocol\'s reference implementation has kept Kerberos secure and interoperable for two decades after the original designers moved on.' + "Long-time maintainer of the MIT Kerberos reference implementation β€” the codebase that powers Active Directory, Hadoop, NFSv4 secure mode, and many enterprise SSO deployments. Hudson's sustained engineering on the protocol's reference implementation has kept Kerberos secure and interoperable for two decades after the original designers moved on." }, { name: 'Eran Hammer', @@ -38,7 +37,7 @@ export const authenticationStory: SubcategoryStory = { title: 'OAuth 1.0 Editor / OAuth 2.0 Critic', org: 'Independent', contribution: - "Edited the OAuth 1.0 specification ([[rfc:5849|RFC 5849]], 2010) and was the lead author through OAuth 2.0 drafts. Famously resigned from the OAuth 2.0 spec in July 2012 with a blog post (\"OAuth 2.0 and the Road to Hell\") arguing that the new spec was a developer-experience disaster: too many extension points, too many ways to do the same thing, no required signing, no built-in interop. The post is still cited as both \"why OAuth 2 is hard\" and \"why simple specs win.\"" + 'Edited the OAuth 1.0 specification ([[rfc:5849|RFC 5849]], 2010) and was the lead author through OAuth 2.0 drafts. Famously resigned from the OAuth 2.0 spec in July 2012 with a blog post ("OAuth 2.0 and the Road to Hell") arguing that the new spec was a developer-experience disaster: too many extension points, too many ways to do the same thing, no required signing, no built-in interop. The post is still cited as both "why OAuth 2 is hard" and "why simple specs win."' }, { name: 'Dick Hardt', @@ -46,7 +45,7 @@ export const authenticationStory: SubcategoryStory = { title: 'OAuth 2.0 Editor', org: 'Sxip / Microsoft', contribution: - "Took over from Hammer and shepherded [[oauth2|OAuth 2.0]] to publication ([[rfc:6749|RFC 6749]], 2012). Defended the framework-not-protocol approach: OAuth 2.0 is intentionally a toolkit because the use cases (server-to-server, browser app, mobile app, IoT) genuinely need different flows. The PKCE extension ([[rfc:7636|RFC 7636]], 2015) and OAuth 2.1 (consolidating best practices) are both responses to the worst of the 2012-era flexibility." + 'Took over from Hammer and shepherded [[oauth2|OAuth 2.0]] to publication ([[rfc:6749|RFC 6749]], 2012). Defended the framework-not-protocol approach: OAuth 2.0 is intentionally a toolkit because the use cases (server-to-server, browser app, mobile app, IoT) genuinely need different flows. The PKCE extension ([[rfc:7636|RFC 7636]], 2015) and OAuth 2.1 (consolidating best practices) are both responses to the worst of the 2012-era flexibility.' } ] }, @@ -57,13 +56,13 @@ export const authenticationStory: SubcategoryStory = { year: 1978, title: 'Needham-Schroeder Protocol', description: - "The academic foundation for ticket-based authentication. Subsequently shown to have a replay attack (1981) that the Lowe fix (1995) addressed. Kerberos is a Needham-Schroeder descendant with timestamps to prevent the attack." + 'The academic foundation for ticket-based authentication. Subsequently shown to have a replay attack (1981) that the Lowe fix (1995) addressed. Kerberos is a Needham-Schroeder descendant with timestamps to prevent the attack.' }, { year: 1988, title: 'Kerberos V4 at MIT', description: - "[[kerberos|Kerberos]] ships as part of MIT Project Athena. KDC, TGS, ticket-granting tickets, time-synchronized authentication. The model that defines authentication for the next 35 years." + '[[kerberos|Kerberos]] ships as part of MIT Project Athena. KDC, TGS, ticket-granting tickets, time-synchronized authentication. The model that defines authentication for the next 35 years.' }, { year: 1993, @@ -81,19 +80,19 @@ export const authenticationStory: SubcategoryStory = { year: 2007, title: 'OAuth Conceived', description: - "Blaine Cook (Twitter) and Chris Messina want to give third-party apps API access without sharing passwords. The proto-OAuth draft is sketched at a coffee shop. Within a year it\'s under IETF consideration." + "Blaine Cook (Twitter) and Chris Messina want to give third-party apps API access without sharing passwords. The proto-OAuth draft is sketched at a coffee shop. Within a year it's under IETF consideration." }, { year: 2010, title: 'OAuth 1.0a (RFC 5849)', description: - "OAuth 1.0a β€” fully spec\'d signature-based delegated auth. Used by Twitter, Flickr, Yahoo, Google\'s first public APIs." + "OAuth 1.0a β€” fully spec'd signature-based delegated auth. Used by Twitter, Flickr, Yahoo, Google's first public APIs." }, { year: 2012, title: 'OAuth 2.0 (RFC 6749)', description: - "[[oauth2|OAuth 2.0]] published. Framework rather than protocol β€” multiple grant types (authorization code, implicit, client credentials, password). Hammer publicly resigns as editor citing complexity and developer-experience concerns." + '[[oauth2|OAuth 2.0]] published. Framework rather than protocol β€” multiple grant types (authorization code, implicit, client credentials, password). Hammer publicly resigns as editor citing complexity and developer-experience concerns.' }, { year: 2014, @@ -105,7 +104,7 @@ export const authenticationStory: SubcategoryStory = { year: 2015, title: 'PKCE (RFC 7636)', description: - "PKCE β€” Proof Key for Code Exchange β€” extends OAuth 2.0 to protect public clients (mobile apps, SPAs) from authorization-code interception. Becomes the recommended pattern for all OAuth flows." + 'PKCE β€” Proof Key for Code Exchange β€” extends OAuth 2.0 to protect public clients (mobile apps, SPAs) from authorization-code interception. Becomes the recommended pattern for all OAuth flows.' }, { year: 2019, @@ -123,33 +122,39 @@ export const authenticationStory: SubcategoryStory = { year: 2025, title: 'OAuth 2.1 Stabilizes', description: - "OAuth 2.1 consolidates a decade of best-current-practice into one spec. Removes implicit and password grants. PKCE required for authorization-code flow. The standardization of \"how to do OAuth 2 safely\" instead of \"OAuth 2 plus six other RFCs.\"" + 'OAuth 2.1 consolidates a decade of best-current-practice into one spec. Removes implicit and password grants. PKCE required for authorization-code flow. The standardization of "how to do OAuth 2 safely" instead of "OAuth 2 plus six other RFCs."' } ] }, { type: 'comparison', title: 'Kerberos vs OAuth 2.0', - axes: ['Problem solved', 'Architecture', 'Credential', 'Time semantics', 'Where it dominates'], + axes: [ + 'Problem solved', + 'Architecture', + 'Credential', + 'Time semantics', + 'Where it dominates' + ], rows: [ { label: '[[kerberos|Kerberos]]', values: [ - '\"Authenticate this user to many services without sharing their password\"', + '"Authenticate this user to many services without sharing their password"', 'Three-party: client, KDC, service', 'Time-stamped tickets, short-lived', 'Tightly synchronized (clock skew > 5 min = ticket invalid)', - "Active Directory, Hadoop, NFS Kerberos mode, enterprise SSO inside corporate networks" + 'Active Directory, Hadoop, NFS Kerberos mode, enterprise SSO inside corporate networks' ] }, { label: '[[oauth2|OAuth 2.0]]', values: [ - '\"Let an app act on a user\'s behalf without that user giving up their password\"', + '"Let an app act on a user\'s behalf without that user giving up their password"', 'Three-party: user, authorization server, resource server', 'Bearer tokens (anyone with the token has the access)', 'Loose β€” tokens have an expiry, but no clock-sync requirement', - "Public-facing APIs, third-party app authorization, OIDC for federated login" + 'Public-facing APIs, third-party app authorization, OIDC for federated login' ] } ], @@ -178,38 +183,38 @@ export const authenticationStory: SubcategoryStory = { S-->>U: AP_REP β€” mutual-auth response Note over U,S: User and service share session key, further messages encrypted`, caption: - "The Kerberos flow has the classic \"three-headed dog\" structure: AS (initial authentication), TGS (service ticket distribution), and the actual service. The user's password never leaves the user's machine. The KDC holds keys for *everyone* (users and services), which is also why a KDC compromise is catastrophic.", + 'The Kerberos flow has the classic "three-headed dog" structure: AS (initial authentication), TGS (service ticket distribution), and the actual service. The user\'s password never leaves the user\'s machine. The KDC holds keys for *everyone* (users and services), which is also why a KDC compromise is catastrophic.', steps: { 0: '**Step 1 β€” Get a TGT.** Before the user can talk to *any* service, they need a Ticket Granting Ticket from the AS. This happens once per login session.', 1: 'User sends an **AS_REQ** identifying themselves. Importantly: this message does **not** contain the password.', - 2: '**AS looks up alice in its database**, retrieves her long-term key (derived from her password), and prepares a TGT encrypted under the TGS\'s own key (so only the TGS can read it later).', - 3: '**AS_REP** comes back with the TGT *plus* a session key, all encrypted under alice\'s password-derived key.', + 2: "**AS looks up alice in its database**, retrieves her long-term key (derived from her password), and prepares a TGT encrypted under the TGS's own key (so only the TGS can read it later).", + 3: "**AS_REP** comes back with the TGT *plus* a session key, all encrypted under alice's password-derived key.", 4: '**User decrypts with the password.** If the password was correct, the decryption succeeds and the user now holds a TGT plus session key. If the password was wrong, the bytes are garbage and the user knows immediately. The password never crossed the wire.', 5: '**Step 2 β€” Get a service ticket.** Now the user wants to talk to a specific service (say a file server). They go back to the KDC, but this time present their TGT.', - 6: 'User sends **TGS_REQ**: the TGT, a fresh authenticator (timestamp + checksum encrypted under the TGT\'s session key), and the name of the target service.', - 7: '**TGS validates the TGT** (it can, because TGT is encrypted under TGS\'s own key) and the authenticator (proving the request is fresh). It then mints a service ticket encrypted under the fileserver\'s key.', + 6: "User sends **TGS_REQ**: the TGT, a fresh authenticator (timestamp + checksum encrypted under the TGT's session key), and the name of the target service.", + 7: "**TGS validates the TGT** (it can, because TGT is encrypted under TGS's own key) and the authenticator (proving the request is fresh). It then mints a service ticket encrypted under the fileserver's key.", 8: '**TGS_REP** delivers the service ticket plus a new session key for the user↔fileserver conversation.', - 9: '**Step 3 β€” Use the service ticket.** The user now has everything needed to authenticate to the fileserver without the KDC\'s further involvement.', + 9: "**Step 3 β€” Use the service ticket.** The user now has everything needed to authenticate to the fileserver without the KDC's further involvement.", 10: 'User sends **AP_REQ** to the service: the service ticket plus a fresh authenticator. The service can decrypt the ticket (it has its own key) and validate the authenticator with the session key inside.', 11: '**Service validates the timestamp.** Authenticator timestamps must be within ~5 minutes β€” this is why Kerberos is allergic to clock skew.', - 12: 'Service replies with **AP_REP**, encrypting a value derived from the user\'s authenticator to prove mutual authentication (the user knows they\'re talking to the real fileserver, not an impostor).', + 12: "Service replies with **AP_REP**, encrypting a value derived from the user's authenticator to prove mutual authentication (the user knows they're talking to the real fileserver, not an impostor).", 13: 'From this point, **user and service share a session key** and can talk securely (or at least authenticated) for the lifetime of the service ticket β€” typically 8 to 24 hours.' } }, { type: 'callout', title: 'Why OAuth 2.0 Looks Like a Mess', - text: `If you\'ve ever tried to implement [[oauth2|OAuth 2.0]], you\'ve probably been confused. There are *four* grant types. Tokens come in *two* forms (access + refresh). There\'s ID Token on top via OpenID Connect. There\'s PKCE for public clients. There\'s dynamic client registration. There\'s the authorization endpoint, the token endpoint, the userinfo endpoint, the discovery endpoint. The total spec surface across OAuth 2.0 + OIDC + PKCE + Dynamic Registration is hundreds of pages.\n\nEran Hammer\'s 2012 resignation post β€” *"OAuth 2.0 and the Road to Hell"* β€” argued this was a disaster:\n\n> *"What I think will be the result is many vendors leveraging the framework, but very little interoperability. The market will need to consolidate on one or two specific implementations of OAuth 2.0... I just don\'t think it\'s going to be pretty."*\n\nThirteen years later, the prediction was right *and* wrong. Right: most OAuth 2.0 deployments use one of a small number of standard flows (authorization code with PKCE for web/mobile; client credentials for service-to-service; refresh tokens for long-lived access). Wrong: the patterns *did* consolidate. OAuth 2.1 is the spec that finally documents "the way it actually got done." If you implement OAuth 2.1 today, you can interop with almost anything.\n\nThe flexibility Hammer hated was the cost of OAuth 2.0\'s success: it\'s used by everything from a JavaScript SPA to an embedded device to a B2B API, and a single grant type couldn\'t serve all of those. The spec sprawl was the price; the market consolidation came eventually.` + text: `If you've ever tried to implement [[oauth2|OAuth 2.0]], you've probably been confused. There are *four* grant types. Tokens come in *two* forms (access + refresh). There's ID Token on top via OpenID Connect. There's PKCE for public clients. There's dynamic client registration. There's the authorization endpoint, the token endpoint, the userinfo endpoint, the discovery endpoint. The total spec surface across OAuth 2.0 + OIDC + PKCE + Dynamic Registration is hundreds of pages.\n\nEran Hammer's 2012 resignation post β€” *"OAuth 2.0 and the Road to Hell"* β€” argued this was a disaster:\n\n> *"What I think will be the result is many vendors leveraging the framework, but very little interoperability. The market will need to consolidate on one or two specific implementations of OAuth 2.0... I just don't think it's going to be pretty."*\n\nThirteen years later, the prediction was right *and* wrong. Right: most OAuth 2.0 deployments use one of a small number of standard flows (authorization code with PKCE for web/mobile; client credentials for service-to-service; refresh tokens for long-lived access). Wrong: the patterns *did* consolidate. OAuth 2.1 is the spec that finally documents "the way it actually got done." If you implement OAuth 2.1 today, you can interop with almost anything.\n\nThe flexibility Hammer hated was the cost of OAuth 2.0's success: it's used by everything from a JavaScript SPA to an embedded device to a B2B API, and a single grant type couldn't serve all of those. The spec sprawl was the price; the market consolidation came eventually.` }, { type: 'narrative', title: 'The Failure Modes', - text: `[[kerberos|Kerberos]]\'s failure mode is **clock skew**. Tickets are timestamped and have a hard validity window (default 5 minutes). If a client\'s clock drifts more than that from the KDC, every authentication fails with a cryptic error. The fix β€” NTP-sync everything β€” is universal in well-run environments. The pathological cases are battery-backed CMOS clocks dying on a VM after a long power-off; the entire host\'s Kerberos breaks until you fix the clock. (Microsoft\'s Windows Time Service exists largely to manage this for AD environments.)\n\nKerberos\' second failure mode is **the KDC as single point of failure**. The KDC holds the keys for every principal in the realm; if it dies, no one can authenticate. Active Directory uses domain controllers that replicate, but the dependency is real β€” a network partition that isolates a site from its KDCs degrades to "you can\'t log in" within ticket lifetime.\n\n[[oauth2|OAuth 2.0]]\'s failure mode is **bearer tokens**. The access token is a *bearer credential* β€” anyone holding it has the access. If your access token leaks (XSS, logged in error reports, stored in a wrong place), anyone with it can act as you until it expires. Mitigations: keep tokens short-lived (5–60 minutes), use refresh tokens with rotation, deploy DPoP (Demonstrating Proof-of-Possession) where the token is bound to a key the client holds. But "bearer tokens are bearer tokens" is the dominant production reality, and token exfiltration is the dominant OAuth attack class.\n\nBoth share a third failure mode: **the trusted-CA problem at scale**. Kerberos cross-realm trust is hand-configured between realms (manageable for a corporation, painful for a federation of universities). OAuth's federation depends on the user trusting that "Sign in with Google" really is Google, that the OIDC issuer is who it says it is. {{phishing|Phishing}} consent screens β€” fake login pages styled exactly like the real one β€” are the most common attack against OAuth in 2025.` + text: `[[kerberos|Kerberos]]'s failure mode is **clock skew**. Tickets are timestamped and have a hard validity window (default 5 minutes). If a client's clock drifts more than that from the KDC, every authentication fails with a cryptic error. The fix β€” NTP-sync everything β€” is universal in well-run environments. The pathological cases are battery-backed CMOS clocks dying on a VM after a long power-off; the entire host's Kerberos breaks until you fix the clock. (Microsoft's Windows Time Service exists largely to manage this for AD environments.)\n\nKerberos' second failure mode is **the KDC as single point of failure**. The KDC holds the keys for every principal in the realm; if it dies, no one can authenticate. Active Directory uses domain controllers that replicate, but the dependency is real β€” a network partition that isolates a site from its KDCs degrades to "you can't log in" within ticket lifetime.\n\n[[oauth2|OAuth 2.0]]'s failure mode is **bearer tokens**. The access token is a *bearer credential* β€” anyone holding it has the access. If your access token leaks (XSS, logged in error reports, stored in a wrong place), anyone with it can act as you until it expires. Mitigations: keep tokens short-lived (5–60 minutes), use refresh tokens with rotation, deploy DPoP (Demonstrating Proof-of-Possession) where the token is bound to a key the client holds. But "bearer tokens are bearer tokens" is the dominant production reality, and token exfiltration is the dominant OAuth attack class.\n\nBoth share a third failure mode: **the trusted-CA problem at scale**. Kerberos cross-realm trust is hand-configured between realms (manageable for a corporation, painful for a federation of universities). OAuth's federation depends on the user trusting that "Sign in with Google" really is Google, that the OIDC issuer is who it says it is. {{phishing|Phishing}} consent screens β€” fake login pages styled exactly like the real one β€” are the most common attack against OAuth in 2025.` }, { type: 'narrative', - title: 'What\'s Next', - text: `Active work in 2025:\n\n- **Passkeys and WebAuthn** are slowly displacing password-based authentication. Cross-device synced passkeys (Apple, Google, Microsoft, 1Password, Bitwarden) make WebAuthn UX usable by non-technical users. The "death of the password" has been promised for 20 years; it\'s finally happening for consumer logins.\n- **OAuth 2.1** consolidates best practices into one spec. Many libraries and providers already implement the 2.1 conservative subset.\n- **DPoP** (Demonstrating Proof-of-Possession, [[rfc:9449|RFC 9449]]) binds OAuth tokens to a client-held key. Mitigates the bearer-token leak problem. Adoption is uneven but growing.\n- **Sender-constrained access tokens** in general β€” TLS-bound, certificate-bound, or DPoP-bound β€” are the long-term answer to "bearer tokens are too easy to steal."\n- **Workload Identity Federation** lets cloud workloads (GCP, AWS, Azure VMs / containers) authenticate to *other* clouds without long-lived API keys. The OAuth pattern applied to machine-to-machine auth.\n- **The Kerberos slow decline** continues. Cloud-native deployments don\'t use it; new enterprise systems default to OIDC. Active Directory remains, but the action is in Entra ID and similar cloud SSO products that *speak* AD-compatible protocols at the edge while running OAuth+OIDC underneath.\n- **MCP and OAuth 2.0 convergence** β€” Anthropic\'s Model Context Protocol picked OAuth 2.1 + DCR (Dynamic Client Registration) as the auth model for remote MCP servers. The new agent ecosystem is being built on OAuth from day one.` + title: "What's Next", + text: `Active work in 2025:\n\n- **Passkeys and WebAuthn** are slowly displacing password-based authentication. Cross-device synced passkeys (Apple, Google, Microsoft, 1Password, Bitwarden) make WebAuthn UX usable by non-technical users. The "death of the password" has been promised for 20 years; it's finally happening for consumer logins.\n- **OAuth 2.1** consolidates best practices into one spec. Many libraries and providers already implement the 2.1 conservative subset.\n- **DPoP** (Demonstrating Proof-of-Possession, [[rfc:9449|RFC 9449]]) binds OAuth tokens to a client-held key. Mitigates the bearer-token leak problem. Adoption is uneven but growing.\n- **Sender-constrained access tokens** in general β€” TLS-bound, certificate-bound, or DPoP-bound β€” are the long-term answer to "bearer tokens are too easy to steal."\n- **Workload Identity Federation** lets cloud workloads (GCP, AWS, Azure VMs / containers) authenticate to *other* clouds without long-lived API keys. The OAuth pattern applied to machine-to-machine auth.\n- **The Kerberos slow decline** continues. Cloud-native deployments don't use it; new enterprise systems default to OIDC. Active Directory remains, but the action is in Entra ID and similar cloud SSO products that *speak* AD-compatible protocols at the edge while running OAuth+OIDC underneath.\n- **MCP and OAuth 2.0 convergence** β€” Anthropic's Model Context Protocol picked OAuth 2.1 + DCR (Dynamic Client Registration) as the auth model for remote MCP servers. The new agent ecosystem is being built on OAuth from day one.` } ] }; diff --git a/src/lib/data/subcategory-stories/conferencing-calls.ts b/src/lib/data/subcategory-stories/conferencing-calls.ts index 65c557d..1d98933 100644 --- a/src/lib/data/subcategory-stories/conferencing-calls.ts +++ b/src/lib/data/subcategory-stories/conferencing-calls.ts @@ -3,12 +3,12 @@ import type { SubcategoryStory } from './types'; export const conferencingCallsStory: SubcategoryStory = { subcategoryId: 'conferencing-calls', tagline: - "The full call stack β€” signaling, session description, media transport, and NAT traversal β€” composing into a browser-native call", + 'The full call stack β€” signaling, session description, media transport, and NAT traversal β€” composing into a browser-native call', sections: [ { type: 'narrative', title: 'The Anatomy of a Phone Call (Over IP)', - text: `Most protocols in this app do one thing. The conferencing family does four things, in concert. To make a video call between two browsers, four protocols have to cooperate:\n\n- **[[sip|SIP]]** is the **signaling**: setup, ring, accept, hang up. The phone-call equivalents of "your friend is calling," "they picked up," "they hung up." SIP doesn\'t carry voice or video β€” it only negotiates the session.\n- **[[sdp|SDP]]** is the **session description**: what codecs are available, what IP addresses to send media to, what encryption keys to use. SDP is the data; SIP is the envelope.\n- **[[rtp|RTP]]** is the **media transport**: the actual audio and video packets, with sequence numbers and timestamps for reconstruction.\n- **[[webrtc|WebRTC]]** is *all of the above*, packaged for the browser. Behind the WebRTC API, the browser does SDP offer/answer, ICE for NAT traversal, DTLS handshake for keys, SRTP for encrypted media. WebRTC didn\'t invent any of these protocols β€” it bundled them into something you can drive from JavaScript.\n\nThis layering is not accidental. It comes from a deep architectural decision the IETF made in the late 1990s: **separate signaling from media**. The phone networks tied them together (the same circuit carried both your "I want to call" and your voice). IP-based calling separated them so signaling could go through one path (often a server) while media could go peer-to-peer. The savings in core-network bandwidth at scale are enormous. The cost is that NAT traversal becomes everyone\'s problem β€” which is why the [[ice|ICE]] / [[stun|STUN]] / [[turn|TURN]] machinery exists.\n\nThe modern call from Zoom, Google Meet, Discord, Slack, WhatsApp video, FaceTime, Microsoft Teams β€” all of them use this stack. The branding differs; the bones are the same.` + text: `Most protocols in this app do one thing. The conferencing family does four things, in concert. To make a video call between two browsers, four protocols have to cooperate:\n\n- **[[sip|SIP]]** is the **signaling**: setup, ring, accept, hang up. The phone-call equivalents of "your friend is calling," "they picked up," "they hung up." SIP doesn't carry voice or video β€” it only negotiates the session.\n- **[[sdp|SDP]]** is the **session description**: what codecs are available, what IP addresses to send media to, what encryption keys to use. SDP is the data; SIP is the envelope.\n- **[[rtp|RTP]]** is the **media transport**: the actual audio and video packets, with sequence numbers and timestamps for reconstruction.\n- **[[webrtc|WebRTC]]** is *all of the above*, packaged for the browser. Behind the WebRTC API, the browser does SDP offer/answer, ICE for NAT traversal, DTLS handshake for keys, SRTP for encrypted media. WebRTC didn't invent any of these protocols β€” it bundled them into something you can drive from JavaScript.\n\nThis layering is not accidental. It comes from a deep architectural decision the IETF made in the late 1990s: **separate signaling from media**. The phone networks tied them together (the same circuit carried both your "I want to call" and your voice). IP-based calling separated them so signaling could go through one path (often a server) while media could go peer-to-peer. The savings in core-network bandwidth at scale are enormous. The cost is that NAT traversal becomes everyone's problem β€” which is why the [[nat-traversal|ICE]] / [[nat-traversal|STUN]] / [[nat-traversal|TURN]] machinery exists.\n\nThe modern call from Zoom, Google Meet, Discord, Slack, WhatsApp video, FaceTime, Microsoft Teams β€” all of them use this stack. The branding differs; the bones are the same.` }, { type: 'pioneers', @@ -50,7 +50,7 @@ export const conferencingCallsStory: SubcategoryStory = { year: 1996, title: 'RTP RFC 1889', description: - "[[pioneer:henning-schulzrinne|Schulzrinne]] and team publish [[rtp|RTP]] β€” Real-time Transport Protocol. Sequence numbers, timestamps, SSRC identifiers. Designed to ride on UDP for media." + '[[pioneer:henning-schulzrinne|Schulzrinne]] and team publish [[rtp|RTP]] β€” Real-time Transport Protocol. Sequence numbers, timestamps, SSRC identifiers. Designed to ride on UDP for media.' }, { year: 1996, @@ -62,55 +62,55 @@ export const conferencingCallsStory: SubcategoryStory = { year: 1999, title: 'SIP Becomes IETF Standard (RFC 2543)', description: - "The IETF response to H.323: [[sip|SIP]] β€” text-based, HTTP-inspired, much simpler. RFC 2543 published. The \"SIP vs H.323 wars\" begin and last about five years." + 'The IETF response to H.323: [[sip|SIP]] β€” text-based, HTTP-inspired, much simpler. RFC 2543 published. The "SIP vs H.323 wars" begin and last about five years.' }, { year: 2002, title: 'SIP RFC 3261', description: - "The revision that finalized SIP\'s shape. Within a few years, almost every IP-PBX (Asterisk, Cisco, Avaya), every soft-phone, and most enterprise VoIP runs SIP. H.323 fades." + "The revision that finalized SIP's shape. Within a few years, almost every IP-PBX (Asterisk, Cisco, Avaya), every soft-phone, and most enterprise VoIP runs SIP. H.323 fades." }, { year: 2003, title: 'Skype Launches', description: - "Skype ships using a fully proprietary peer-to-peer protocol β€” *not* SIP. The first widely-deployed consumer Internet calling, with its own ideas about NAT traversal and codecs. The lesson: a closed protocol with a great UX can crush an open one for years." + 'Skype ships using a fully proprietary peer-to-peer protocol β€” *not* SIP. The first widely-deployed consumer Internet calling, with its own ideas about NAT traversal and codecs. The lesson: a closed protocol with a great UX can crush an open one for years.' }, { year: 2005, title: 'STUN RFC 3489', description: - "[[stun|STUN]] β€” Session Traversal Utilities for NAT β€” lets a peer discover its public-facing IP address through a NAT. The first piece of NAT-traversal infrastructure for media protocols." + '[[nat-traversal|STUN]] β€” Session Traversal Utilities for NAT β€” lets a peer discover its public-facing IP address through a NAT. The first piece of NAT-traversal infrastructure for media protocols.' }, { year: 2010, title: 'WHATWG / W3C Start WebRTC', description: - "Google publishes the initial [[webrtc|WebRTC]] proposal at the W3C. The IETF charters the RTCWEB working group. The goal: browser-to-browser audio, video, and data without plugins." + 'Google publishes the initial [[webrtc|WebRTC]] proposal at the W3C. The IETF charters the RTCWEB working group. The goal: browser-to-browser audio, video, and data without plugins.' }, { year: 2013, title: 'WebRTC 1.0 Ships in Chrome and Firefox', description: - "Chrome and Firefox implement WebRTC for real-time media. The first cross-browser video calls without Flash or plugins. Hangouts moves from a custom plugin to WebRTC." + 'Chrome and Firefox implement WebRTC for real-time media. The first cross-browser video calls without Flash or plugins. Hangouts moves from a custom plugin to WebRTC.' }, { year: 2017, title: 'WebRTC 1.0 Becomes W3C Candidate Recommendation', description: - "After seven years of standardization, WebRTC 1.0 finalizes. Apple Safari ships WebRTC support, making it truly cross-browser. WebRTC becomes the default for video calling on the web." + 'After seven years of standardization, WebRTC 1.0 finalizes. Apple Safari ships WebRTC support, making it truly cross-browser. WebRTC becomes the default for video calling on the web.' }, { year: 2020, title: 'WebRTC Saves the Pandemic', description: - "COVID lockdowns push every video-calling product to record load. Zoom, Google Meet, Microsoft Teams, Jitsi all scale on infrastructure that\'s WebRTC at the edge (or close to it). The protocols designed for a few thousand simultaneous calls now carry hundreds of millions." + "COVID lockdowns push every video-calling product to record load. Zoom, Google Meet, Microsoft Teams, Jitsi all scale on infrastructure that's WebRTC at the edge (or close to it). The protocols designed for a few thousand simultaneous calls now carry hundreds of millions." }, { year: 2024, title: 'WebRTC over QUIC Experiments', description: - "WebTransport (QUIC streams in the browser) opens experiments with non-RTP media. WebCodecs API lets JavaScript directly encode and decode video frames. \"Custom WebRTC\" β€” using QUIC + WebCodecs instead of the built-in stack β€” appears in production at Google Stadia\'s successor projects and some streaming startups." + 'WebTransport (QUIC streams in the browser) opens experiments with non-RTP media. WebCodecs API lets JavaScript directly encode and decode video frames. "Custom WebRTC" β€” using QUIC + WebCodecs instead of the built-in stack β€” appears in production at Google Stadia\'s successor projects and some streaming startups.' } ] }, @@ -125,14 +125,14 @@ export const conferencingCallsStory: SubcategoryStory = { 'Signaling β€” call setup, teardown, control', 'Text (HTTP-like), runs over UDP/TCP/TLS/WebSocket', 'INVITE / 200 OK / ACK / BYE messages', - "SS7 setup messages (the telco signaling network)" + 'SS7 setup messages (the telco signaling network)' ] }, { label: '[[sdp|SDP]]', values: [ - 'Session description β€” \"what codecs, what addresses, what keys\"', - 'Text β€” \`v=\`, \`m=\`, \`c=\`, \`a=\` lines', + 'Session description β€” "what codecs, what addresses, what keys"', + 'Text β€” `v=`, `m=`, `c=`, `a=` lines', 'Capability negotiation, embedded in SIP messages', '(No PSTN equivalent β€” circuits had fixed capabilities)' ] @@ -152,11 +152,11 @@ export const conferencingCallsStory: SubcategoryStory = { 'Browser-native packaging of all of the above', 'JavaScript API + the protocols underneath', 'Audio, video, and data channels', - "(Browser API, not a PSTN equivalent)" + '(Browser API, not a PSTN equivalent)' ] } ], - note: "[[webrtc|WebRTC]] *contains* the other three. When you use \`RTCPeerConnection\`, the browser does SDP offer/answer, ICE/STUN/TURN for NAT, DTLS handshake, then sends SRTP-encrypted [[rtp|RTP]]. The signaling channel (how the two browsers exchange SDP) is *not* part of WebRTC β€” you bring your own, usually a WebSocket or a SIP-over-WebSocket gateway." + note: '[[webrtc|WebRTC]] *contains* the other three. When you use `RTCPeerConnection`, the browser does SDP offer/answer, ICE/STUN/TURN for NAT, DTLS handshake, then sends SRTP-encrypted [[rtp|RTP]]. The signaling channel (how the two browsers exchange SDP) is *not* part of WebRTC β€” you bring your own, usually a WebSocket or a SIP-over-WebSocket gateway.' }, { type: 'animated-sequence', @@ -195,12 +195,12 @@ export const conferencingCallsStory: SubcategoryStory = { A->>B: SRTP audio and video frames B-->>A: SRTP audio and video frames`, caption: - "The call setup is a five-phase dance. Signaling negotiates *what* (codecs, capabilities). ICE figures out *how* (which network path actually works). DTLS sets up *keys*. Only then does media (SRTP) start flowing. All of this happens behind a one-line JavaScript API.", + 'The call setup is a five-phase dance. Signaling negotiates *what* (codecs, capabilities). ICE figures out *how* (which network path actually works). DTLS sets up *keys*. Only then does media (SRTP) start flowing. All of this happens behind a one-line JavaScript API.', steps: { 0: '**Phase 1 β€” Signaling.** Before the two peers can talk to each other, they need a way to *exchange* setup info. WebRTC deliberately does not specify this β€” you bring your own (typically a WebSocket to a server you run).', 1: 'Browser A connects to the signaling server. Could be your chat backend, a Firebase channel, a custom WebSocket service.', 2: 'Browser B connects to the same signaling server.', - 3: '**Phase 2 β€” Offer / Answer.** SDP is the data format that describes a session: "I support these codecs, here\'s the cipher I propose, here\'s where I\'ll send media."', + 3: "**Phase 2 β€” Offer / Answer.** SDP is the data format that describes a session: \"I support these codecs, here's the cipher I propose, here's where I'll send media.\"", 4: 'Browser A calls `pc.createOffer()`. The browser produces an SDP describing its capabilities.', 5: 'A sends the offer to the signaling server β€” to be relayed to B.', 6: 'Signaling forwards the offer to B. (Signaling is just a pipe here; it does not understand SDP.)', @@ -209,16 +209,16 @@ export const conferencingCallsStory: SubcategoryStory = { 9: 'Signaling relays the answer to A. Both peers now have matching SDPs.', 10: '**Phase 3 β€” ICE candidate gathering.** Each peer now needs to discover what IP addresses and ports the *other* peer can actually reach it on. NAT makes this non-trivial.', 11: 'A asks STUN: **"what does my public address look like from outside the NAT?"**', - 12: 'STUN responds with A\'s server-reflexive candidate β€” its public IP and port.', + 12: "STUN responds with A's server-reflexive candidate β€” its public IP and port.", 13: 'A also asks TURN to **allocate a relay**, in case direct connectivity fails. TURN sits on a public address and forwards traffic.', 14: 'TURN gives A a **relayed candidate** β€” an address that, if B sends to it, will forward to A.', 15: 'A sends its candidates to B via signaling. (B does the same β€” abbreviated here.)', - 16: 'Signaling relays A\'s candidates to B.', + 16: "Signaling relays A's candidates to B.", 17: 'B sends its candidates back.', - 18: 'Signaling relays B\'s candidates to A. Both peers now know every possible address to try.', + 18: "Signaling relays B's candidates to A. Both peers now know every possible address to try.", 19: '**Phase 4 β€” Connectivity checks.** Each peer pings every candidate pair with STUN binding requests to find which path actually works.', - 20: 'A sends a STUN binding to B\'s direct address. (If A and B can\'t reach each other directly, this fails and ICE falls back to a TURN-relayed pair.)', - 21: 'B responds. **A direct path works** β€” the most expensive path (TURN relay) won\'t be needed for this call.', + 20: "A sends a STUN binding to B's direct address. (If A and B can't reach each other directly, this fails and ICE falls back to a TURN-relayed pair.)", + 21: "B responds. **A direct path works** β€” the most expensive path (TURN relay) won't be needed for this call.", 22: '**TURN not needed.** ~75% of WebRTC calls find a direct path; the rest fall back to TURN at the cost of double bandwidth.', 23: '**Phase 5 β€” Media flows.** Before audio/video can be sent, the two peers exchange DTLS handshakes to derive SRTP keys. *No* keys are sent in cleartext.', 24: 'A initiates the **DTLS handshake** directly with B (no third party). The result is a pair of SRTP keys.', @@ -229,17 +229,17 @@ export const conferencingCallsStory: SubcategoryStory = { { type: 'callout', title: 'NAT Traversal Is the Hard Part', - text: `Most of the engineering complexity in modern video calling isn\'t the codecs or the protocols. It\'s **NAT traversal**.\n\nMost browsers running video calls are behind home routers, corporate firewalls, or carrier-grade NATs. None of them have a public IP. None of them can be directly contacted from the outside Internet. So how do two peers behind NATs send packets directly to each other? The answer is the {{ice|ICE}} framework, composed of:\n\n- **{{stun|STUN}}** β€” a tiny protocol where a peer asks a public server "what does my public IP and port look like to you?" The server replies with the address as seen from outside the NAT. The peer now knows its server-reflexive candidate.\n- **{{turn|TURN}}** β€” when direct connectivity is impossible (symmetric NAT, restrictive firewall), TURN relays the media through a public server. Both peers send media to TURN; TURN forwards to the other peer. Works but doubles the bandwidth cost and adds latency.\n- **ICE** β€” the framework that gathers all possible candidates (host, server-reflexive, relayed), exchanges them via signaling, and probes pairwise connectivity to pick the best working path.\n\nIn production, ICE finds a direct path for ~75% of WebRTC calls (host-to-host or via STUN). The remaining ~25% require TURN relay. TURN servers are expensive (they pay for the relay bandwidth) and are why running a self-hosted Jitsi or Asterisk involves more than spinning up one box.\n\nNAT traversal is also why peer-to-peer messaging at scale (BitTorrent, blockchain peer discovery, IPFS) ends up looking suspiciously similar to WebRTC underneath. The problem is the same: how to find a direct path through hostile middleboxes.` + text: `Most of the engineering complexity in modern video calling isn't the codecs or the protocols. It's **NAT traversal**.\n\nMost browsers running video calls are behind home routers, corporate firewalls, or carrier-grade NATs. None of them have a public IP. None of them can be directly contacted from the outside Internet. So how do two peers behind NATs send packets directly to each other? The answer is the {{ice|ICE}} framework, composed of:\n\n- **{{stun|STUN}}** β€” a tiny protocol where a peer asks a public server "what does my public IP and port look like to you?" The server replies with the address as seen from outside the NAT. The peer now knows its server-reflexive candidate.\n- **{{turn|TURN}}** β€” when direct connectivity is impossible (symmetric NAT, restrictive firewall), TURN relays the media through a public server. Both peers send media to TURN; TURN forwards to the other peer. Works but doubles the bandwidth cost and adds latency.\n- **ICE** β€” the framework that gathers all possible candidates (host, server-reflexive, relayed), exchanges them via signaling, and probes pairwise connectivity to pick the best working path.\n\nIn production, ICE finds a direct path for ~75% of WebRTC calls (host-to-host or via STUN). The remaining ~25% require TURN relay. TURN servers are expensive (they pay for the relay bandwidth) and are why running a self-hosted Jitsi or Asterisk involves more than spinning up one box.\n\nNAT traversal is also why peer-to-peer messaging at scale (BitTorrent, blockchain peer discovery, IPFS) ends up looking suspiciously similar to WebRTC underneath. The problem is the same: how to find a direct path through hostile middleboxes.` }, { type: 'narrative', title: 'The Failure Modes', - text: `[[sip|SIP]]\'s failure mode is **dialogs through middleboxes**. SIP messages reference IP addresses and ports in their body (in SDP and in headers like Contact, Via, Record-Route). Every NAT, firewall, or SIP-aware proxy in the path may need to rewrite these. SIP-ALG (Application Layer Gateway) implementations in consumer routers are notoriously buggy β€” they break calls more often than they help. The standard advice in the VoIP industry is "disable SIP-ALG on your router."\n\n[[rtp|RTP]]\'s failure mode is **jitter and loss**. Real-time media can\'t wait for retransmission β€” by the time TCP would have re-sent a lost frame, the user has heard the gap. Solutions include forward error correction (RTP FEC), packet-loss concealment (the codec guesses what the missing frame sounded like), and adaptive jitter buffers. WebRTC\'s built-in stack handles a lot of this automatically, which is part of why "use WebRTC" is the right answer instead of "use RTP directly" for most teams.\n\n[[webrtc|WebRTC]]\'s failure mode is **complexity**. WebRTC is "easy" in the sense that the browser API is small. It is brutally hard once you go beyond simple peer-to-peer: scaling to many participants (you need an SFU β€” Selective Forwarding Unit, like Jitsi, mediasoup, LiveKit), recording, simulcast/SVC for bandwidth adaptation, network resilience for cellular. Most products that "use WebRTC" actually use WebRTC at the browser and a complex media server (often based on libwebrtc) behind the scenes. The "peer-to-peer" promise is true for 1:1 calls and rare for group calls.` + text: `[[sip|SIP]]'s failure mode is **dialogs through middleboxes**. SIP messages reference IP addresses and ports in their body (in SDP and in headers like Contact, Via, Record-Route). Every NAT, firewall, or SIP-aware proxy in the path may need to rewrite these. SIP-ALG (Application Layer Gateway) implementations in consumer routers are notoriously buggy β€” they break calls more often than they help. The standard advice in the VoIP industry is "disable SIP-ALG on your router."\n\n[[rtp|RTP]]'s failure mode is **jitter and loss**. Real-time media can't wait for retransmission β€” by the time TCP would have re-sent a lost frame, the user has heard the gap. Solutions include forward error correction (RTP FEC), packet-loss concealment (the codec guesses what the missing frame sounded like), and adaptive jitter buffers. WebRTC's built-in stack handles a lot of this automatically, which is part of why "use WebRTC" is the right answer instead of "use RTP directly" for most teams.\n\n[[webrtc|WebRTC]]'s failure mode is **complexity**. WebRTC is "easy" in the sense that the browser API is small. It is brutally hard once you go beyond simple peer-to-peer: scaling to many participants (you need an SFU β€” Selective Forwarding Unit, like Jitsi, mediasoup, LiveKit), recording, simulcast/SVC for bandwidth adaptation, network resilience for cellular. Most products that "use WebRTC" actually use WebRTC at the browser and a complex media server (often based on libwebrtc) behind the scenes. The "peer-to-peer" promise is true for 1:1 calls and rare for group calls.` }, { type: 'narrative', - title: 'What\'s Next', - text: `Active work in 2025:\n\n- **WebRTC + WebCodecs + WebTransport** β€” the "custom WebRTC" pattern where apps bypass the built-in stack and assemble their own from lower-level browser primitives. Better control over codecs, latency, and bandwidth β€” at the cost of reimplementing what WebRTC gave you for free.\n- **AV1 in WebRTC** β€” Chrome and Firefox now negotiate AV1 by default for screen sharing; software encoders are catching up for video. ~30% bandwidth savings at the same quality.\n- **AI noise suppression and background blur** moved to client-side TensorFlow.js or native models. Krisp, NVIDIA Maxine, and built-in Zoom/Teams/Meet features all happen *before* the codec sees the frame β€” turning bad audio into clean audio invisibly.\n- **Spatial audio** in conferencing (Zoom, Teams) places each participant in 3D space. Reduces fatigue at the cost of more processing per stream.\n- **Real-time AI voice** (OpenAI Realtime API, Google Gemini Live, ElevenLabs streaming) is the new "what does the call stack do?" question. The answer: probably WebRTC, plus WebSocket or QUIC for the AI side. The stack designed for human-to-human is now carrying human-to-AI calls at growing scale.\n- **WHIP / WHEP** (WebRTC ingest and egress over HTTP) β€” the same simplification that\'s replacing RTMP for ingestion may eventually displace SIP for one-way broadcasting too.` + title: "What's Next", + text: `Active work in 2025:\n\n- **WebRTC + WebCodecs + WebTransport** β€” the "custom WebRTC" pattern where apps bypass the built-in stack and assemble their own from lower-level browser primitives. Better control over codecs, latency, and bandwidth β€” at the cost of reimplementing what WebRTC gave you for free.\n- **AV1 in WebRTC** β€” Chrome and Firefox now negotiate AV1 by default for screen sharing; software encoders are catching up for video. ~30% bandwidth savings at the same quality.\n- **AI noise suppression and background blur** moved to client-side TensorFlow.js or native models. Krisp, NVIDIA Maxine, and built-in Zoom/Teams/Meet features all happen *before* the codec sees the frame β€” turning bad audio into clean audio invisibly.\n- **Spatial audio** in conferencing (Zoom, Teams) places each participant in 3D space. Reduces fatigue at the cost of more processing per stream.\n- **Real-time AI voice** (OpenAI Realtime API, Google Gemini Live, ElevenLabs streaming) is the new "what does the call stack do?" question. The answer: probably WebRTC, plus WebSocket or QUIC for the AI side. The stack designed for human-to-human is now carrying human-to-AI calls at growing scale.\n- **WHIP / WHEP** (WebRTC ingest and egress over HTTP) β€” the same simplification that's replacing RTMP for ingestion may eventually displace SIP for one-way broadcasting too.` } ] }; diff --git a/src/lib/data/subcategory-stories/datagram-transport.ts b/src/lib/data/subcategory-stories/datagram-transport.ts index bb56834..95a25a4 100644 --- a/src/lib/data/subcategory-stories/datagram-transport.ts +++ b/src/lib/data/subcategory-stories/datagram-transport.ts @@ -3,7 +3,7 @@ import type { SubcategoryStory } from './types'; export const datagramTransportStory: SubcategoryStory = { subcategoryId: 'datagram-transport', tagline: - "Going raw β€” or building something better in user space β€” on top of {{ip|IP}}'s native datagrams", + "Going raw β€” or building something better in user space β€” on top of [[ip|IP]]'s native datagrams", sections: [ { type: 'narrative', @@ -32,7 +32,7 @@ export const datagramTransportStory: SubcategoryStory = { title: 'Designer of QUIC', org: 'Google', contribution: - 'Started [[quic|QUIC]] at Google in 2012 to fix [[tcp|TCP]]\'s deployment problems: kernel ossification, [[head-of-line-blocking|HoL blocking]], and the slow rollout of TLS 1.3. Roskind\'s key bet was that the transport layer could be *re-implemented in user space* β€” ship updates with the browser, escape the kernel\'s deployment cycle. By 2017, Google reported ~7% of all Internet traffic was already QUIC. The {{ietf|IETF}} chartered the QUIC WG in 2016; [[rfc:9000|RFC 9000]] published in 2021.', + "Started [[quic|QUIC]] at Google in 2012 to fix [[tcp|TCP]]'s deployment problems: kernel ossification, {{head-of-line-blocking|HoL blocking}}, and the slow rollout of TLS 1.3. Roskind's key bet was that the transport layer could be *re-implemented in user space* β€” ship updates with the browser, escape the kernel's deployment cycle. By 2017, Google reported ~7% of all Internet traffic was already QUIC. The {{ietf|IETF}} chartered the QUIC WG in 2016; [[rfc:9000|RFC 9000]] published in 2021.", imagePath: 'https://upload.wikimedia.org/wikipedia/commons/thumb/c/c7/Jim_Roskind_2016.jpg/330px-Jim_Roskind_2016.jpg' }, @@ -54,7 +54,7 @@ export const datagramTransportStory: SubcategoryStory = { year: 1980, title: 'UDP Standardized (RFC 768)', description: - '[[pioneer:jon-postel|Postel]]\'s 3-page spec defines the simplest possible transport: 8-byte header, no state, no guarantees.' + "[[pioneer:jon-postel|Postel]]'s 3-page spec defines the simplest possible transport: 8-byte header, no state, no guarantees." }, { year: 1983, @@ -72,7 +72,7 @@ export const datagramTransportStory: SubcategoryStory = { year: 2008, title: 'NAT Traversal via UDP Hole Punching', description: - '{{ice|ICE}} (RFC 5245) and {{stun|STUN}}/{{turn|TURN}} establish that peer-to-peer connectivity requires UDP. [[webrtc|WebRTC]], P2P games, and (later) BitTorrent all rely on UDP\'s lighter NAT footprint.' + "{{ice|ICE}} (RFC 5245) and {{stun|STUN}}/{{turn|TURN}} establish that peer-to-peer connectivity requires UDP. [[webrtc|WebRTC]], P2P games, and (later) BitTorrent all rely on UDP's lighter NAT footprint." }, { year: 2012, @@ -102,7 +102,7 @@ export const datagramTransportStory: SubcategoryStory = { year: 2024, title: 'MASQUE Published', description: - 'Tunneling arbitrary traffic inside QUIC β€” used by iCloud Private Relay, Apple Private Cloud Compute, and Cloudflare\'s Privacy Gateway.' + "Tunneling arbitrary traffic inside QUIC β€” used by iCloud Private Relay, Apple Private Cloud Compute, and Cloudflare's Privacy Gateway." } ] }, @@ -115,7 +115,7 @@ export const datagramTransportStory: SubcategoryStory = { label: '[[udp|UDP]]', values: [ 'None β€” fire and forget', - 'None (application\'s problem β€” e.g. DTLS)', + "None (application's problem β€” e.g. DTLS)", 'None β€” opaque datagrams', "Application's problem", '[[dns|DNS]], [[ntp|NTP]], [[rtp|RTP]], multicast, games' @@ -154,13 +154,13 @@ export const datagramTransportStory: SubcategoryStory = { C->>S: 0-RTT application data using cached keys S-->>C: 1-RTT response`, caption: - "[[udp|UDP]] makes the application do everything. [[quic|QUIC]] bundles handshake + encryption + transport into a single round trip, and zero round trips on resumption. The cost: every QUIC implementation re-implements reliable transport in user space.", + '[[udp|UDP]] makes the application do everything. [[quic|QUIC]] bundles handshake + encryption + transport into a single round trip, and zero round trips on resumption. The cost: every QUIC implementation re-implements reliable transport in user space.', steps: { - 0: '**[[udp|UDP]] β€” zero handshake.** No connection setup at all. The first datagram carries the application\'s actual payload. If the network drops it, the application learns about it (or doesn\'t) on its own schedule.', + 0: "**[[udp|UDP]] β€” zero handshake.** No connection setup at all. The first datagram carries the application's actual payload. If the network drops it, the application learns about it (or doesn't) on its own schedule.", 1: 'Client sends a **UDP datagram**. 8-byte header, payload, done.', 2: '**No ACK is expected.** The kernel washes its hands of the packet the moment it leaves the NIC.', 3: '**No retransmit happens at the transport layer.** If anything needs to retry, the application has to do it.', - 4: 'Server replies if it wants to. That reply, too, is fire-and-forget β€” either it arrives or it doesn\'t.', + 4: "Server replies if it wants to. That reply, too, is fire-and-forget β€” either it arrives or it doesn't.", 5: '**[[quic|QUIC]] 1-RTT.** Unlike UDP, QUIC builds a real, encrypted, multiplexed transport on top β€” but it does the entire handshake in ONE round trip. Compare to TLS-over-TCP, which needs 3 (TCP SYN/SYN-ACK/ACK plus TLS handshake).', 6: 'Client sends **Initial: ClientHello + QUIC params**. The first packet carries the TLS 1.3 ClientHello *and* QUIC transport parameters. Some of the packet is even encrypted (anti-injection), though the keys come from a public derivation.', 7: 'Server responds with **Initial: ServerHello + Handshake**. Now both sides have ephemeral keys and can encrypt the handshake fully. This is the same packet that contains the server certificate.', @@ -174,17 +174,17 @@ export const datagramTransportStory: SubcategoryStory = { { type: 'callout', title: 'Protocol Ossification β€” Why QUIC Runs on UDP', - text: `Here\'s the dirty secret of the modern Internet: **[[tcp|TCP]] cannot evolve**. Try to add a new TCP option, and a measurable fraction of the Internet silently drops your packets. Try to enable a new TCP feature (Multipath TCP, fast open, ECN), and middleboxes β€” firewalls, NATs, load balancers, deep-packet-inspection appliances β€” will reject or strip it.\n\nMiddleboxes do this because they read TCP headers and reject anything that doesn\'t look like what they remember from 2003. Once enough middleboxes do this, the protocol *fossilizes* β€” even though the wire format is supposed to be extensible, in practice it isn\'t.\n\n[[quic|QUIC]]\'s defense is total: encrypt the transport headers. Middleboxes see a UDP packet to port 443 and nothing else. They cannot inspect QUIC framing, cannot strip new fields they don\'t recognize, cannot reject features they don\'t understand. The cost of that defense is a re-implementation of reliable transport in user space β€” but the reward is **a transport protocol that can change**.` + text: `Here's the dirty secret of the modern Internet: **[[tcp|TCP]] cannot evolve**. Try to add a new TCP option, and a measurable fraction of the Internet silently drops your packets. Try to enable a new TCP feature (Multipath TCP, fast open, ECN), and middleboxes β€” firewalls, NATs, load balancers, deep-packet-inspection appliances β€” will reject or strip it.\n\nMiddleboxes do this because they read TCP headers and reject anything that doesn't look like what they remember from 2003. Once enough middleboxes do this, the protocol *fossilizes* β€” even though the wire format is supposed to be extensible, in practice it isn't.\n\n[[quic|QUIC]]'s defense is total: encrypt the transport headers. Middleboxes see a UDP packet to port 443 and nothing else. They cannot inspect QUIC framing, cannot strip new fields they don't recognize, cannot reject features they don't understand. The cost of that defense is a re-implementation of reliable transport in user space β€” but the reward is **a transport protocol that can change**.` }, { type: 'narrative', title: 'The Failure Mode', - text: `[[udp|UDP]]\'s failure mode is *the application got it wrong*. Without congestion control, a UDP application that retries too aggressively can melt a network. [[dns|DNS]] amplification attacks weaponize UDP\'s lack of state: spoof a victim\'s address as the source of a 64-byte DNS query, and the open resolver replies with a 4 KB response *to the victim*. The amplification ratio enables 600 Gbps DDoS attacks from modest botnets.\n\n[[quic|QUIC]]\'s failure mode is **CPU**. Each QUIC connection does its own encryption, congestion control, and packet processing in user space. A kernel TCP stack benefits from decades of optimization (TSO, GRO, zero-copy); QUIC implementations are still catching up. Cloudflare measured QUIC at ~3.5Γ— the CPU cost of TLS-over-TCP at equivalent throughput in 2024. Hardware offload for QUIC is the active frontier β€” Intel and AMD shipped first-pass QUIC NIC offloads in 2024.` + text: `[[udp|UDP]]'s failure mode is *the application got it wrong*. Without congestion control, a UDP application that retries too aggressively can melt a network. [[dns|DNS]] amplification attacks weaponize UDP's lack of state: spoof a victim's address as the source of a 64-byte DNS query, and the open resolver replies with a 4 KB response *to the victim*. The amplification ratio enables 600 Gbps DDoS attacks from modest botnets.\n\n[[quic|QUIC]]'s failure mode is **CPU**. Each QUIC connection does its own encryption, congestion control, and packet processing in user space. A kernel TCP stack benefits from decades of optimization (TSO, GRO, zero-copy); QUIC implementations are still catching up. Cloudflare measured QUIC at ~3.5Γ— the CPU cost of TLS-over-TCP at equivalent throughput in 2024. Hardware offload for QUIC is the active frontier β€” Intel and AMD shipped first-pass QUIC NIC offloads in 2024.` }, { type: 'narrative', - title: 'What\'s Next', - text: `Active work in 2025:\n\n- **Multipath QUIC** β€” bonding multiple network paths into one QUIC connection, like [[mptcp|MPTCP]] but easier because QUIC isn\'t bound to TCP\'s wire format. Draft in WG, deployment underway at Apple and Cloudflare.\n- **MASQUE** β€” running arbitrary protocols (TCP, UDP, IP) inside QUIC for tunneling. Powers iCloud Private Relay and similar privacy infrastructure.\n- **WebTransport** β€” exposes QUIC streams to browsers, a likely successor to {{websockets|WebSockets}} for low-latency bidirectional traffic.\n- **Media-over-QUIC** β€” a new family of standards for live and on-demand media that bypasses RTP/RTMP/HLS entirely.\n- **QUIC offload silicon** β€” first-generation NIC support landing in 2024–2026, closing the CPU-cost gap with TCP.\n\nUDP itself isn\'t evolving β€” that\'s the point. It is the stable substrate. The action is one layer up.` + title: "What's Next", + text: `Active work in 2025:\n\n- **Multipath QUIC** β€” bonding multiple network paths into one QUIC connection, like [[mptcp|MPTCP]] but easier because QUIC isn't bound to TCP's wire format. Draft in WG, deployment underway at Apple and Cloudflare.\n- **MASQUE** β€” running arbitrary protocols (TCP, UDP, IP) inside QUIC for tunneling. Powers iCloud Private Relay and similar privacy infrastructure.\n- **WebTransport** β€” exposes QUIC streams to browsers, a likely successor to [[websockets|WebSockets]] for low-latency bidirectional traffic.\n- **Media-over-QUIC** β€” a new family of standards for live and on-demand media that bypasses RTP/RTMP/HLS entirely.\n- **QUIC offload silicon** β€” first-generation NIC support landing in 2024–2026, closing the CPU-cost gap with TCP.\n\nUDP itself isn't evolving β€” that's the point. It is the stable substrate. The action is one layer up.` } ] }; diff --git a/src/lib/data/subcategory-stories/enterprise-brokers.ts b/src/lib/data/subcategory-stories/enterprise-brokers.ts index 4ab8d25..d0edb35 100644 --- a/src/lib/data/subcategory-stories/enterprise-brokers.ts +++ b/src/lib/data/subcategory-stories/enterprise-brokers.ts @@ -3,19 +3,19 @@ import type { SubcategoryStory } from './types'; export const enterpriseBrokersStory: SubcategoryStory = { subcategoryId: 'enterprise-brokers', tagline: - "Decoupling producers from consumers at scale β€” queues, immutable logs, and the wire formats that talk to them", + 'Decoupling producers from consumers at scale β€” queues, immutable logs, and the wire formats that talk to them', sections: [ { type: 'narrative', title: 'Two Philosophies, One Family', - text: `In 1992, IBM shipped MQSeries β€” software that let one program send a message to another *without either knowing about the other*. The producer wrote to a queue; the consumer read from it; the broker in the middle handled persistence, ordering, and failure. This idea β€” **message-oriented middleware** β€” was strange to most programmers in an era when "calling a function" still meant calling a function on the same machine. By 2005 it was running global banks, airlines, and stock exchanges.\n\nEnterprise messaging splits into two philosophies:\n\n- **Queues** β€” a message goes in, one consumer takes it out, it\'s gone. This is the MQSeries model, standardized as **[[amqp|AMQP]]** ([[rfc:0|0-9-1 in 2008, 1.0 in 2011]]). RabbitMQ is the dominant open-source implementation. The mental model: a worker pool draining a backlog.\n- **Logs** β€” a message goes in, *every* consumer can read it, at any offset, forever (or until retention expires). This is the **[[kafka|Kafka]]** model, born at LinkedIn in 2011 and now ubiquitous. The mental model: an append-only stream of events that anyone can replay.\n\nBoth ship at planetary scale; both have decades of stories about teams that picked the wrong one and rebuilt. Queues are great when each message must be processed exactly once and order between consumers doesn\'t matter. Logs are great when many independent systems need to react to the same stream of events at their own pace.\n\nA third member of the family, **[[stomp|STOMP]]**, isn\'t a broker β€” it\'s a *wire format* for talking to brokers. Simple Text-Oriented Messaging Protocol: human-readable frames over TCP. ActiveMQ, RabbitMQ, and HornetQ all speak STOMP. It\'s the lingua franca for clients (especially browsers via WebSocket) that don\'t want to ship a full AMQP or Kafka library.` + text: `In 1992, IBM shipped MQSeries β€” software that let one program send a message to another *without either knowing about the other*. The producer wrote to a queue; the consumer read from it; the broker in the middle handled persistence, ordering, and failure. This idea β€” **message-oriented middleware** β€” was strange to most programmers in an era when "calling a function" still meant calling a function on the same machine. By 2005 it was running global banks, airlines, and stock exchanges.\n\nEnterprise messaging splits into two philosophies:\n\n- **Queues** β€” a message goes in, one consumer takes it out, it's gone. This is the MQSeries model, standardized as **[[amqp|AMQP]]** ([[rfc:0|0-9-1 in 2008, 1.0 in 2011]]). RabbitMQ is the dominant open-source implementation. The mental model: a worker pool draining a backlog.\n- **Logs** β€” a message goes in, *every* consumer can read it, at any offset, forever (or until retention expires). This is the **[[kafka|Kafka]]** model, born at LinkedIn in 2011 and now ubiquitous. The mental model: an append-only stream of events that anyone can replay.\n\nBoth ship at planetary scale; both have decades of stories about teams that picked the wrong one and rebuilt. Queues are great when each message must be processed exactly once and order between consumers doesn't matter. Logs are great when many independent systems need to react to the same stream of events at their own pace.\n\nA third member of the family, **[[stomp|STOMP]]**, isn't a broker β€” it's a *wire format* for talking to brokers. Simple Text-Oriented Messaging Protocol: human-readable frames over TCP. ActiveMQ, RabbitMQ, and HornetQ all speak STOMP. It's the lingua franca for clients (especially browsers via WebSocket) that don't want to ship a full AMQP or Kafka library.` }, { type: 'pioneers', title: 'The Broker Architects', people: [ { - name: 'John A. O\'Hara', + name: "John A. O'Hara", years: '–', title: 'AMQP Originator', org: 'JPMorgan Chase', @@ -28,7 +28,7 @@ export const enterpriseBrokersStory: SubcategoryStory = { title: 'Co-creator of Kafka', org: 'LinkedIn / Confluent', contribution: - "Co-created [[kafka|Apache Kafka]] at LinkedIn in 2011 with Neha Narkhede and Jun Rao. LinkedIn had outgrown ActiveMQ and Splunk for event ingestion; Kafka was their bet on a *log-as-primitive* approach instead of a queue-as-primitive. The 2013 paper \"The Log: What every software engineer should know about real-time data\\'s unifying abstraction\" is required reading. Kreps later co-founded Confluent (2014), now the dominant commercial Kafka company." + 'Co-created [[kafka|Apache Kafka]] at LinkedIn in 2011 with Neha Narkhede and Jun Rao. LinkedIn had outgrown ActiveMQ and Splunk for event ingestion; Kafka was their bet on a *log-as-primitive* approach instead of a queue-as-primitive. The 2013 paper "The Log: What every software engineer should know about real-time data\\\'s unifying abstraction" is required reading. Kreps later co-founded Confluent (2014), now the dominant commercial Kafka company.' }, { name: 'Brian McCallister', @@ -47,13 +47,13 @@ export const enterpriseBrokersStory: SubcategoryStory = { year: 1992, title: 'IBM MQSeries Ships', description: - "The first commercially significant message broker. Defines the queue model that AMQP later standardizes. Runs banks and airlines for the next 30 years; still alive as IBM MQ." + 'The first commercially significant message broker. Defines the queue model that AMQP later standardizes. Runs banks and airlines for the next 30 years; still alive as IBM MQ.' }, { year: 2001, title: 'JMS 1.0 (Java Message Service)', description: - "Sun ships JMS β€” a Java API for messaging, not a wire protocol. Every Java app can talk to any broker that implements JMS. Powerful but Java-only." + 'Sun ships JMS β€” a Java API for messaging, not a wire protocol. Every Java app can talk to any broker that implements JMS. Powerful but Java-only.' }, { year: 2003, @@ -65,7 +65,7 @@ export const enterpriseBrokersStory: SubcategoryStory = { year: 2005, title: 'STOMP Designed', description: - "Brian McCallister and Hiram Chirino design [[stomp|STOMP]] β€” Simple Text-Oriented Messaging Protocol. Five frame types, human-readable, no specific broker required." + 'Brian McCallister and Hiram Chirino design [[stomp|STOMP]] β€” Simple Text-Oriented Messaging Protocol. Five frame types, human-readable, no specific broker required.' }, { year: 2007, @@ -83,13 +83,13 @@ export const enterpriseBrokersStory: SubcategoryStory = { year: 2011, title: 'Kafka Open-Sourced at Apache', description: - "LinkedIn donates [[kafka|Kafka]] to the Apache Software Foundation. The log model β€” partitioned, replicated, consumer-group-based β€” is a different conception of messaging than queues." + 'LinkedIn donates [[kafka|Kafka]] to the Apache Software Foundation. The log model β€” partitioned, replicated, consumer-group-based β€” is a different conception of messaging than queues.' }, { year: 2011, title: 'AMQP 1.0', description: - "AMQP 1.0 finalized β€” wire-format-only, dropped the exchange/queue model from 0-9-1. RabbitMQ supports it via a plugin but keeps 0-9-1 as the default. The split between 0-9-1 and 1.0 has fragmented the AMQP ecosystem ever since." + 'AMQP 1.0 finalized β€” wire-format-only, dropped the exchange/queue model from 0-9-1. RabbitMQ supports it via a plugin but keeps 0-9-1 as the default. The split between 0-9-1 and 1.0 has fragmented the AMQP ecosystem ever since.' }, { year: 2014, @@ -101,13 +101,13 @@ export const enterpriseBrokersStory: SubcategoryStory = { year: 2017, title: 'Kafka Streams + ksqlDB', description: - "Kafka grows beyond pure transport into stream processing. Kafka Streams (a Java library) and ksqlDB (a SQL-ish layer) let you do joins, aggregations, and windowing directly against the log." + 'Kafka grows beyond pure transport into stream processing. Kafka Streams (a Java library) and ksqlDB (a SQL-ish layer) let you do joins, aggregations, and windowing directly against the log.' }, { year: 2021, title: 'Kafka Removes ZooKeeper Dependency', description: - "KIP-500 β€” Kafka raft-based metadata (KRaft) β€” eliminates the long-standing ZooKeeper dependency. Operationally simpler; a smaller blast radius when something goes wrong." + 'KIP-500 β€” Kafka raft-based metadata (KRaft) β€” eliminates the long-standing ZooKeeper dependency. Operationally simpler; a smaller blast radius when something goes wrong.' }, { year: 2024, @@ -129,7 +129,7 @@ export const enterpriseBrokersStory: SubcategoryStory = { 'Until ack from consumer', 'Competing consumers drain a queue', 'Binary frames over TCP', - "Work distribution, RPC patterns, request/response over queues" + 'Work distribution, RPC patterns, request/response over queues' ] }, { @@ -139,7 +139,7 @@ export const enterpriseBrokersStory: SubcategoryStory = { 'Configurable retention (hours to forever)', 'Consumer groups read at their own offset', 'Custom binary over TCP (Kafka protocol)', - "Event sourcing, stream processing, replay, audit logs" + 'Event sourcing, stream processing, replay, audit logs' ] }, { @@ -149,11 +149,11 @@ export const enterpriseBrokersStory: SubcategoryStory = { "Broker's problem", 'Whatever the broker supports', 'Text frames over TCP or WebSocket', - "Browser ↔ broker; scripts and tools without language-specific libs" + 'Browser ↔ broker; scripts and tools without language-specific libs' ] } ], - note: "If you find yourself trying to make Kafka behave like a queue (or AMQP behave like a log), you almost certainly picked the wrong tool. The mental models are genuinely different." + note: 'If you find yourself trying to make Kafka behave like a queue (or AMQP behave like a log), you almost certainly picked the wrong tool. The mental models are genuinely different.' }, { type: 'animated-sequence', @@ -187,7 +187,7 @@ export const enterpriseBrokersStory: SubcategoryStory = { K-->>C2: C Note over K: messages remain β€” both groups read independently`, caption: - "In [[amqp|AMQP]], a message belongs to whoever consumes it first; the queue empties. In [[kafka|Kafka]], the messages stay; each consumer group has its own read offset. This is why \"replay the last hour of events\" is trivial with Kafka and nearly impossible with AMQP.", + 'In [[amqp|AMQP]], a message belongs to whoever consumes it first; the queue empties. In [[kafka|Kafka]], the messages stay; each consumer group has its own read offset. This is why "replay the last hour of events" is trivial with Kafka and nearly impossible with AMQP.', steps: { 0: '**AMQP β€” competing consumers.** The queue is the source of truth. Multiple workers pull from the same queue; each message goes to exactly one of them.', 1: 'Producer publishes **msg A** to the queue.', @@ -213,18 +213,18 @@ export const enterpriseBrokersStory: SubcategoryStory = { }, { type: 'callout', - title: 'The Confluent Argument: \"The Log Is the Database\"', - text: `[[pioneer:jay-kreps|Jay Kreps]]\'s 2013 essay "The Log: What every software engineer should know about real-time data\'s unifying abstraction" reframed [[kafka|Kafka]] from "a message broker" to "the source of truth for your data."\n\nThe argument: every stateful system in your stack is, in some sense, a *materialized view* over an event log. Your database is rows derived from a sequence of inserts/updates/deletes. Your search index is documents derived from upstream changes. Your cache is a recent snapshot. If you make the log itself the primary source β€” and treat all derived state as downstream views over it β€” then:\n\n- Adding a new system means subscribing to the log and replaying history\n- Recovery means resetting the offset and re-deriving state\n- Auditing is free β€” every state change is in the log\n- Pipelines become declarative β€” "this view is a transformation of these topics"\n\nThis is the architectural pattern called **event sourcing**, and Kafka was the first widely-deployed system that made it operationally feasible at scale. Whether you buy the full argument or not, the *mental model* is now standard across distributed-systems design. The log-as-primitive view is one of the deepest contributions of the Kafka era.` + title: 'The Confluent Argument: "The Log Is the Database"', + text: `**Jay Kreps**'s 2013 essay "The Log: What every software engineer should know about real-time data's unifying abstraction" reframed [[kafka|Kafka]] from "a message broker" to "the source of truth for your data."\n\nThe argument: every stateful system in your stack is, in some sense, a *materialized view* over an event log. Your database is rows derived from a sequence of inserts/updates/deletes. Your search index is documents derived from upstream changes. Your cache is a recent snapshot. If you make the log itself the primary source β€” and treat all derived state as downstream views over it β€” then:\n\n- Adding a new system means subscribing to the log and replaying history\n- Recovery means resetting the offset and re-deriving state\n- Auditing is free β€” every state change is in the log\n- Pipelines become declarative β€” "this view is a transformation of these topics"\n\nThis is the architectural pattern called **event sourcing**, and Kafka was the first widely-deployed system that made it operationally feasible at scale. Whether you buy the full argument or not, the *mental model* is now standard across distributed-systems design. The log-as-primitive view is one of the deepest contributions of the Kafka era.` }, { type: 'narrative', title: 'The Failure Modes', - text: `[[amqp|AMQP]]/RabbitMQ\'s failure mode is **the unbounded queue**. A consumer falls behind; the queue grows; memory fills; the broker dies. RabbitMQ has rate-limiting, max-length policies, and dead-letter exchanges to mitigate this, but every team running RabbitMQ in anger has a story about a queue that ate the broker. The discipline: always set max-length, always have a dead-letter exchange, always alert on queue depth.\n\n[[kafka|Kafka]]\'s failure mode is **operations**. Running Kafka well requires real distributed-systems expertise: partition planning, broker sizing, consumer-group rebalancing, log retention, offset management, replication lag, ZooKeeper (pre-KRaft) coordination. Kafka-as-a-service (Confluent Cloud, AWS MSK, Aiven, Redpanda Cloud) exists precisely because most companies should *not* operate Kafka themselves. Even with managed Kafka, the consumer side is hard: a consumer group rebalance under load can stall processing for minutes.\n\n[[stomp|STOMP]]\'s failure mode is **its simplicity**. There\'s no built-in flow control, no native end-to-end ack semantics, no message-acknowledgment timeouts. Brokers add their own β€” and they all add slightly different ones. A STOMP client that works with ActiveMQ may not work identically with RabbitMQ. The protocol is the floor; everything above the floor is broker-specific.` + text: `[[amqp|AMQP]]/RabbitMQ's failure mode is **the unbounded queue**. A consumer falls behind; the queue grows; memory fills; the broker dies. RabbitMQ has rate-limiting, max-length policies, and dead-letter exchanges to mitigate this, but every team running RabbitMQ in anger has a story about a queue that ate the broker. The discipline: always set max-length, always have a dead-letter exchange, always alert on queue depth.\n\n[[kafka|Kafka]]'s failure mode is **operations**. Running Kafka well requires real distributed-systems expertise: partition planning, broker sizing, consumer-group rebalancing, log retention, offset management, replication lag, ZooKeeper (pre-KRaft) coordination. Kafka-as-a-service (Confluent Cloud, AWS MSK, Aiven, Redpanda Cloud) exists precisely because most companies should *not* operate Kafka themselves. Even with managed Kafka, the consumer side is hard: a consumer group rebalance under load can stall processing for minutes.\n\n[[stomp|STOMP]]'s failure mode is **its simplicity**. There's no built-in flow control, no native end-to-end ack semantics, no message-acknowledgment timeouts. Brokers add their own β€” and they all add slightly different ones. A STOMP client that works with ActiveMQ may not work identically with RabbitMQ. The protocol is the floor; everything above the floor is broker-specific.` }, { type: 'narrative', - title: 'What\'s Next', - text: `Active work in 2025:\n\n- **Tiered storage in Kafka** β€” cold data offloaded to S3/GCS while hot data stays on local disk. Cuts broker storage costs by ~10Γ—. KIP-405 shipped; AWS MSK and Confluent Cloud offer it.\n- **Iceberg + Kafka convergence** β€” Confluent\'s Tableflow and Redpanda\'s direct Iceberg writes make every Kafka topic queryable as an Iceberg table. The log-as-database vision is finally operationally trivial.\n- **WarpStream and \"stateless brokers\"** β€” broker designs that store every partition directly in S3 instead of replicating on local disk. Trade a bit of latency for dramatically lower operational complexity and cost. Acquired by Confluent in 2024.\n- **RabbitMQ 4.0** ships proper quorum queues by default and finally removes mirrored queues. The eternal RabbitMQ operational pain point is being addressed.\n- **NATS** continues quietly winning niches where Kafka is overkill but AMQP is too heavy β€” embedded systems, edge networks, in-cluster service eventing.\n- **The unsexy truth**: most teams should pick a managed broker (Confluent Cloud, AWS MSK, RabbitMQ Cloud, Upstash Kafka, etc.) and never operate one themselves. Running a broker is operationally distinct from using one.` + title: "What's Next", + text: `Active work in 2025:\n\n- **Tiered storage in Kafka** β€” cold data offloaded to S3/GCS while hot data stays on local disk. Cuts broker storage costs by ~10Γ—. KIP-405 shipped; AWS MSK and Confluent Cloud offer it.\n- **Iceberg + Kafka convergence** β€” Confluent's Tableflow and Redpanda's direct Iceberg writes make every Kafka topic queryable as an Iceberg table. The log-as-database vision is finally operationally trivial.\n- **WarpStream and "stateless brokers"** β€” broker designs that store every partition directly in S3 instead of replicating on local disk. Trade a bit of latency for dramatically lower operational complexity and cost. Acquired by Confluent in 2024.\n- **RabbitMQ 4.0** ships proper quorum queues by default and finally removes mirrored queues. The eternal RabbitMQ operational pain point is being addressed.\n- **NATS** continues quietly winning niches where Kafka is overkill but AMQP is too heavy β€” embedded systems, edge networks, in-cluster service eventing.\n- **The unsexy truth**: most teams should pick a managed broker (Confluent Cloud, AWS MSK, RabbitMQ Cloud, Upstash Kafka, etc.) and never operate one themselves. Running a broker is operationally distinct from using one.` } ] }; diff --git a/src/lib/data/subcategory-stories/federated-messaging.ts b/src/lib/data/subcategory-stories/federated-messaging.ts index 1a4666c..79c281c 100644 --- a/src/lib/data/subcategory-stories/federated-messaging.ts +++ b/src/lib/data/subcategory-stories/federated-messaging.ts @@ -3,12 +3,12 @@ import type { SubcategoryStory } from './types'; export const federatedMessagingStory: SubcategoryStory = { subcategoryId: 'federated-messaging', tagline: - "Federated chat for an era that wanted walled gardens β€” the protocol that powered everyone before everyone left", + 'Federated chat for an era that wanted walled gardens β€” the protocol that powered everyone before everyone left', sections: [ { type: 'narrative', title: 'The Federated Dream', - text: `In 1999, instant messaging was a mess. AOL Instant Messenger, ICQ, MSN Messenger, and Yahoo! Messenger were the dominant players, and they were *deliberately* incompatible. AOL spent years patching its servers to actively block third-party clients. If you wanted to message someone on AIM and you used Yahoo, you had to install Yahoo too. Both.\n\nJeremie Miller β€” a developer in St. Louis β€” looked at this and asked the obvious question: *why doesn\'t messaging work like email?* Email is **federated**. You don\'t need a Gmail account to email someone with a Gmail address. Any mail server can talk to any other mail server. Your address is \`you@your-server.com\`, and the routing just works.\n\nMiller\'s answer was **Jabber** (1999) β€” an open, federated, XML-based messaging protocol where users had addresses like \`alice@jabber.org\` and any server could talk to any other server. In 2002, the IETF standardized it as **[[xmpp|XMPP]]** (Extensible Messaging and Presence Protocol) in [[rfc:6120|RFCs 6120 and 6121]].\n\nFor a brief, glorious decade, XMPP looked like it might win. **Google Talk** launched in 2005 on XMPP and federated with other XMPP servers. **Facebook Chat** ran on XMPP from 2008. **WhatsApp** used a modified XMPP for its core messaging through at least 2014. **HipChat**, **GroupMe**, the original **Cisco Jabber** (it kept the name), Zoom\'s chat β€” all XMPP. At one point in the early 2010s, XMPP carried more messages than any other open protocol on the internet.\n\nThen, one by one, every major provider turned off federation. Google Talk dropped XMPP federation in 2014. Facebook Chat became Facebook Messenger and went proprietary. WhatsApp closed its XMPP-derived protocol to outside servers. The walled gardens won.\n\nThis is the story of how a protocol can be technically successful, used by billions, and still lose.` + text: `In 1999, instant messaging was a mess. AOL Instant Messenger, ICQ, MSN Messenger, and Yahoo! Messenger were the dominant players, and they were *deliberately* incompatible. AOL spent years patching its servers to actively block third-party clients. If you wanted to message someone on AIM and you used Yahoo, you had to install Yahoo too. Both.\n\nJeremie Miller β€” a developer in St. Louis β€” looked at this and asked the obvious question: *why doesn't messaging work like email?* Email is **federated**. You don't need a Gmail account to email someone with a Gmail address. Any mail server can talk to any other mail server. Your address is \`you@your-server.com\`, and the routing just works.\n\nMiller's answer was **Jabber** (1999) β€” an open, federated, XML-based messaging protocol where users had addresses like \`alice@jabber.org\` and any server could talk to any other server. In 2002, the IETF standardized it as **[[xmpp|XMPP]]** (Extensible Messaging and Presence Protocol) in [[rfc:6120|RFCs 6120 and 6121]].\n\nFor a brief, glorious decade, XMPP looked like it might win. **Google Talk** launched in 2005 on XMPP and federated with other XMPP servers. **Facebook Chat** ran on XMPP from 2008. **WhatsApp** used a modified XMPP for its core messaging through at least 2014. **HipChat**, **GroupMe**, the original **Cisco Jabber** (it kept the name), Zoom's chat β€” all XMPP. At one point in the early 2010s, XMPP carried more messages than any other open protocol on the internet.\n\nThen, one by one, every major provider turned off federation. Google Talk dropped XMPP federation in 2014. Facebook Chat became Facebook Messenger and went proprietary. WhatsApp closed its XMPP-derived protocol to outside servers. The walled gardens won.\n\nThis is the story of how a protocol can be technically successful, used by billions, and still lose.` }, { type: 'pioneers', @@ -20,8 +20,7 @@ export const federatedMessagingStory: SubcategoryStory = { title: 'Inventor of Jabber/XMPP', org: 'Jabber.org / Jabber, Inc. / Anaerobic', contribution: - "Started Jabber in 1998 as a side project to build an open alternative to AIM/ICQ. The original Jabber server (jabberd, written in C) launched in 2000. Miller co-founded Jabber, Inc. (commercial Jabber, eventually acquired by Cisco in 2008). The IETF standardized the protocol as [[xmpp|XMPP]] in 2002 ([[rfc:6120|RFC 3920/3921]], updated in 2011 to [[rfc:6120|RFC 6120/6121]]). After XMPP, Miller worked on TeleHash and a series of decentralized-protocol projects." - + 'Started Jabber in 1998 as a side project to build an open alternative to AIM/ICQ. The original Jabber server (jabberd, written in C) launched in 2000. Miller co-founded Jabber, Inc. (commercial Jabber, eventually acquired by Cisco in 2008). The IETF standardized the protocol as [[xmpp|XMPP]] in 2002 ([[rfc:6120|RFC 3920/3921]], updated in 2011 to [[rfc:6120|RFC 6120/6121]]). After XMPP, Miller worked on TeleHash and a series of decentralized-protocol projects.' }, { name: 'Peter Saint-Andre', @@ -29,7 +28,7 @@ export const federatedMessagingStory: SubcategoryStory = { title: 'XSF Executive Director / Spec Editor', org: 'XMPP Standards Foundation', contribution: - "Edited the major [[xmpp|XMPP]] specifications for nearly two decades, including the 2011 RFC 6120/6121/6122 update. Saint-Andre also led the XMPP Extensions Process (XEPs) β€” the document series that defines the dozens of optional protocol extensions (group chat, pub/sub, file transfer, voice, video). Most production XMPP deployments are 95% extensions and 5% core; without the XEP discipline, XMPP would have fragmented years earlier than it did." + 'Edited the major [[xmpp|XMPP]] specifications for nearly two decades, including the 2011 RFC 6120/6121/6122 update. Saint-Andre also led the XMPP Extensions Process (XEPs) β€” the document series that defines the dozens of optional protocol extensions (group chat, pub/sub, file transfer, voice, video). Most production XMPP deployments are 95% extensions and 5% core; without the XEP discipline, XMPP would have fragmented years earlier than it did.' }, { name: 'Matthew Hodgson', @@ -48,7 +47,7 @@ export const federatedMessagingStory: SubcategoryStory = { year: 1999, title: 'Jabber Begins', description: - "Jeremie Miller starts the Jabber project. The first design goal: messaging that works the way email works β€” anyone can run a server, any server can federate with any other." + 'Jeremie Miller starts the Jabber project. The first design goal: messaging that works the way email works β€” anyone can run a server, any server can federate with any other.' }, { year: 2000, @@ -66,55 +65,55 @@ export const federatedMessagingStory: SubcategoryStory = { year: 2004, title: 'RFC 3920/3921 β€” XMPP Core + IM', description: - 'The first XMPP RFCs publish. XML streams, JID addressing (\`local@domain/resource\`), presence subscriptions, message stanzas.' + 'The first XMPP RFCs publish. XML streams, JID addressing (`local@domain/resource`), presence subscriptions, message stanzas.' }, { year: 2005, title: 'Google Talk Launches on XMPP', description: - "Google ships Talk as an XMPP-federated service. Any XMPP user could chat with any Google Talk user. For the next decade Google Talk is the protocol\'s flagship deployment." + "Google ships Talk as an XMPP-federated service. Any XMPP user could chat with any Google Talk user. For the next decade Google Talk is the protocol's flagship deployment." }, { year: 2008, title: 'Facebook Chat Goes XMPP', description: - "Facebook ships chat using XMPP. Federation is one-way (you could connect from external XMPP clients, but Facebook Chat users couldn\'t message outside)." + "Facebook ships chat using XMPP. Federation is one-way (you could connect from external XMPP clients, but Facebook Chat users couldn't message outside)." }, { year: 2009, title: 'WhatsApp Uses Modified XMPP', description: - "WhatsApp\'s server is a modified ejabberd (Erlang XMPP server). The protocol on the wire is XMPP-derived through at least the 2014 Facebook acquisition era, eventually drifting into a proprietary binary protocol." + "WhatsApp's server is a modified ejabberd (Erlang XMPP server). The protocol on the wire is XMPP-derived through at least the 2014 Facebook acquisition era, eventually drifting into a proprietary binary protocol." }, { year: 2011, title: 'RFC 6120/6121 β€” XMPP Refresh', description: - "The current XMPP specification, edited by Peter Saint-Andre. Cleans up TLS requirements, internationalization (JIDs in Unicode), and stream features." + 'The current XMPP specification, edited by Peter Saint-Andre. Cleans up TLS requirements, internationalization (JIDs in Unicode), and stream features.' }, { year: 2014, title: 'Google Drops XMPP Federation', description: - "Google Talk becomes Hangouts. XMPP federation is removed. The single largest source of cross-server messages on the federated XMPP network disappears overnight." + 'Google Talk becomes Hangouts. XMPP federation is removed. The single largest source of cross-server messages on the federated XMPP network disappears overnight.' }, { year: 2014, title: 'Matrix Begins', description: - "Matthew Hodgson and Amandine Le Pape start Matrix as an HTTP-based, decentralized chat protocol. Explicitly positioned as \"what we wish XMPP looked like in 2014.\"" + 'Matthew Hodgson and Amandine Le Pape start Matrix as an HTTP-based, decentralized chat protocol. Explicitly positioned as "what we wish XMPP looked like in 2014."' }, { year: 2017, title: 'WhatsApp Goes Fully Proprietary', description: - "The last vestiges of WhatsApp\'s XMPP heritage are replaced by a fully proprietary binary protocol. The largest deployment of an XMPP-derived protocol is no longer XMPP." + "The last vestiges of WhatsApp's XMPP heritage are replaced by a fully proprietary binary protocol. The largest deployment of an XMPP-derived protocol is no longer XMPP." }, { year: 2024, title: 'EU Digital Markets Act', description: - "The DMA names \"gatekeeper\" platforms (WhatsApp, Messenger, iMessage) and requires they offer interoperability APIs. The protocol details are unclear; XMPP and Matrix are both being discussed as candidate bridges. The federated dream gets a regulatory comeback." + 'The DMA names "gatekeeper" platforms (WhatsApp, Messenger, iMessage) and requires they offer interoperability APIs. The protocol details are unclear; XMPP and Matrix are both being discussed as candidate bridges. The federated dream gets a regulatory comeback.' } ] }, @@ -130,7 +129,7 @@ export const federatedMessagingStory: SubcategoryStory = { 'XML stanzas over long-lived TCP/TLS', 'OMEMO (Signal-protocol-based) or OTR; not mandatory', 'No β€” designed for desktop XMPP clients', - "Still running in niches (gaming, IoT, smart-home); near-zero consumer presence" + 'Still running in niches (gaming, IoT, smart-home); near-zero consumer presence' ] }, { @@ -140,7 +139,7 @@ export const federatedMessagingStory: SubcategoryStory = { 'JSON events over HTTPS', 'Megolm (Signal-derived); on by default in newer clients', 'Yes β€” designed for modern mobile clients', - "Active growth β€” used by Element, governments (France, Germany), some Discord-alt communities" + 'Active growth β€” used by Element, governments (France, Germany), some Discord-alt communities' ] }, { @@ -148,13 +147,13 @@ export const federatedMessagingStory: SubcategoryStory = { values: [ 'None (walled gardens)', 'Proprietary binary protocols', - 'Signal Protocol (WhatsApp, Messenger), Apple\'s own (iMessage)', + "Signal Protocol (WhatsApp, Messenger), Apple's own (iMessage)", 'Yes β€” phone-number-first identity', - "Billions of users; effectively the messaging layer of mobile" + 'Billions of users; effectively the messaging layer of mobile' ] } ], - note: "The walled gardens won the consumer market. The federated protocols ([[xmpp|XMPP]], Matrix) still matter for governments, IoT, and any context where one party doesn\'t want to depend on Meta\'s servers." + note: "The walled gardens won the consumer market. The federated protocols ([[xmpp|XMPP]], Matrix) still matter for governments, IoT, and any context where one party doesn't want to depend on Meta's servers." }, { type: 'animated-sequence', @@ -175,33 +174,33 @@ export const federatedMessagingStory: SubcategoryStory = { SB->>B: deliver message from Alice Note over A,B: No central authority β€” just two servers and DNS`, caption: - "This is the federation pattern email pioneered and XMPP brought to chat. Any server can speak to any other server using only DNS β€” no central authority issues credentials, no platform brokers the connection. Beautiful in theory; commercially fragile in practice.", + 'This is the federation pattern email pioneered and XMPP brought to chat. Any server can speak to any other server using only DNS β€” no central authority issues credentials, no platform brokers the connection. Beautiful in theory; commercially fragile in practice.', steps: { - 0: '**Federation in action.** Alice is on example.com\'s XMPP server, Bob is on foo.org\'s. Neither server is a "platform" β€” they\'re run by different operators, and any other organization could run a third without asking permission.', - 1: 'Alice\'s client sends a `<message>` stanza to her own server, addressed to `bob@foo.org`.', - 2: 'Server SA does not know foo.org\'s address. It asks **DNS for the SRV record** `_xmpp-server._tcp.foo.org`. (SRV records let the operator point service traffic at a specific host and port without affecting the main hostname.)', + 0: "**Federation in action.** Alice is on example.com's XMPP server, Bob is on foo.org's. Neither server is a \"platform\" β€” they're run by different operators, and any other organization could run a third without asking permission.", + 1: "Alice's client sends a `<message>` stanza to her own server, addressed to `bob@foo.org`.", + 2: "Server SA does not know foo.org's address. It asks **DNS for the SRV record** `_xmpp-server._tcp.foo.org`. (SRV records let the operator point service traffic at a specific host and port without affecting the main hostname.)", 3: 'DNS replies with `xmpp.foo.org:5269` β€” the canonical XMPP server-to-server port. (Client-to-server is 5222; server-to-server is 5269.)', 4: 'SA **opens an XML stream to SB**. The first time these two servers talk, a stream is established and reused for all subsequent messages between them.', 5: 'SB responds with **stream features, TLS, and dialback verification**. Dialback is XMPP\'s lightweight "are you really example.com?" check β€” uses DNS itself to validate.', - 6: 'SA **forwards Alice\'s message** to SB, properly tagged with the sender domain so SB can verify and route.', - 7: 'SB **delivers the message** to Bob\'s connected client (or queues it if Bob is offline).', + 6: "SA **forwards Alice's message** to SB, properly tagged with the sender domain so SB can verify and route.", + 7: "SB **delivers the message** to Bob's connected client (or queues it if Bob is offline).", 8: '**No central authority.** ICANN does not bless XMPP servers. There is no Meta, no platform. The whole interaction relied only on DNS and the two servers agreeing on a common protocol β€” exactly the email model.' } }, { type: 'callout', title: 'Why the Walled Gardens Won', - text: `Federation is the right architecture and it lost. Why?\n\n**Spam and abuse.** Email federates β€” and the operational cost is the entire anti-spam industry. Every mail server runs SpamAssassin, SPF, DKIM, DMARC, blocklists, reputation scoring. Running a federated chat server means rebuilding that infrastructure. Walled gardens have to police only inside their own walls.\n\n**Mobile push.** Mobile OSes (iOS, Android) heavily restrict background services. A federated chat client can\'t maintain a long-lived XMPP connection β€” the OS will kill it. Push notifications require a server that *the OS trusts*, which means going through Apple\'s APNs or Google\'s FCM, which means the chat provider has to operate a centralized service anyway. Federation\'s "any server" promise hits the mobile wall.\n\n**End-to-end encryption is harder to federate.** Signal Protocol-style E2EE requires the sender to know each recipient\'s current device keys. In a federated system, fetching keys means trusting the other server to tell the truth. In a walled garden, the central server controls the key directory and the trust is implicit.\n\n**Network effects.** Once WhatsApp has your friends, you can\'t leave without losing them. Federation requires every server operator to coordinate; a walled garden requires only the one operator. The walled gardens scaled faster than federation could compete.\n\nThe technical merit of XMPP was never the question. The economics, the operational complexity, and the mobile platforms killed it.` + text: `Federation is the right architecture and it lost. Why?\n\n**Spam and abuse.** Email federates β€” and the operational cost is the entire anti-spam industry. Every mail server runs SpamAssassin, SPF, DKIM, DMARC, blocklists, reputation scoring. Running a federated chat server means rebuilding that infrastructure. Walled gardens have to police only inside their own walls.\n\n**Mobile push.** Mobile OSes (iOS, Android) heavily restrict background services. A federated chat client can't maintain a long-lived XMPP connection β€” the OS will kill it. Push notifications require a server that *the OS trusts*, which means going through Apple's APNs or Google's FCM, which means the chat provider has to operate a centralized service anyway. Federation's "any server" promise hits the mobile wall.\n\n**End-to-end encryption is harder to federate.** Signal Protocol-style E2EE requires the sender to know each recipient's current device keys. In a federated system, fetching keys means trusting the other server to tell the truth. In a walled garden, the central server controls the key directory and the trust is implicit.\n\n**Network effects.** Once WhatsApp has your friends, you can't leave without losing them. Federation requires every server operator to coordinate; a walled garden requires only the one operator. The walled gardens scaled faster than federation could compete.\n\nThe technical merit of XMPP was never the question. The economics, the operational complexity, and the mobile platforms killed it.` }, { type: 'narrative', title: 'The Failure Mode', - text: `[[xmpp|XMPP]]\'s failure mode wasn\'t a protocol-level bug β€” it was **extensibility without governance**. The core protocol is small; everything interesting happens in XEPs (XMPP Extension Proposals). Group chat (MUC, XEP-0045) is a XEP. File transfer (Jingle, XEP-0166). End-to-end encryption (OMEMO, XEP-0384). Pub/sub (XEP-0060). Voice and video (XEP-0167).\n\nThis was meant to be a feature β€” pick the XEPs you need; ignore the rest. In practice, it meant every client supported a *different subset* of XEPs. Sending a file from Pidgin to Adium might work; from Conversations to Gajim might not. From a corporate Cisco Jabber client to anything else, almost never. The "extensible" in the name created interoperability fragmentation that walled gardens, by their nature, didn\'t have.\n\nMatrix\'s answer is to fold more functionality into the core spec and version it deliberately. Whether that strategy avoids the same fragmentation over a long horizon is the open question of the federated chat world.` + text: `[[xmpp|XMPP]]'s failure mode wasn't a protocol-level bug β€” it was **extensibility without governance**. The core protocol is small; everything interesting happens in XEPs (XMPP Extension Proposals). Group chat (MUC, XEP-0045) is a XEP. File transfer (Jingle, XEP-0166). End-to-end encryption (OMEMO, XEP-0384). Pub/sub (XEP-0060). Voice and video (XEP-0167).\n\nThis was meant to be a feature β€” pick the XEPs you need; ignore the rest. In practice, it meant every client supported a *different subset* of XEPs. Sending a file from Pidgin to Adium might work; from Conversations to Gajim might not. From a corporate Cisco Jabber client to anything else, almost never. The "extensible" in the name created interoperability fragmentation that walled gardens, by their nature, didn't have.\n\nMatrix's answer is to fold more functionality into the core spec and version it deliberately. Whether that strategy avoids the same fragmentation over a long horizon is the open question of the federated chat world.` }, { type: 'narrative', - title: 'What\'s Next', - text: `Active work in 2025:\n\n- **EU Digital Markets Act interop** β€” the DMA names WhatsApp and Messenger as gatekeepers required to offer messaging interoperability to third parties. The technical protocol is being argued; [[xmpp|XMPP]] and Matrix are both in the conversation as candidate bridges. The first time in 20 years that regulation rather than market forces is pushing federation forward.\n- **Matrix in government** β€” France\'s government chat (Tchap), Germany\'s healthcare messaging (TI-Messenger), and the German Bundeswehr have all standardized on Matrix. Sovereignty concerns are driving uptake where US-based walled gardens are politically unacceptable.\n- **XMPP for IoT and gaming** β€” the protocol that powers Zoom\'s chat, every major MMO backend (League of Legends, World of Warcraft chat), Sony PlayStation Network messaging, and most XMPP-IoT smart-home stacks. The consumer-chat market is gone; the infrastructure market remains.\n- **Bridges between worlds** β€” Beeper (acquired by Automattic) and matrix.org bridges aim to be one app that talks to WhatsApp, iMessage, SMS, Telegram, Signal, and Matrix simultaneously. The federation-as-aggregation-layer approach when federation-as-protocol failed.\n- **The unsexy truth**: federated chat lost the consumer market and probably won\'t get it back. The interesting frontier is *interoperability bridges* and *sovereign-government deployments*, not the federated dream returning to displace WhatsApp.` + title: "What's Next", + text: `Active work in 2025:\n\n- **EU Digital Markets Act interop** β€” the DMA names WhatsApp and Messenger as gatekeepers required to offer messaging interoperability to third parties. The technical protocol is being argued; [[xmpp|XMPP]] and Matrix are both in the conversation as candidate bridges. The first time in 20 years that regulation rather than market forces is pushing federation forward.\n- **Matrix in government** β€” France's government chat (Tchap), Germany's healthcare messaging (TI-Messenger), and the German Bundeswehr have all standardized on Matrix. Sovereignty concerns are driving uptake where US-based walled gardens are politically unacceptable.\n- **XMPP for IoT and gaming** β€” the protocol that powers Zoom's chat, every major MMO backend (League of Legends, World of Warcraft chat), Sony PlayStation Network messaging, and most XMPP-IoT smart-home stacks. The consumer-chat market is gone; the infrastructure market remains.\n- **Bridges between worlds** β€” Beeper (acquired by Automattic) and matrix.org bridges aim to be one app that talks to WhatsApp, iMessage, SMS, Telegram, Signal, and Matrix simultaneously. The federation-as-aggregation-layer approach when federation-as-protocol failed.\n- **The unsexy truth**: federated chat lost the consumer market and probably won't get it back. The interesting frontier is *interoperability bridges* and *sovereign-government deployments*, not the federated dream returning to displace WhatsApp.` } ] }; diff --git a/src/lib/data/subcategory-stories/http-versions.ts b/src/lib/data/subcategory-stories/http-versions.ts index 25cf389..ed6f73f 100644 --- a/src/lib/data/subcategory-stories/http-versions.ts +++ b/src/lib/data/subcategory-stories/http-versions.ts @@ -3,7 +3,7 @@ import type { SubcategoryStory } from './types'; export const httpVersionsStory: SubcategoryStory = { subcategoryId: 'http-versions', tagline: - 'Thirty years of one protocol β€” from a text-based handshake on a NeXT cube to encrypted multiplexed streams over {{quic|QUIC}}', + 'Thirty years of one protocol β€” from a text-based handshake on a NeXT cube to encrypted multiplexed streams over [[quic|QUIC]]', sections: [ { type: 'narrative', @@ -21,7 +21,7 @@ export const httpVersionsStory: SubcategoryStory = { title: 'Inventor of the World Wide Web', org: 'CERN / W3C / MIT', contribution: - 'Wrote the first web browser, web server, and HTML specification in late 1990. The original HTTP was a single \`GET\` line returning a document β€” no headers, no status codes, no methods. By 1996 [[http1|HTTP/1.0]] had grown headers and \`POST\`; [[http1|HTTP/1.1]] followed in 1997 with persistent connections that kept the web from drowning in {{tcp-handshake|TCP handshakes}}.', + 'Wrote the first web browser, web server, and HTML specification in late 1990. The original HTTP was a single `GET` line returning a document β€” no headers, no status codes, no methods. By 1996 [[http1|HTTP/1.0]] had grown headers and `POST`; [[http1|HTTP/1.1]] followed in 1997 with persistent connections that kept the web from drowning in {{tcp-handshake|TCP handshakes}}.', imagePath: 'https://upload.wikimedia.org/wikipedia/commons/thumb/6/63/Tim_Berners-Lee_April_2009.jpg/330px-Tim_Berners-Lee_April_2009.jpg' }, @@ -43,7 +43,7 @@ export const httpVersionsStory: SubcategoryStory = { title: 'Designer of QUIC', org: 'Google', contribution: - 'Designed the original {{quic|QUIC}} at Google starting in 2012 β€” a fundamentally new transport over [[udp|UDP]] that solved [[http2|HTTP/2]]\'s transport-layer {{head-of-line-blocking|head-of-line blocking}} by giving each stream its own loss-recovery context. The {{ietf|IETF}} took over standardization in 2016; [[http3|HTTP/3]] became RFC 9114 in June 2022. Roskind\'s key insight: encryption belongs *inside* the transport, not above it.', + "Designed the original [[quic|QUIC]] at Google starting in 2012 β€” a fundamentally new transport over [[udp|UDP]] that solved [[http2|HTTP/2]]'s transport-layer {{head-of-line-blocking|head-of-line blocking}} by giving each stream its own loss-recovery context. The {{ietf|IETF}} took over standardization in 2016; [[http3|HTTP/3]] became RFC 9114 in June 2022. Roskind's key insight: encryption belongs *inside* the transport, not above it.", imagePath: 'https://upload.wikimedia.org/wikipedia/commons/thumb/c/c7/Jim_Roskind_2016.jpg/330px-Jim_Roskind_2016.jpg' } @@ -56,25 +56,25 @@ export const httpVersionsStory: SubcategoryStory = { year: 1990, title: 'HTTP/0.9 β€” The One-Line Protocol', description: - '[[pioneer:tim-berners-lee|Berners-Lee]] writes the first web server on a NeXT cube at {{cern|CERN}}. The entire HTTP spec: \`GET /path\`. Server returns the document and closes.' + '[[pioneer:tim-berners-lee|Berners-Lee]] writes the first web server on a NeXT cube at {{cern|CERN}}. The entire HTTP spec: `GET /path`. Server returns the document and closes.' }, { year: 1996, title: 'HTTP/1.0 (RFC 1945)', description: - 'Headers arrive. Status codes. \`POST\`. Content-Type. Each request still opens a new [[tcp|TCP]] connection β€” the {{three-way-handshake|three-way handshake}} happens for every image on a page.' + 'Headers arrive. Status codes. `POST`. Content-Type. Each request still opens a new [[tcp|TCP]] connection β€” the {{three-way-handshake|three-way handshake}} happens for every image on a page.' }, { year: 1997, title: 'HTTP/1.1 (RFC 2068, later 7230–7235)', description: - 'Persistent connections (\`Keep-Alive\`) become the default. Pipelining is *specified* but breaks in practice. Chunked encoding, virtual hosts via \`Host:\` header, range requests. This is the HTTP that ran the web for 18 years.' + 'Persistent connections (`Keep-Alive`) become the default. Pipelining is *specified* but breaks in practice. Chunked encoding, virtual hosts via `Host:` header, range requests. This is the HTTP that ran the web for 18 years.' }, { year: 2009, title: 'SPDY at Google', description: - '[[pioneer:mike-belshe|Mike Belshe]] and Roberto Peon ship {{spdy|SPDY}} in Chrome. Binary frames, multiplexed streams over one connection, header compression, server push. The web didn\'t need a new protocol β€” it needed [[http1|HTTP/1.1]] without its bottlenecks.' + "[[pioneer:mike-belshe|Mike Belshe]] and Roberto Peon ship {{spdy|SPDY}} in Chrome. Binary frames, multiplexed streams over one connection, header compression, server push. The web didn't need a new protocol β€” it needed [[http1|HTTP/1.1]] without its bottlenecks." }, { year: 2012, @@ -86,13 +86,13 @@ export const httpVersionsStory: SubcategoryStory = { year: 2013, title: 'QUIC at Google', description: - '[[pioneer:jim-roskind|Jim Roskind]] starts {{quic|QUIC}} β€” a UDP-based transport that bundles encryption, congestion control, and stream multiplexing into one. By 2017, ~7% of all Google traffic already runs on QUIC.' + '[[pioneer:jim-roskind|Jim Roskind]] starts [[quic|QUIC]] β€” a UDP-based transport that bundles encryption, congestion control, and stream multiplexing into one. By 2017, ~7% of all Google traffic already runs on QUIC.' }, { year: 2015, title: 'HTTP/2 Published (RFC 7540)', description: - 'Binary framing, multiplexing, {{hpack|HPACK}} header compression, server push (rarely used in practice). Solves [[http1|HTTP/1.1]]\'s application-layer {{head-of-line-blocking|HoL blocking}}. Doesn\'t solve TCP\'s.' + "Binary framing, multiplexing, {{hpack|HPACK}} header compression, server push (rarely used in practice). Solves [[http1|HTTP/1.1]]'s application-layer {{head-of-line-blocking|HoL blocking}}. Doesn't solve TCP's." }, { year: 2016, @@ -117,7 +117,7 @@ export const httpVersionsStory: SubcategoryStory = { { type: 'callout', title: 'The Head-of-Line Blocking Saga', - text: `Each HTTP version is, in some sense, a reaction to head-of-line blocking at a different layer.\n\n**[[http1|HTTP/1.1]]**: HoL blocking *at the application layer*. One request per connection means a slow response stalls the next request on that socket. Browsers worked around this by opening 6 parallel connections per origin.\n\n**[[http2|HTTP/2]]**: solves application-layer HoL with stream multiplexing β€” hundreds of concurrent requests over one connection. But it still runs over [[tcp|TCP]], and a single lost packet stalls *all* streams until TCP recovers it. HoL just moved down a layer.\n\n**[[http3|HTTP/3]]**: solves transport-layer HoL by moving streams *into* {{quic|QUIC}}. Each stream has its own loss-recovery context. One stream waiting for a retransmit doesn't block the others. The buck finally stops.` + text: `Each HTTP version is, in some sense, a reaction to head-of-line blocking at a different layer.\n\n**[[http1|HTTP/1.1]]**: HoL blocking *at the application layer*. One request per connection means a slow response stalls the next request on that socket. Browsers worked around this by opening 6 parallel connections per origin.\n\n**[[http2|HTTP/2]]**: solves application-layer HoL with stream multiplexing β€” hundreds of concurrent requests over one connection. But it still runs over [[tcp|TCP]], and a single lost packet stalls *all* streams until TCP recovers it. HoL just moved down a layer.\n\n**[[http3|HTTP/3]]**: solves transport-layer HoL by moving streams *into* [[quic|QUIC]]. Each stream has its own loss-recovery context. One stream waiting for a retransmit doesn't block the others. The buck finally stops.` }, { type: 'animated-sequence', @@ -143,7 +143,7 @@ export const httpVersionsStory: SubcategoryStory = { C->>S: Stream 8, GET /app.js, independent loss recovery S-->>C: Streams delivered in any order, loss on one does not stall others`, caption: - "Same three requests, three protocols. In [[http1|HTTP/1.1]] they're serialized. In [[http2|HTTP/2]] they multiplex but share one TCP socket. In [[http3|HTTP/3]] each stream has its own loss recovery on top of {{quic|QUIC}}.", + "Same three requests, three protocols. In [[http1|HTTP/1.1]] they're serialized. In [[http2|HTTP/2]] they multiplex but share one TCP socket. In [[http3|HTTP/3]] each stream has its own loss recovery on top of [[quic|QUIC]].", steps: { 0: '**[[http1|HTTP/1.1]] β€” serial requests on one connection.** With Keep-Alive, the client can reuse a TCP connection for many requests, but only one can be in flight at a time.', 1: 'Client sends a **GET for the HTML**. Browser starts the page load.', @@ -159,7 +159,7 @@ export const httpVersionsStory: SubcategoryStory = { 11: 'Server returns **interleaved frames** from all three streams. The page can start rendering as soon as the HTML frames arrive β€” no head-of-line blocking *at the application layer*. But all three streams share one TCP connection, and a single dropped TCP packet stalls all of them.', 12: '**[[http3|HTTP/3]] β€” multiplexing without TCP HoL.** Each stream is owned by [[quic|QUIC]] (over UDP), with its own loss-recovery context. Stream 0 stalling does not affect stream 4 or 8.', 13: 'Client opens **stream 0** for the HTML over QUIC.', - 14: 'Client opens **stream 4** for the CSS β€” if a UDP packet carrying stream 4 is lost, QUIC retransmits only that stream\'s data.', + 14: "Client opens **stream 4** for the CSS β€” if a UDP packet carrying stream 4 is lost, QUIC retransmits only that stream's data.", 15: 'Client opens **stream 8** for the JS β€” same independence.', 16: '**Streams arrive in any order**, and packet loss on one does not stall the others. The HoL ghost that haunted HTTP for 25 years is finally exorcised β€” at the cost of moving reliable transport into user space.' } @@ -167,17 +167,17 @@ export const httpVersionsStory: SubcategoryStory = { { type: 'narrative', title: 'The Ossification Trap', - text: `There's a subtle reason [[http3|HTTP/3]] runs on {{quic|QUIC}} over [[udp|UDP]] rather than on a new TCP-like protocol: **{{ossification|protocol ossification}}**. The internet's middleboxes β€” firewalls, NATs, deep-packet-inspection appliances β€” only understand [[tcp|TCP]] and [[udp|UDP]]. Anything else gets blocked. Worse, those middleboxes peek inside TCP headers and reject anything that doesn't look exactly like 1990s TCP. Try to add a new TCP option, and a few percent of the internet silently drops your packets.\n\nQUIC's defense: encrypt everything. Not just the payload β€” the *transport headers* too. Middleboxes can see a UDP packet going to port 443 and that's it. They can't inspect the QUIC framing, so they can't reject things they don't recognize. Future QUIC versions can change the wire format and middleboxes won't notice.\n\nThe price: implementing QUIC means re-implementing reliable transport in user space, since the kernel doesn't help. The reward: a transport that can evolve.` + text: `There's a subtle reason [[http3|HTTP/3]] runs on [[quic|QUIC]] over [[udp|UDP]] rather than on a new TCP-like protocol: **{{ossification|protocol ossification}}**. The internet's middleboxes β€” firewalls, NATs, deep-packet-inspection appliances β€” only understand [[tcp|TCP]] and [[udp|UDP]]. Anything else gets blocked. Worse, those middleboxes peek inside TCP headers and reject anything that doesn't look exactly like 1990s TCP. Try to add a new TCP option, and a few percent of the internet silently drops your packets.\n\nQUIC's defense: encrypt everything. Not just the payload β€” the *transport headers* too. Middleboxes can see a UDP packet going to port 443 and that's it. They can't inspect the QUIC framing, so they can't reject things they don't recognize. Future QUIC versions can change the wire format and middleboxes won't notice.\n\nThe price: implementing QUIC means re-implementing reliable transport in user space, since the kernel doesn't help. The reward: a transport that can evolve.` }, { type: 'callout', title: 'Why HTTP/2 Server Push Mostly Died', - text: `One of [[http2|HTTP/2]]\'s big features was *server push*: a server could send resources to the client before the client asked for them. The idea was that if the client requests \`/index.html\`, the server can push \`/style.css\` and \`/app.js\` proactively.\n\nIn practice: it almost never helped. Servers couldn\'t predict what the client already had cached, so they re-sent things the client didn\'t need. The browser cache and the push cache fought each other. Chrome removed server push support in 2022. [[http3|HTTP/3]] kept the feature for compatibility but nobody uses it. The lesson: a clever optimization that requires guessing client state usually loses to just letting the client ask.` + text: `One of [[http2|HTTP/2]]'s big features was *server push*: a server could send resources to the client before the client asked for them. The idea was that if the client requests \`/index.html\`, the server can push \`/style.css\` and \`/app.js\` proactively.\n\nIn practice: it almost never helped. Servers couldn't predict what the client already had cached, so they re-sent things the client didn't need. The browser cache and the push cache fought each other. Chrome removed server push support in 2022. [[http3|HTTP/3]] kept the feature for compatibility but nobody uses it. The lesson: a clever optimization that requires guessing client state usually loses to just letting the client ask.` }, { type: 'narrative', - title: 'What\'s Next', - text: `[[http3|HTTP/3]] is shipping but not finished. Active work in 2025:\n\n- **{{webtransport|WebTransport}}**: bidirectional streams over QUIC, exposed to browsers β€” a possible replacement for {{websockets|WebSockets}} where you want UDP-like semantics with TLS.\n- **{{masque|MASQUE}}**: tunnel arbitrary protocols inside QUIC, used by iCloud Private Relay and similar privacy products.\n- **HTTP/2 over QUIC**: not actually a thing, but it\'s a useful reminder that the framing layer (HTTP) and the transport (TCP/QUIC) are now genuinely separable.\n- **Multipath QUIC**: the same {{mptcp|MPTCP}} idea β€” use multiple network paths in parallel β€” but for QUIC, which is much easier to evolve than TCP.\n\nThe deeper trend: HTTP is now the universal application protocol, and the interesting evolution is happening at the *transport* layer beneath it. After 35 years, the protocol that started as \`GET /index.html\` runs more of the world\'s traffic than any other single protocol β€” and the next chapter is being written by the people who decided TCP wasn\'t good enough anymore.` + title: "What's Next", + text: `[[http3|HTTP/3]] is shipping but not finished. Active work in 2025:\n\n- **{{webtransport|WebTransport}}**: bidirectional streams over QUIC, exposed to browsers β€” a possible replacement for [[websockets|WebSockets]] where you want UDP-like semantics with TLS.\n- **{{masque|MASQUE}}**: tunnel arbitrary protocols inside QUIC, used by iCloud Private Relay and similar privacy products.\n- **HTTP/2 over QUIC**: not actually a thing, but it's a useful reminder that the framing layer (HTTP) and the transport (TCP/QUIC) are now genuinely separable.\n- **Multipath QUIC**: the same [[mptcp|MPTCP]] idea β€” use multiple network paths in parallel β€” but for QUIC, which is much easier to evolve than TCP.\n\nThe deeper trend: HTTP is now the universal application protocol, and the interesting evolution is happening at the *transport* layer beneath it. After 35 years, the protocol that started as \`GET /index.html\` runs more of the world's traffic than any other single protocol β€” and the next chapter is being written by the people who decided TCP wasn't good enough anymore.` } ] }; diff --git a/src/lib/data/subcategory-stories/index.ts b/src/lib/data/subcategory-stories/index.ts index 1639e29..2950668 100644 --- a/src/lib/data/subcategory-stories/index.ts +++ b/src/lib/data/subcategory-stories/index.ts @@ -29,7 +29,7 @@ import { networkServicesStory } from './network-services'; import { wlanWanStory } from './wlan-wan'; import { panProximityStory } from './pan-proximity'; -const stories: SubcategoryStory[] = [ +export const subcategoryStories: SubcategoryStory[] = [ linkLayerStory, internetLayerStory, routingStory, @@ -55,7 +55,7 @@ const stories: SubcategoryStory[] = [ ]; const storyMap = new Map<string, SubcategoryStory>( - stories.map((s) => [s.subcategoryId, s]) + subcategoryStories.map((s) => [s.subcategoryId, s]) ); export function getSubcategoryStory(subcategoryId: string): SubcategoryStory | undefined { diff --git a/src/lib/data/subcategory-stories/internet-layer.ts b/src/lib/data/subcategory-stories/internet-layer.ts index c0d90be..22b7977 100644 --- a/src/lib/data/subcategory-stories/internet-layer.ts +++ b/src/lib/data/subcategory-stories/internet-layer.ts @@ -3,12 +3,12 @@ import type { SubcategoryStory } from './types'; export const internetLayerStory: SubcategoryStory = { subcategoryId: 'internet-layer', tagline: - "Best-effort packet delivery across networks β€” the narrow waist of the hourglass that lets the rest of the Internet exist", + 'Best-effort packet delivery across networks β€” the narrow waist of the hourglass that lets the rest of the Internet exist', sections: [ { type: 'narrative', title: 'The Layer That Everything Else Trusts', - text: `Networking diagrams traditionally draw the Internet protocol stack as an **hourglass**. Many physical link layers at the bottom (Ethernet, Wi-Fi, fiber, cellular). Many transport and application layers at the top ([[tcp|TCP]], [[udp|UDP]], [[http3|HTTP]], [[dns|DNS]]). One protocol in the middle.\n\nThat middle protocol is **[[ip|IP]]**. Every packet on the Internet, regardless of what physical medium it crosses or what application generated it, wears an IP header. The narrowness of the waist is what makes the whole thing work: any application can run over any link as long as both speak IP. Wi-Fi got added without changing TCP. HTTP/3 got added without changing Ethernet. The hourglass shape is the architectural reason the Internet was able to evolve at all.\n\nThe Internet Layer family has three members:\n\n- **[[ip|IPv4]]** ([[rfc:791|RFC 791]], 1981) is the original. 32-bit addresses, 20-byte header, decades of operational hardening. The address space (~4.3 billion) ran out years ago; [[nat-traversal|NAT]] is how we\'ve been pretending otherwise.\n- **[[ipv6|IPv6]]** ([[rfc:8200|RFC 8200]], 1998 / 2017) is the successor. 128-bit addresses (enough to give every grain of sand on Earth its own /64). Cleaned-up header (40 bytes, fewer fields, better fragmentation rules). Mandatory IPsec was once part of the pitch; deployed reality is more complicated.\n- **[[icmp|ICMP]]** ([[rfc:792|RFC 792]] for v4, [[rfc:4443|RFC 4443]] for v6) is the diagnostic shadow. Echo (the basis of \`ping\`), TTL-exceeded (the basis of \`traceroute\`), destination-unreachable, redirect. Not really a transport β€” more of a control plane for IP itself.\n\nThe **best-effort** promise is what makes IP scale. The protocol guarantees nothing β€” packets may arrive in any order, may be duplicated, may be silently dropped, may have bits corrupted. All reliability is the responsibility of higher layers ([[tcp|TCP]], [[quic|QUIC]], the application). Routers don\'t need to remember any state about flows; they just look at the destination address, consult the routing table, forward. This statelessness is what lets the Internet survive at scale β€” failures are routed around without anyone needing to coordinate.` + text: `Networking diagrams traditionally draw the Internet protocol stack as an **hourglass**. Many physical link layers at the bottom (Ethernet, Wi-Fi, fiber, cellular). Many transport and application layers at the top ([[tcp|TCP]], [[udp|UDP]], [[http3|HTTP]], [[dns|DNS]]). One protocol in the middle.\n\nThat middle protocol is **[[ip|IP]]**. Every packet on the Internet, regardless of what physical medium it crosses or what application generated it, wears an IP header. The narrowness of the waist is what makes the whole thing work: any application can run over any link as long as both speak IP. Wi-Fi got added without changing TCP. HTTP/3 got added without changing Ethernet. The hourglass shape is the architectural reason the Internet was able to evolve at all.\n\nThe Internet Layer family has three members:\n\n- **[[ip|IPv4]]** ([[rfc:791|RFC 791]], 1981) is the original. 32-bit addresses, 20-byte header, decades of operational hardening. The address space (~4.3 billion) ran out years ago; [[nat-traversal|NAT]] is how we've been pretending otherwise.\n- **[[ipv6|IPv6]]** ([[rfc:8200|RFC 8200]], 1998 / 2017) is the successor. 128-bit addresses (enough to give every grain of sand on Earth its own /64). Cleaned-up header (40 bytes, fewer fields, better fragmentation rules). Mandatory IPsec was once part of the pitch; deployed reality is more complicated.\n- **[[icmp|ICMP]]** ([[rfc:792|RFC 792]] for v4, [[rfc:4443|RFC 4443]] for v6) is the diagnostic shadow. Echo (the basis of \`ping\`), TTL-exceeded (the basis of \`traceroute\`), destination-unreachable, redirect. Not really a transport β€” more of a control plane for IP itself.\n\nThe **best-effort** promise is what makes IP scale. The protocol guarantees nothing β€” packets may arrive in any order, may be duplicated, may be silently dropped, may have bits corrupted. All reliability is the responsibility of higher layers ([[tcp|TCP]], [[quic|QUIC]], the application). Routers don't need to remember any state about flows; they just look at the destination address, consult the routing table, forward. This statelessness is what lets the Internet survive at scale β€” failures are routed around without anyone needing to coordinate.` }, { type: 'pioneers', @@ -30,7 +30,7 @@ export const internetLayerStory: SubcategoryStory = { title: 'Co-inventor of TCP/IP', org: 'DARPA / Corporation for National Research Initiatives', contribution: - "Conceived the open-architecture networking idea at DARPA in 1972 and recruited [[pioneer:vint-cerf|Cerf]] to collaborate on the protocols that would become TCP/IP. The crucial decision was that the internet protocol β€” the spanning layer that connected disparate networks β€” should make no assumptions about the underlying network technology. That decision lets [[ip|IP]] run on Ethernet, Wi-Fi, satellites, dark fiber, smoke signals, and IP-over-Avian-Carriers ([[rfc:1149|RFC 1149]] β€” yes, really)." + 'Conceived the open-architecture networking idea at DARPA in 1972 and recruited [[pioneer:vint-cerf|Cerf]] to collaborate on the protocols that would become TCP/IP. The crucial decision was that the internet protocol β€” the spanning layer that connected disparate networks β€” should make no assumptions about the underlying network technology. That decision lets [[ip|IP]] run on Ethernet, Wi-Fi, satellites, dark fiber, smoke signals, and IP-over-Avian-Carriers ([[rfc:1149|RFC 1149]] β€” yes, really).' }, { id: 'steve-deering', @@ -39,7 +39,7 @@ export const internetLayerStory: SubcategoryStory = { title: 'Father of IPv6 and IP Multicast', org: 'Stanford / Xerox PARC / Cisco', contribution: - "Designed IP multicast (RFC 1112, 1989) β€” the model for one-to-many delivery that underlies multicast routing, IGMP, and (eventually) every IPTV deployment. Also co-designed [[ipv6|IPv6]] (RFC 1883, 1995; later RFC 2460, then [[rfc:8200|RFC 8200]] in 2017) at Xerox PARC and Cisco. Deering\\'s judgment that \"variable-length addresses are operationally too hard\" β€” leading to IPv6\\'s fixed 128-bit width β€” is one of the bets that defines the next 50 years of Internet addressing." + 'Designed IP multicast (RFC 1112, 1989) β€” the model for one-to-many delivery that underlies multicast routing, IGMP, and (eventually) every IPTV deployment. Also co-designed [[ipv6|IPv6]] (RFC 1883, 1995; later RFC 2460, then [[rfc:8200|RFC 8200]] in 2017) at Xerox PARC and Cisco. Deering\\\'s judgment that "variable-length addresses are operationally too hard" β€” leading to IPv6\\\'s fixed 128-bit width β€” is one of the bets that defines the next 50 years of Internet addressing.' } ] }, @@ -50,7 +50,7 @@ export const internetLayerStory: SubcategoryStory = { year: 1974, title: 'Cerf & Kahn Publish TCP/IP Concept', description: - '\"A Protocol for Packet Network Intercommunication\" defines open-architecture networking. The protocol is monolithic at first.' + '"A Protocol for Packet Network Intercommunication" defines open-architecture networking. The protocol is monolithic at first.' }, { year: 1978, @@ -68,25 +68,25 @@ export const internetLayerStory: SubcategoryStory = { year: 1981, title: 'ICMP RFC 792', description: - '[[icmp|ICMP]] standardized β€” the diagnostic protocol that gave us \`ping\` (1983) and later \`traceroute\` (1988).' + '[[icmp|ICMP]] standardized β€” the diagnostic protocol that gave us `ping` (1983) and later `traceroute` (1988).' }, { year: 1983, title: 'ARPANET Flag Day', description: - "January 1, 1983 β€” the ARPANET transitions from NCP to [[tcp|TCP]]/[[ip|IP]]. Most networking textbooks date \"the Internet\" from this day." + 'January 1, 1983 β€” the ARPANET transitions from NCP to [[tcp|TCP]]/[[ip|IP]]. Most networking textbooks date "the Internet" from this day.' }, { year: 1993, title: 'CIDR Replaces Classful Addressing (RFC 1519)', description: - "Classless Inter-Domain Routing β€” variable-length subnet masks. Saves [[ip|IPv4]] from premature exhaustion through the late 1990s." + 'Classless Inter-Domain Routing β€” variable-length subnet masks. Saves [[ip|IPv4]] from premature exhaustion through the late 1990s.' }, { year: 1995, title: 'IPv6 First Spec (RFC 1883)', description: - "[[pioneer:steve-deering|Deering]]\'s [[ipv6|IPv6]] specification publishes. 128-bit addresses, simpler header, no fragmentation by routers (only by hosts)." + "[[pioneer:steve-deering|Deering]]'s [[ipv6|IPv6]] specification publishes. 128-bit addresses, simpler header, no fragmentation by routers (only by hosts)." }, { year: 1998, @@ -98,31 +98,31 @@ export const internetLayerStory: SubcategoryStory = { year: 2011, title: 'IPv4 Address Exhaustion', description: - "IANA allocates the last /8 of IPv4 to a regional registry on February 3, 2011. Regional registries run out over the next decade. The address space the original architects thought would last forever is gone." + 'IANA allocates the last /8 of IPv4 to a regional registry on February 3, 2011. Regional registries run out over the next decade. The address space the original architects thought would last forever is gone.' }, { year: 2012, title: 'World IPv6 Launch Day', description: - "Google, Facebook, Yahoo, Akamai, and others permanently enable [[ipv6|IPv6]] on their main websites. Real-world IPv6 traffic share starts rising from <1%." + 'Google, Facebook, Yahoo, Akamai, and others permanently enable [[ipv6|IPv6]] on their main websites. Real-world IPv6 traffic share starts rising from <1%.' }, { year: 2017, title: 'IPv6 RFC 8200', description: - "The current IPv6 specification. Mostly clarifications; a few changes to fragmentation handling. Officially raises IPv6 to Internet Standard." + 'The current IPv6 specification. Mostly clarifications; a few changes to fragmentation handling. Officially raises IPv6 to Internet Standard.' }, { year: 2021, title: 'IPv6 Adoption ~40%', description: - "Google measures ~40% of users reaching it via IPv6. Apple-mandated IPv6-only support in App Store apps (2016) drove much of the adoption β€” every major mobile app must work over IPv6-only networks." + 'Google measures ~40% of users reaching it via IPv6. Apple-mandated IPv6-only support in App Store apps (2016) drove much of the adoption β€” every major mobile app must work over IPv6-only networks.' }, { year: 2024, title: 'IPv4 Address Trading', description: - "IPv4 /24 blocks trade for $40-50 each on the secondary market. AWS, Cloudflare, Microsoft are major buyers. The last vestiges of IPv4 allocation become a commodity market." + 'IPv4 /24 blocks trade for $40-50 each on the secondary market. AWS, Cloudflare, Microsoft are major buyers. The last vestiges of IPv4 allocation become a commodity market.' } ] }, @@ -136,9 +136,9 @@ export const internetLayerStory: SubcategoryStory = { values: [ '20 bytes minimum (40 with options)', '32 bits', - "4.3 billion addresses (long exhausted; [[nat-traversal|NAT]] stretches it)", + '4.3 billion addresses (long exhausted; [[nat-traversal|NAT]] stretches it)', 'Wide deployment, mature tooling, simple operation', - "Routers can fragment in transit" + 'Routers can fragment in transit' ] }, { @@ -146,23 +146,23 @@ export const internetLayerStory: SubcategoryStory = { values: [ '40 bytes fixed (extension headers for options)', '128 bits', - "3.4 Γ— 10³⁸ addresses (effectively unlimited)", + '3.4 Γ— 10³⁸ addresses (effectively unlimited)', 'No NAT needed, simpler header, native autoconfiguration (SLAAC)', - "Only end-hosts fragment; routers send ICMPv6 Packet Too Big" + 'Only end-hosts fragment; routers send ICMPv6 Packet Too Big' ] }, { label: '[[icmp|ICMP]]', values: [ 'Variable (depends on type)', - "N/A β€” uses IP addresses", - "N/A", + 'N/A β€” uses IP addresses', + 'N/A', 'Diagnostic + error reporting (echo, TTL exceeded, destination unreachable)', - "N/A" + 'N/A' ] } ], - note: "ICMP isn\'t a transport β€” it\'s a control protocol for IP itself. ICMPv4 and ICMPv6 are different protocols with overlapping purposes; ICMPv6 absorbed ARP\'s functionality via Neighbor Discovery." + note: "ICMP isn't a transport β€” it's a control protocol for IP itself. ICMPv4 and ICMPv6 are different protocols with overlapping purposes; ICMPv6 absorbed ARP's functionality via Neighbor Discovery." }, { type: 'animated-sequence', @@ -189,7 +189,7 @@ export const internetLayerStory: SubcategoryStory = { B-->>A: ICMP Destination Unreachable or response Note over A: traceroute now knows the full path β€” R1, R2, R3, B`, caption: - "This is how `traceroute` actually works β€” it abuses the TTL field. Every IP router decrements TTL; when TTL reaches 0, the router drops the packet and sends an ICMP Time Exceeded back to the source. By sending probes with TTL=1, 2, 3, ..., a source can map the path packet-by-packet. The control plane was never designed for this; it just falls out of the rules.", + 'This is how `traceroute` actually works β€” it abuses the TTL field. Every IP router decrements TTL; when TTL reaches 0, the router drops the packet and sends an ICMP Time Exceeded back to the source. By sending probes with TTL=1, 2, 3, ..., a source can map the path packet-by-packet. The control plane was never designed for this; it just falls out of the rules.', steps: { 0: '**Normal IP forwarding.** Every router along the path decrements the TTL (Time To Live) field in the IP header by 1. The TTL exists to prevent packets from looping forever in case of routing loops.', 1: 'Source sends a packet destined for B with **TTL=64** (the typical default).', @@ -198,29 +198,29 @@ export const internetLayerStory: SubcategoryStory = { 4: '**Router 3 decrements TTL to 61** and forwards to B. The packet arrived in 4 hops and burned 4 TTL units.', 5: '**Traceroute exploits TTL.** Instead of sending packets with normal TTLs, traceroute sends probes with TTL=1, then 2, then 3... Each probe expires N hops in, and the router that expires it sends an ICMP error back.', 6: 'Source sends a probe with **TTL=1**. R1 will decrement to 0 and drop it.', - 7: 'R1 returns an **ICMP Time Exceeded** message. The source now knows R1\'s IP address β€” first hop identified.', + 7: "R1 returns an **ICMP Time Exceeded** message. The source now knows R1's IP address β€” first hop identified.", 8: 'Source sends a probe with **TTL=2**. R1 decrements to 1 and forwards; R2 decrements to 0 and drops.', 9: 'R2 returns **ICMP Time Exceeded** β€” second hop identified.', 10: 'Source sends a probe with **TTL=3**. Reaches R3, which decrements to 0 and drops.', 11: 'R3 returns **ICMP Time Exceeded** β€” third hop identified.', - 12: 'Source sends a probe with **TTL=4**. This time it reaches B. B is the destination, not a router; it responds with ICMP Destination Unreachable (if the probe was UDP to a closed port, traceroute\'s usual trick) or a regular response.', - 13: 'B\'s reply ends the trace. Traceroute now knows the full path: **A β†’ R1 β†’ R2 β†’ R3 β†’ B**, plus the round-trip latency to each hop. The TTL mechanism β€” designed only to prevent loops β€” gave us the most-used network-diagnostic tool ever built.' + 12: "Source sends a probe with **TTL=4**. This time it reaches B. B is the destination, not a router; it responds with ICMP Destination Unreachable (if the probe was UDP to a closed port, traceroute's usual trick) or a regular response.", + 13: "B's reply ends the trace. Traceroute now knows the full path: **A β†’ R1 β†’ R2 β†’ R3 β†’ B**, plus the round-trip latency to each hop. The TTL mechanism β€” designed only to prevent loops β€” gave us the most-used network-diagnostic tool ever built." } }, { type: 'callout', title: 'Why IPv6 Took 30 Years', - text: `[[ipv6|IPv6]] was published in 1995. By 2010, IPv4 was running out of addresses; the migration should have been urgent. As of 2025, IPv6 carries ~40% of Google traffic β€” better than people expected by 2020, but still far from the "IPv4 is gone" world the original transition plans envisioned.\n\nWhy the slow march?\n\n- **There\'s no flag day.** Unlike the 1983 ARPANET TCP/IP cutover (which had ~400 hosts on one network), the modern Internet has billions of devices on countless networks. No central authority can flip a switch. Every operator transitions independently.\n- **NAT bought time.** [[nat-traversal|NAT]] β€” designed as a temporary hack β€” let one IPv4 address serve hundreds of devices behind a home router. The address-exhaustion pressure was real but never *acute*. People could keep using IPv4 indefinitely (uncomfortably, but indefinitely).\n- **IPv6 isn\'t a superset of IPv4.** A pure IPv6 host can\'t reach IPv4-only hosts without translation (NAT64, CLAT, 464XLAT). A network running only IPv6 has to maintain IPv4 reachability anyway for legacy services. Dual-stack β€” running both β€” is operationally complex.\n- **No business benefit (until now).** From an individual operator\'s perspective, IPv6 cost money to deploy and brought no new functionality. The address-exhaustion cost was diffused across the industry; the cost of deployment was localized.\n- **Apple changed the calculus in 2016.** Apple\'s App Store policy requiring all apps to work on IPv6-only networks meant every iOS developer had to test and fix their apps. T-Mobile USA going IPv6-only on their cellular network made that real. The pressure flipped from \"why bother\" to \"my service breaks if I don\'t.\"\n\nThe deeper lesson: replacing the protocol at the bottom of the hourglass is the hardest possible thing to do in network engineering. Everything depends on it. Backward compatibility constraints multiply. Replacement might still complete; it might never complete. Either outcome is consistent with the data so far.` + text: `[[ipv6|IPv6]] was published in 1995. By 2010, IPv4 was running out of addresses; the migration should have been urgent. As of 2025, IPv6 carries ~40% of Google traffic β€” better than people expected by 2020, but still far from the "IPv4 is gone" world the original transition plans envisioned.\n\nWhy the slow march?\n\n- **There's no flag day.** Unlike the 1983 ARPANET TCP/IP cutover (which had ~400 hosts on one network), the modern Internet has billions of devices on countless networks. No central authority can flip a switch. Every operator transitions independently.\n- **NAT bought time.** [[nat-traversal|NAT]] β€” designed as a temporary hack β€” let one IPv4 address serve hundreds of devices behind a home router. The address-exhaustion pressure was real but never *acute*. People could keep using IPv4 indefinitely (uncomfortably, but indefinitely).\n- **IPv6 isn't a superset of IPv4.** A pure IPv6 host can't reach IPv4-only hosts without translation (NAT64, CLAT, 464XLAT). A network running only IPv6 has to maintain IPv4 reachability anyway for legacy services. Dual-stack β€” running both β€” is operationally complex.\n- **No business benefit (until now).** From an individual operator's perspective, IPv6 cost money to deploy and brought no new functionality. The address-exhaustion cost was diffused across the industry; the cost of deployment was localized.\n- **Apple changed the calculus in 2016.** Apple's App Store policy requiring all apps to work on IPv6-only networks meant every iOS developer had to test and fix their apps. T-Mobile USA going IPv6-only on their cellular network made that real. The pressure flipped from "why bother" to "my service breaks if I don't."\n\nThe deeper lesson: replacing the protocol at the bottom of the hourglass is the hardest possible thing to do in network engineering. Everything depends on it. Backward compatibility constraints multiply. Replacement might still complete; it might never complete. Either outcome is consistent with the data so far.` }, { type: 'narrative', title: 'The Failure Modes', - text: `[[ip|IPv4]]\'s failure mode is **address exhaustion**. There aren\'t enough 32-bit addresses for the world\'s devices, and there haven\'t been for years. [[nat-traversal|NAT]] hides the shortage at the cost of breaking the original peer-to-peer Internet model. Carrier-Grade NAT (where a cellular carrier runs NAT in their core) gives an entire customer base a single IPv4 address β€” when that IP gets DDoSed or blacklisted, *every* customer is affected. The economic pressure shows up as IPv4 address blocks trading for $40-50 per IP on the secondary market.\n\n[[ipv6|IPv6]]\'s failure modes are subtler. The protocol design replaced some IPv4 problems with new ones:\n\n- **No fragmentation in routers.** Sounds good β€” fragmentation was a performance disaster. But path-MTU discovery requires ICMPv6 \"Packet Too Big\" messages to reach the source, and many networks block ICMP. Black-hole MTU problems (connection establishes, large packets silently dropped) are an IPv6 operational headache.\n- **128-bit addresses are hard to type.** \`2001:db8:85a3::8a2e:370:7334\` instead of \`192.168.1.50\`. SLAAC-derived addresses are even more abstract. Diagnostic UX is worse than IPv4.\n- **Privacy extensions complicate logging.** SLAAC addresses change over time for privacy; correlating logs across time intervals is harder.\n\n[[icmp|ICMP]]\'s failure mode is **operators blocking it**. ICMP is essential for network operation (path-MTU discovery, error reporting) but is commonly blocked by misconfigured firewalls because "ICMP is dangerous." Blocking *all* ICMP breaks many things subtly β€” IPv6 connectivity in particular relies on ICMPv6 for Neighbor Discovery. The "block ICMP echo only" advice from RFC 4890 is correct but rarely followed.` + text: `[[ip|IPv4]]'s failure mode is **address exhaustion**. There aren't enough 32-bit addresses for the world's devices, and there haven't been for years. [[nat-traversal|NAT]] hides the shortage at the cost of breaking the original peer-to-peer Internet model. Carrier-Grade NAT (where a cellular carrier runs NAT in their core) gives an entire customer base a single IPv4 address β€” when that IP gets DDoSed or blacklisted, *every* customer is affected. The economic pressure shows up as IPv4 address blocks trading for $40-50 per IP on the secondary market.\n\n[[ipv6|IPv6]]'s failure modes are subtler. The protocol design replaced some IPv4 problems with new ones:\n\n- **No fragmentation in routers.** Sounds good β€” fragmentation was a performance disaster. But path-MTU discovery requires ICMPv6 "Packet Too Big" messages to reach the source, and many networks block ICMP. Black-hole MTU problems (connection establishes, large packets silently dropped) are an IPv6 operational headache.\n- **128-bit addresses are hard to type.** \`2001:db8:85a3::8a2e:370:7334\` instead of \`192.168.1.50\`. SLAAC-derived addresses are even more abstract. Diagnostic UX is worse than IPv4.\n- **Privacy extensions complicate logging.** SLAAC addresses change over time for privacy; correlating logs across time intervals is harder.\n\n[[icmp|ICMP]]'s failure mode is **operators blocking it**. ICMP is essential for network operation (path-MTU discovery, error reporting) but is commonly blocked by misconfigured firewalls because "ICMP is dangerous." Blocking *all* ICMP breaks many things subtly β€” IPv6 connectivity in particular relies on ICMPv6 for Neighbor Discovery. The "block ICMP echo only" advice from RFC 4890 is correct but rarely followed.` }, { type: 'narrative', - title: 'What\'s Next', - text: `Active work in 2025:\n\n- **IPv6-only networks** continue to spread. Most major mobile carriers (T-Mobile USA, Reliance Jio, France\'s mobile networks) are IPv6-only with NAT64/DNS64 for legacy IPv4 access. Apple-mandated dual-stack support means iOS apps just work on these networks. The transition is happening, slowly.\n- **Segment Routing (SRv6)** is rolling out in ISP backbones. Encodes the explicit packet path inside the IPv6 header itself; doesn\'t replace [[bgp|BGP]] but changes how engineers express traffic engineering. Largely an enterprise/ISP technology, invisible to end users.\n- **IPv6 Extension Headers** β€” a generality of IPv6 originally meant for innovation β€” remain underutilized. Many networks drop packets containing extension headers (which they shouldn\'t but do); deploying anything beyond plain IPv6 is operationally hard.\n- **QUIC over IP** β€” [[quic|QUIC]] is layered above IP via UDP, but the design point β€” encrypt transport headers, escape middlebox ossification β€” is essentially "evolve transport behavior without changing IP." It\'s a workaround for the fact that IPv6 mass deployment didn\'t happen on schedule.\n- **IPv4 secondary market** continues. AWS now owns >100 million IPv4 addresses; Cloudflare, Microsoft, Akamai are major holders. IPv4 prefixes are quietly becoming a financial asset class.\n- **The boring truth**: IPv4 will be running real production traffic in 2050. The hourglass is wide enough to hold both versions of the waist for a very long time.` + title: "What's Next", + text: `Active work in 2025:\n\n- **IPv6-only networks** continue to spread. Most major mobile carriers (T-Mobile USA, Reliance Jio, France's mobile networks) are IPv6-only with NAT64/DNS64 for legacy IPv4 access. Apple-mandated dual-stack support means iOS apps just work on these networks. The transition is happening, slowly.\n- **Segment Routing (SRv6)** is rolling out in ISP backbones. Encodes the explicit packet path inside the IPv6 header itself; doesn't replace [[bgp|BGP]] but changes how engineers express traffic engineering. Largely an enterprise/ISP technology, invisible to end users.\n- **IPv6 Extension Headers** β€” a generality of IPv6 originally meant for innovation β€” remain underutilized. Many networks drop packets containing extension headers (which they shouldn't but do); deploying anything beyond plain IPv6 is operationally hard.\n- **QUIC over IP** β€” [[quic|QUIC]] is layered above IP via UDP, but the design point β€” encrypt transport headers, escape middlebox ossification β€” is essentially "evolve transport behavior without changing IP." It's a workaround for the fact that IPv6 mass deployment didn't happen on schedule.\n- **IPv4 secondary market** continues. AWS now owns >100 million IPv4 addresses; Cloudflare, Microsoft, Akamai are major holders. IPv4 prefixes are quietly becoming a financial asset class.\n- **The boring truth**: IPv4 will be running real production traffic in 2050. The hourglass is wide enough to hold both versions of the waist for a very long time.` } ] }; diff --git a/src/lib/data/subcategory-stories/iot-messaging.ts b/src/lib/data/subcategory-stories/iot-messaging.ts index 9911695..0a8de6e 100644 --- a/src/lib/data/subcategory-stories/iot-messaging.ts +++ b/src/lib/data/subcategory-stories/iot-messaging.ts @@ -3,12 +3,12 @@ import type { SubcategoryStory } from './types'; export const iotMessagingStory: SubcategoryStory = { subcategoryId: 'iot-messaging', tagline: - "Talking to billions of constrained devices over flaky links β€” when every byte and every milliwatt matters", + 'Talking to billions of constrained devices over flaky links β€” when every byte and every milliwatt matters', sections: [ { type: 'narrative', title: 'When the Device Is the Constraint', - text: `Most networking protocols assume the endpoint is a server or a workstation: gigabytes of RAM, gigahertz of CPU, mains power, a stable Ethernet link. IoT inverts every one of those assumptions. The endpoint is a temperature sensor on a windmill, a soil-moisture probe in a field, a smart-meter on the side of a house, an asset tracker glued to a pallet. It has 32 KB of RAM, an 8-bit MCU, a CR2032 battery that must last seven years, and a cellular link that drops out every other day.\n\nTwo protocols dominate this world:\n\n- **[[mqtt|MQTT]]** (1999) is a publish/subscribe protocol designed at IBM for SCADA systems running over satellite links. The wire format is brutally compact (a 2-byte header for most messages); the topic model is hierarchical strings; quality-of-service is built in (QoS 0/1/2). A broker in the middle does all the work; devices speak only to the broker. By 2020 it powered Facebook Messenger, AWS IoT Core, and approximately every commercial IoT platform that exists.\n- **[[coap|CoAP]]** (2014) is "[[http1|HTTP]] for constrained devices." It maps GET/POST/PUT/DELETE onto [[udp|UDP]] datagrams, supports observe-style streaming for resource changes, and packs the protocol into a few hundred bytes of RAM. The mental model: REST on a sensor. The CoRE working group at the IETF designed it specifically so a web developer who knows HTTP can reason about IoT without learning a new paradigm.\n\nThey aren\'t direct competitors. MQTT centralizes on a broker; CoAP is peer-to-peer. MQTT runs on [[tcp|TCP]]; CoAP on [[udp|UDP]]. MQTT is great when many devices fan out events to many backends. CoAP is great when a controller polls or observes individual devices on a constrained-radio mesh (6LoWPAN, Thread).` + text: `Most networking protocols assume the endpoint is a server or a workstation: gigabytes of RAM, gigahertz of CPU, mains power, a stable Ethernet link. IoT inverts every one of those assumptions. The endpoint is a temperature sensor on a windmill, a soil-moisture probe in a field, a smart-meter on the side of a house, an asset tracker glued to a pallet. It has 32 KB of RAM, an 8-bit MCU, a CR2032 battery that must last seven years, and a cellular link that drops out every other day.\n\nTwo protocols dominate this world:\n\n- **[[mqtt|MQTT]]** (1999) is a publish/subscribe protocol designed at IBM for SCADA systems running over satellite links. The wire format is brutally compact (a 2-byte header for most messages); the topic model is hierarchical strings; quality-of-service is built in (QoS 0/1/2). A broker in the middle does all the work; devices speak only to the broker. By 2020 it powered Facebook Messenger, AWS IoT Core, and approximately every commercial IoT platform that exists.\n- **[[coap|CoAP]]** (2014) is "[[http1|HTTP]] for constrained devices." It maps GET/POST/PUT/DELETE onto [[udp|UDP]] datagrams, supports observe-style streaming for resource changes, and packs the protocol into a few hundred bytes of RAM. The mental model: REST on a sensor. The CoRE working group at the IETF designed it specifically so a web developer who knows HTTP can reason about IoT without learning a new paradigm.\n\nThey aren't direct competitors. MQTT centralizes on a broker; CoAP is peer-to-peer. MQTT runs on [[tcp|TCP]]; CoAP on [[udp|UDP]]. MQTT is great when many devices fan out events to many backends. CoAP is great when a controller polls or observes individual devices on a constrained-radio mesh (6LoWPAN, Thread).` }, { type: 'pioneers', @@ -20,7 +20,7 @@ export const iotMessagingStory: SubcategoryStory = { title: 'Co-inventor of MQTT', org: 'IBM', contribution: - "Co-invented [[mqtt|MQTT]] at IBM in 1999 with Arlen Nipper. The original use case was telemetry from oil pipelines monitored by VSAT (satellite) β€” a connection that was expensive, low-bandwidth, and routinely flaky. MQTT\\'s minimalism (2-byte header, no acks required at QoS 0) and its broker-mediated pub/sub model were direct responses to those constraints. Stanford-Clark also pioneered residential applications β€” \"MQTT in the home\" demos in the mid-2000s β€” that previewed the smart-home era." + 'Co-invented [[mqtt|MQTT]] at IBM in 1999 with Arlen Nipper. The original use case was telemetry from oil pipelines monitored by VSAT (satellite) β€” a connection that was expensive, low-bandwidth, and routinely flaky. MQTT\\\'s minimalism (2-byte header, no acks required at QoS 0) and its broker-mediated pub/sub model were direct responses to those constraints. Stanford-Clark also pioneered residential applications β€” "MQTT in the home" demos in the mid-2000s β€” that previewed the smart-home era.' }, { name: 'Arlen Nipper', @@ -47,7 +47,7 @@ export const iotMessagingStory: SubcategoryStory = { year: 1999, title: 'MQTT Born at IBM', description: - "[[pioneer:andy-stanford-clark|Stanford-Clark]] and [[pioneer:arlen-nipper|Nipper]] design [[mqtt|MQTT]] for monitoring oil pipelines via satellite links. Constraints: expensive bandwidth, frequent disconnects, tiny embedded controllers." + '**Stanford-Clark** and **Nipper** design [[mqtt|MQTT]] for monitoring oil pipelines via satellite links. Constraints: expensive bandwidth, frequent disconnects, tiny embedded controllers.' }, { year: 2011, @@ -59,7 +59,7 @@ export const iotMessagingStory: SubcategoryStory = { year: 2013, title: 'Facebook Messenger Adopts MQTT', description: - "Facebook ships MQTT in Messenger\'s mobile apps for chat-message delivery β€” a counterintuitive but brilliant fit. The same protocol designed for oil pipelines turns out to be perfect for low-latency push to phones on flaky mobile networks." + "Facebook ships MQTT in Messenger's mobile apps for chat-message delivery β€” a counterintuitive but brilliant fit. The same protocol designed for oil pipelines turns out to be perfect for low-latency push to phones on flaky mobile networks." }, { year: 2014, @@ -77,7 +77,7 @@ export const iotMessagingStory: SubcategoryStory = { year: 2016, title: 'AWS IoT Core Launches', description: - "AWS picks MQTT as the primary protocol for AWS IoT Core. Azure, Google Cloud IoT (now deprecated), Alibaba Cloud IoT all follow with MQTT-first stacks." + 'AWS picks MQTT as the primary protocol for AWS IoT Core. Azure, Google Cloud IoT (now deprecated), Alibaba Cloud IoT all follow with MQTT-first stacks.' }, { year: 2018, @@ -89,13 +89,13 @@ export const iotMessagingStory: SubcategoryStory = { year: 2019, title: 'MQTT 5 Published', description: - "MQTT 5 adds shared subscriptions, message expiry, request/response patterns, properties (extensible metadata), reason codes. Most production deployments are still on 3.1.1 because of broker-side feature gating, but 5 is the path forward." + 'MQTT 5 adds shared subscriptions, message expiry, request/response patterns, properties (extensible metadata), reason codes. Most production deployments are still on 3.1.1 because of broker-side feature gating, but 5 is the path forward.' }, { year: 2022, title: 'Matter Launches with CoAP', description: - "Matter (Apple/Google/Amazon\'s unified smart-home protocol) uses CoAP-over-Thread for its commissioning and device communication. The largest consumer-facing deployment of CoAP to date." + "Matter (Apple/Google/Amazon's unified smart-home protocol) uses CoAP-over-Thread for its commissioning and device communication. The largest consumer-facing deployment of CoAP to date." }, { year: 2024, @@ -117,7 +117,7 @@ export const iotMessagingStory: SubcategoryStory = { '[[tcp|TCP]] (with [[tls|TLS]]) β€” sometimes WebSocket', 'Topic strings the publisher and subscriber agree on', 'QoS 0 (at-most-once) / 1 (at-least-once) / 2 (exactly-once)', - "Cloud-connected fleet telemetry, mobile push, smart-home cloud" + 'Cloud-connected fleet telemetry, mobile push, smart-home cloud' ] }, { @@ -127,11 +127,11 @@ export const iotMessagingStory: SubcategoryStory = { '[[udp|UDP]] (with DTLS) β€” sometimes TCP', 'Resource URIs + multicast discovery', 'Confirmable / non-confirmable messages', - "Constrained-radio meshes (Thread, 6LoWPAN), Matter, local control" + 'Constrained-radio meshes (Thread, 6LoWPAN), Matter, local control' ] } ], - note: "MQTT requires a broker; CoAP can work device-to-device. If your devices already need a cloud connection (telemetry, OTA updates), MQTT\'s broker is free infrastructure. If they\'re strictly local (Matter / Thread), CoAP avoids the broker dependency entirely." + note: "MQTT requires a broker; CoAP can work device-to-device. If your devices already need a cloud connection (telemetry, OTA updates), MQTT's broker is free infrastructure. If they're strictly local (Matter / Thread), CoAP avoids the broker dependency entirely." }, { type: 'animated-sequence', @@ -161,7 +161,7 @@ export const iotMessagingStory: SubcategoryStory = { B->>S: PUBREL S-->>B: PUBCOMP`, caption: - "[[mqtt|MQTT]] gives you three reliability tiers at the protocol level. Most production traffic is QoS 1 β€” the sweet spot of \"the broker will retry until acked\" without the 4-message overhead of QoS 2. QoS 2 is rare in practice because most apps prefer idempotent message handlers over exactly-once delivery semantics.", + '[[mqtt|MQTT]] gives you three reliability tiers at the protocol level. Most production traffic is QoS 1 β€” the sweet spot of "the broker will retry until acked" without the 4-message overhead of QoS 2. QoS 2 is rare in practice because most apps prefer idempotent message handlers over exactly-once delivery semantics.', steps: { 0: '**QoS 0 β€” fire and forget.** No acknowledgments, no retransmits. Cheapest, lightest, and zero guarantees. Used for telemetry where losing a sample is fine.', 1: 'Publisher sends a **PUBLISH** to the broker. No message ID is used (because there will be no ack to correlate).', @@ -169,7 +169,7 @@ export const iotMessagingStory: SubcategoryStory = { 3: 'No acks anywhere. If the wireless link dropped the packet, the message is gone β€” the publisher will never know.', 4: '**QoS 1 β€” at least once.** Adds acknowledgments. The publisher retries until the broker acks; the broker retries until each subscriber acks. The trade: a message may be *delivered more than once* if an ack is lost and the sender retries after the original arrived.', 5: 'Publisher sends **PUBLISH with message id 42**. Starts a retransmit timer.', - 6: 'Broker stores the message durably (per the publisher\'s settings) and replies with **PUBACK 42**. Publisher can now discard its in-flight copy.', + 6: "Broker stores the message durably (per the publisher's settings) and replies with **PUBACK 42**. Publisher can now discard its in-flight copy.", 7: 'Broker delivers **PUBLISH 42** to the subscriber.', 8: 'Subscriber acks with **PUBACK 42**. Broker is done.', 9: '**Possible duplicate.** If the PUBACK from broker to publisher is lost, the publisher retries β€” the broker may publish the message twice. This is why QoS 1 demands idempotent message handling.', @@ -188,16 +188,16 @@ export const iotMessagingStory: SubcategoryStory = { { type: 'callout', title: 'Why Facebook Messenger Runs MQTT', - text: `In 2013 Facebook revealed that [[mqtt|MQTT]] was the transport for chat messages in their mobile Messenger app. This raised eyebrows β€” MQTT was designed for oil pipelines, why is the world\'s largest chat product using it?\n\nThe reasons are exactly the reasons MQTT was designed for industrial telemetry:\n\n- **Tiny header.** A standard MQTT message has a 2-byte fixed header. On a flaky cellular link, every byte matters for battery and bandwidth.\n- **Persistent session.** A connected mobile client maintains one long-lived TCP/TLS connection to the broker. Server can push instantly; client doesn\'t have to poll.\n- **Last-will-and-testament.** When a client unexpectedly disconnects, the broker publishes a pre-registered "I just went offline" message to subscribers. This is exactly how Messenger detects "user went offline" without polling.\n- **Wildcard subscriptions.** Subscribe to \`user/123/+\` to get every message type for one user; one subscription scales to many message types.\n- **Battery friendly.** Compared to HTTP polling, MQTT\'s persistent connection costs much less radio time on mobile.\n\nFacebook\'s WhatsApp also runs MQTT for the same reasons. The lesson: a protocol designed for *the most constrained possible client* generalizes well to *any constrained client*. Phones turned out to be constrained clients.` + text: `In 2013 Facebook revealed that [[mqtt|MQTT]] was the transport for chat messages in their mobile Messenger app. This raised eyebrows β€” MQTT was designed for oil pipelines, why is the world's largest chat product using it?\n\nThe reasons are exactly the reasons MQTT was designed for industrial telemetry:\n\n- **Tiny header.** A standard MQTT message has a 2-byte fixed header. On a flaky cellular link, every byte matters for battery and bandwidth.\n- **Persistent session.** A connected mobile client maintains one long-lived TCP/TLS connection to the broker. Server can push instantly; client doesn't have to poll.\n- **Last-will-and-testament.** When a client unexpectedly disconnects, the broker publishes a pre-registered "I just went offline" message to subscribers. This is exactly how Messenger detects "user went offline" without polling.\n- **Wildcard subscriptions.** Subscribe to \`user/123/+\` to get every message type for one user; one subscription scales to many message types.\n- **Battery friendly.** Compared to HTTP polling, MQTT's persistent connection costs much less radio time on mobile.\n\nFacebook's WhatsApp also runs MQTT for the same reasons. The lesson: a protocol designed for *the most constrained possible client* generalizes well to *any constrained client*. Phones turned out to be constrained clients.` }, { type: 'narrative', title: 'The Failure Modes', - text: `[[mqtt|MQTT]]\'s failure mode is **the broker as single point of failure**. The broker is the protocol\'s heart; if it dies, the whole fleet is silent. Production deployments cluster brokers (HiveMQ cluster, EMQX cluster, Amazon\'s sharded IoT Core) and shard topics, but the model is fundamentally centralized. Network partitions create the classic split-brain problems, and reconciling messages published on each side of a partition is non-trivial.\n\n[[coap|CoAP]]\'s failure mode is **NAT and firewall traversal**. CoAP runs on UDP, and most home/enterprise NATs are aggressive about closing UDP "connections" after seconds of idle time. For battery-powered devices that wake every few minutes, this means the NAT mapping is gone every time they want to send. Workarounds (CoAP over DTLS keep-alives, proxied through a hub) exist but add complexity. The protocol\'s minimalism becomes a tax once you leave a Thread mesh and hit a real internet.\n\nBoth share a third failure mode: **device firmware sprawl**. Hundreds of MCU vendors, dozens of MQTT/CoAP libraries, varying TLS support, divergent interpretations of the spec. Interop is often a matter of "this client works with that broker but not the other one." The MQTT 5 specification text exists; the *behavior* on the wire is whatever the broker and library agreed on.` + text: `[[mqtt|MQTT]]'s failure mode is **the broker as single point of failure**. The broker is the protocol's heart; if it dies, the whole fleet is silent. Production deployments cluster brokers (HiveMQ cluster, EMQX cluster, Amazon's sharded IoT Core) and shard topics, but the model is fundamentally centralized. Network partitions create the classic split-brain problems, and reconciling messages published on each side of a partition is non-trivial.\n\n[[coap|CoAP]]'s failure mode is **NAT and firewall traversal**. CoAP runs on UDP, and most home/enterprise NATs are aggressive about closing UDP "connections" after seconds of idle time. For battery-powered devices that wake every few minutes, this means the NAT mapping is gone every time they want to send. Workarounds (CoAP over DTLS keep-alives, proxied through a hub) exist but add complexity. The protocol's minimalism becomes a tax once you leave a Thread mesh and hit a real internet.\n\nBoth share a third failure mode: **device firmware sprawl**. Hundreds of MCU vendors, dozens of MQTT/CoAP libraries, varying TLS support, divergent interpretations of the spec. Interop is often a matter of "this client works with that broker but not the other one." The MQTT 5 specification text exists; the *behavior* on the wire is whatever the broker and library agreed on.` }, { type: 'narrative', - title: 'What\'s Next', + title: "What's Next", text: `Active work in 2025:\n\n- **MQTT over [[quic|QUIC]]** moves through IETF drafts. Better than MQTT-over-TCP on lossy mobile links β€” no transport-layer HoL blocking, faster reconnect after network change. EMQX, HiveMQ, NanoMQ have early implementations.\n- **Sparkplug B** continues spreading in industrial OT (factory floors, energy grids) β€” a layer on top of MQTT that defines device discovery, state, and command/control schemas. Bridges IT-style MQTT to OT-style protocols (Modbus, OPC UA).\n- **Matter / Thread adoption** drives more CoAP into consumer homes. Apple Home, Google Home, Amazon Alexa, SmartThings all support Matter now; CoAP is the wire protocol behind the curtains.\n- **MQTT-SN** (MQTT for Sensor Networks) β€” a UDP version of MQTT for the lowest-end devices β€” sees renewed interest as NB-IoT and LTE-M cellular IoT roll out.\n- **The convergence question**: should IoT consolidate on one protocol (probably MQTT) or maintain the broker-vs-peer-to-peer split? Practical answer for 2025 is probably both, indefinitely.` } ] diff --git a/src/lib/data/subcategory-stories/link-layer.ts b/src/lib/data/subcategory-stories/link-layer.ts index 00ddfba..203961c 100644 --- a/src/lib/data/subcategory-stories/link-layer.ts +++ b/src/lib/data/subcategory-stories/link-layer.ts @@ -3,12 +3,12 @@ import type { SubcategoryStory } from './types'; export const linkLayerStory: SubcategoryStory = { subcategoryId: 'link-layer', tagline: - "How bits cross a single physical segment β€” frames, MAC addresses, and the L2/L3 bridge that holds them together", + 'How bits cross a single physical segment β€” frames, MAC addresses, and the L2/L3 bridge that holds them together', sections: [ { type: 'narrative', title: 'The Layer Underneath Everything', - text: `Every packet on the Internet is wrapped, at the moment it crosses any wire or wireless link, in a **frame**. The frame carries the packet plus the addresses of the two physical endpoints involved in *this hop*. The packet might be making a 14-hop journey across the planet; each hop happens at the link layer, with a fresh frame and a fresh pair of physical addresses.\n\nThe link-layer family in this app has two members because they answer two complementary questions:\n\n- **[[ethernet|Ethernet]]** (IEEE 802.3, 1983) answers *how a frame physically gets across a single segment*. The 48-bit MAC address. The 1500-byte MTU (mostly). The CSMA/CD collision-detection mechanism (now historical, replaced by full-duplex switched links). The Ethernet header is what every IP packet wears when it\'s in transit on a wire β€” even when the underlying technology is Wi-Fi, fiber, or 5G, the protocols above the link mostly assume Ethernet-shaped framing.\n- **[[arp|ARP]]** ([[rfc:826|RFC 826]], 1982) answers *how a sender on a local segment finds the MAC address for the next-hop IP*. It\'s the protocol that lives in the crack between Layer 2 (Ethernet) and Layer 3 (IP). You have a packet destined for 192.168.1.50; you know it\'s on your local subnet; you don\'t know its MAC. ARP broadcasts \"who has 192.168.1.50?\" on the segment; the host with that IP replies; you cache the mapping for a few minutes.\n\nEthernet and ARP together are how packets actually move across the wire under all the higher-layer protocols. They\'re also a perfect example of a *layering crime* that nobody minds: ARP can\'t be neatly placed in either Layer 2 or Layer 3 because it bridges them. The TCP/IP textbook treatment usually calls it "Layer 2.5" and moves on.\n\nThis layer is, ironically, the place where Internet protocols are *most* shaped by physical reality. Frame sizes match Ethernet history. Addresses are 48 bits because that\'s what fit in a Xerox PARC chip in 1980. The number of devices on a segment was constrained by collision dynamics. Forty-five years later, the Layer 2 of a Cloudflare data center is still recognizably the Layer 2 of a 1983 office LAN.` + text: `Every packet on the Internet is wrapped, at the moment it crosses any wire or wireless link, in a **frame**. The frame carries the packet plus the addresses of the two physical endpoints involved in *this hop*. The packet might be making a 14-hop journey across the planet; each hop happens at the link layer, with a fresh frame and a fresh pair of physical addresses.\n\nThe link-layer family in this app has two members because they answer two complementary questions:\n\n- **[[ethernet|Ethernet]]** (IEEE 802.3, 1983) answers *how a frame physically gets across a single segment*. The 48-bit MAC address. The 1500-byte MTU (mostly). The CSMA/CD collision-detection mechanism (now historical, replaced by full-duplex switched links). The Ethernet header is what every IP packet wears when it's in transit on a wire β€” even when the underlying technology is Wi-Fi, fiber, or 5G, the protocols above the link mostly assume Ethernet-shaped framing.\n- **[[arp|ARP]]** ([[rfc:826|RFC 826]], 1982) answers *how a sender on a local segment finds the MAC address for the next-hop IP*. It's the protocol that lives in the crack between Layer 2 (Ethernet) and Layer 3 (IP). You have a packet destined for 192.168.1.50; you know it's on your local subnet; you don't know its MAC. ARP broadcasts "who has 192.168.1.50?" on the segment; the host with that IP replies; you cache the mapping for a few minutes.\n\nEthernet and ARP together are how packets actually move across the wire under all the higher-layer protocols. They're also a perfect example of a *layering crime* that nobody minds: ARP can't be neatly placed in either Layer 2 or Layer 3 because it bridges them. The TCP/IP textbook treatment usually calls it "Layer 2.5" and moves on.\n\nThis layer is, ironically, the place where Internet protocols are *most* shaped by physical reality. Frame sizes match Ethernet history. Addresses are 48 bits because that's what fit in a Xerox PARC chip in 1980. The number of devices on a segment was constrained by collision dynamics. Forty-five years later, the Layer 2 of a Cloudflare data center is still recognizably the Layer 2 of a 1983 office LAN.` }, { type: 'pioneers', @@ -36,7 +36,7 @@ export const linkLayerStory: SubcategoryStory = { id: 'radia-perlman', name: 'Radia Perlman', years: '1951–', - title: '\"Mother of the Internet\" / Spanning Tree Protocol', + title: '"Mother of the Internet" / Spanning Tree Protocol', org: 'DEC / Sun / EMC / Dell', contribution: "Invented the Spanning Tree Protocol (STP, 1985) β€” the algorithm that lets a multi-bridge Ethernet network avoid loops without manual configuration. Without STP, two Ethernet switches connected together would form a broadcast loop that would melt the network in milliseconds. Perlman\\'s algorithm β€” elect a root bridge, compute least-cost path, block redundant ports β€” made Ethernet scale beyond a single segment. Also wrote IS-IS (an IGP routing protocol) and the canonical textbook *Interconnections*." @@ -50,7 +50,7 @@ export const linkLayerStory: SubcategoryStory = { year: 1973, title: 'Ethernet at Xerox PARC', description: - "[[pioneer:bob-metcalfe|Metcalfe]] and [[pioneer:david-boggs|Boggs]] design Ethernet for connecting Alto workstations. Initial design memo dated May 22, 1973. Runs at 2.94 Mbps on a single coaxial cable." + '[[pioneer:bob-metcalfe|Metcalfe]] and [[pioneer:david-boggs|Boggs]] design Ethernet for connecting Alto workstations. Initial design memo dated May 22, 1973. Runs at 2.94 Mbps on a single coaxial cable.' }, { year: 1980, @@ -62,61 +62,61 @@ export const linkLayerStory: SubcategoryStory = { year: 1982, title: 'ARP RFC 826', description: - "[[arp|ARP]] standardized. The protocol that bridges IP addressing and Ethernet MAC addressing β€” sit-at-Layer-2.5 forever." + '[[arp|ARP]] standardized. The protocol that bridges IP addressing and Ethernet MAC addressing β€” sit-at-Layer-2.5 forever.' }, { year: 1983, title: 'IEEE 802.3 Standardized', description: - "The IEEE\'s formal Ethernet standard. Initial differences with DIX (frame format, mostly) caused some incompatibility; the two converged over the next few years." + "The IEEE's formal Ethernet standard. Initial differences with DIX (frame format, mostly) caused some incompatibility; the two converged over the next few years." }, { year: 1985, title: 'Spanning Tree Protocol', description: - "[[pioneer:radia-perlman|Perlman]]\'s STP lets multiple bridges interconnect without creating loops. The protocol\'s correctness is famously elegant; her poem \"Algorhyme\" describes it: \"I think that I shall never see / a graph more lovely than a tree.\"" + '[[pioneer:radia-perlman|Perlman]]\'s STP lets multiple bridges interconnect without creating loops. The protocol\'s correctness is famously elegant; her poem "Algorhyme" describes it: "I think that I shall never see / a graph more lovely than a tree."' }, { year: 1990, title: '10BASE-T β€” Twisted Pair Ethernet', description: - "Star-topology Ethernet over twisted-pair cables and hubs. Eliminates the failure mode of \"one cable break takes down the whole segment.\" Begins Ethernet\'s dominance over Token Ring." + 'Star-topology Ethernet over twisted-pair cables and hubs. Eliminates the failure mode of "one cable break takes down the whole segment." Begins Ethernet\'s dominance over Token Ring.' }, { year: 1995, title: 'Fast Ethernet β€” 100 Mbps', description: - "100BASE-TX β€” 100 Mbps over Cat 5 twisted pair. The version that makes Ethernet boringly fast for the next decade. Full-duplex via switches eliminates collisions." + '100BASE-TX β€” 100 Mbps over Cat 5 twisted pair. The version that makes Ethernet boringly fast for the next decade. Full-duplex via switches eliminates collisions.' }, { year: 1998, title: 'Gigabit Ethernet β€” 1 Gbps', description: - "1000BASE-T. The era when Ethernet stopped being \"the office LAN\" and started being the data-center backbone." + '1000BASE-T. The era when Ethernet stopped being "the office LAN" and started being the data-center backbone.' }, { year: 2003, title: 'Power over Ethernet (802.3af)', description: - "PoE lets Ethernet cables carry power as well as data. Powers VoIP phones, IP cameras, wireless APs without separate power adapters. 802.3at (PoE+, 2009) and 802.3bt (PoE++, 2018) keep raising the power ceiling." + 'PoE lets Ethernet cables carry power as well as data. Powers VoIP phones, IP cameras, wireless APs without separate power adapters. 802.3at (PoE+, 2009) and 802.3bt (PoE++, 2018) keep raising the power ceiling.' }, { year: 2010, title: '40G and 100G Ethernet (802.3ba)', description: - "Ethernet hits data-center scale. 40 Gbps and 100 Gbps over fiber. Subsequent generations: 200/400G (802.3bs, 2017), 800G (802.3df, 2024)." + 'Ethernet hits data-center scale. 40 Gbps and 100 Gbps over fiber. Subsequent generations: 200/400G (802.3bs, 2017), 800G (802.3df, 2024).' }, { year: 2018, title: 'Multi-Gigabit Ethernet (NBASE-T)', description: - "2.5GBASE-T and 5GBASE-T over existing Cat 5e/6 cables. Designed for Wi-Fi 6/6E APs that need >1 Gbps backhaul without recabling the building." + '2.5GBASE-T and 5GBASE-T over existing Cat 5e/6 cables. Designed for Wi-Fi 6/6E APs that need >1 Gbps backhaul without recabling the building.' }, { year: 2024, title: 'Ethernet Everywhere', description: - "Ethernet variants now span 100 Mbps (still in some IoT) to 800 Gbps (data center spines), automotive (10BASE-T1S, single-pair), and TSN (Time-Sensitive Networking) for industrial real-time. The frame format has barely changed since 1980." + 'Ethernet variants now span 100 Mbps (still in some IoT) to 800 Gbps (data center spines), automotive (10BASE-T1S, single-pair), and TSN (Time-Sensitive Networking) for industrial real-time. The frame format has barely changed since 1980.' } ] }, @@ -129,9 +129,9 @@ export const linkLayerStory: SubcategoryStory = { label: '[[ethernet|Ethernet]]', values: [ 'Layer 2 (data link)', - "48-bit MAC addresses (2⁴⁸ β‰ˆ 281 trillion)", - "One physical segment (or VLAN)", - "Switches learn MACs from source addresses of received frames" + '48-bit MAC addresses (2⁴⁸ β‰ˆ 281 trillion)', + 'One physical segment (or VLAN)', + 'Switches learn MACs from source addresses of received frames' ] }, { @@ -140,11 +140,11 @@ export const linkLayerStory: SubcategoryStory = { 'Layer 2.5 (between L2 and L3)', 'Maps IPv4 addresses β†’ MAC addresses', 'One physical segment (or VLAN)', - "Broadcast \"who has X?\" β†’ unicast reply; cache the binding" + 'Broadcast "who has X?" β†’ unicast reply; cache the binding' ] } ], - note: "ARP is IPv4-only. IPv6 replaces it with Neighbor Discovery (ND), which uses ICMPv6 β€” same job, different protocol family. The need for the layer-bridging function never went away." + note: 'ARP is IPv4-only. IPv6 replaces it with Neighbor Discovery (ND), which uses ICMPv6 β€” same job, different protocol family. The need for the layer-bridging function never went away.' }, { type: 'animated-sequence', @@ -169,7 +169,7 @@ export const linkLayerStory: SubcategoryStory = { Note over A,B: Subsequent packets bypass ARP β€” cache hit Note over A: cache entry expires after 2-20 minutes, ARP re-runs`, caption: - "This is the classic Ethernet+ARP exchange. The first message to a new IP triggers an ARP request (broadcast across the segment); subsequent messages use the cached MAC. The switch learns MAC-to-port mappings from source addresses, so once both hosts have sent something, the switch forwards directly without flooding.", + 'This is the classic Ethernet+ARP exchange. The first message to a new IP triggers an ARP request (broadcast across the segment); subsequent messages use the cached MAC. The switch learns MAC-to-port mappings from source addresses, so once both hosts have sent something, the switch forwards directly without flooding.', steps: { 0: '**The problem.** Host A wants to send to IP `10.0.0.7`. The IP layer knows where to send (the destination IP); the Ethernet layer needs a *MAC address* to put in the frame header. ARP bridges these two layers.', 1: '**ARP cache miss.** A checks its local ARP cache first. Nothing there for 10.0.0.7 β€” this is the first time A has talked to B.', @@ -177,13 +177,13 @@ export const linkLayerStory: SubcategoryStory = { 3: 'The switch **floods** the broadcast to every port except the one it came in on. This is what "broadcast domain" means.', 4: 'The broadcast reaches B (and every other host on the segment, but they ignore it).', 5: 'B recognizes its own IP in the request. The other hosts silently drop the frame.', - 6: 'B sends an **ARP REPLY** *unicast* back to A. The reply carries B\'s MAC address (`bb:bb`). Only A needs to hear this.', - 7: 'The switch **learns** that MAC `bb:bb` is reachable through B\'s port. This is the source-MAC learning that makes switches more efficient than hubs.', - 8: 'The switch forwards the reply to A β€” *only* to A\'s port, because the switch knows where A is too.', + 6: "B sends an **ARP REPLY** *unicast* back to A. The reply carries B's MAC address (`bb:bb`). Only A needs to hear this.", + 7: "The switch **learns** that MAC `bb:bb` is reachable through B's port. This is the source-MAC learning that makes switches more efficient than hubs.", + 8: "The switch forwards the reply to A β€” *only* to A's port, because the switch knows where A is too.", 9: 'A **caches** the mapping `10.0.0.7 β†’ bb:bb`. Future packets to 10.0.0.7 skip the ARP step entirely.', - 10: '**Now A can send the real packet.** ARP was just to learn B\'s MAC; the actual data transfer begins here.', + 10: "**Now A can send the real packet.** ARP was just to learn B's MAC; the actual data transfer begins here.", 11: 'A sends an **Ethernet frame** with destination MAC `bb:bb` and the IP packet as the payload.', - 12: 'The switch already knows where `bb:bb` lives. It **forwards to B\'s port only** β€” no flooding.', + 12: "The switch already knows where `bb:bb` lives. It **forwards to B's port only** β€” no flooding.", 13: '**Subsequent packets bypass ARP entirely.** Both sides have cached MACs; the switch has learned port assignments. A 10-Gbps file transfer is just billions of frames following this same path.', 14: '**Cache entries expire** after 2–20 minutes (varies by OS). When they expire, ARP runs again β€” which is why a long-idle connection sometimes has a tiny stutter on its first packet after a pause.' } @@ -191,17 +191,17 @@ export const linkLayerStory: SubcategoryStory = { { type: 'callout', title: 'Why Ethernet Won', - text: `In the late 1970s and early 1980s, the LAN wars had three contenders: **[[ethernet|Ethernet]]** (Xerox/DEC/Intel), **Token Ring** (IBM), and **Token Bus** (later FDDI). For ten years it was unclear which would win. By 1995, Ethernet had won everywhere except inside IBM shops. Why?\n\n**Ethernet was cheap.** Coaxial cable + a tap was cheaper than the complex MAU (Multi-station Attachment Unit) for Token Ring. The economics scaled badly for Ethernet at very high station counts (collisions dominated), but most LANs were small enough that the cost difference mattered more than the performance penalty.\n\n**Ethernet was permissive.** You could mix vendors. Add a new station without configuring the network. Plug things in and they worked. Token Ring required careful ring management; FDDI required ring monitors and station ID coordination. The "just plug it in" property of Ethernet was the same property that would later define Wi-Fi.\n\n**Ethernet evolved.** When 10 Mbps over coax (10BASE-5, 10BASE-2) became limiting, 10BASE-T over twisted pair appeared. When that became limiting, 100BASE-TX. Then 1000BASE-T. Then 10GBASE-T. Each generation reused the cabling investment (mostly) and stayed backward-compatible at the frame format. Token Ring couldn\'t evolve as smoothly; it stayed at 16 Mbps long after Ethernet had gone to 100 and beyond.\n\n**Ethernet abandoned collision detection.** The most distinctive thing about original Ethernet β€” CSMA/CD, where stations sensed the carrier before transmitting and detected collisions during transmission β€” is gone. Modern Ethernet is full-duplex switched. Every station has its own dedicated link to the switch; there are no collisions. The thing that made Ethernet *Ethernet* in the textbook diagram of 1985 doesn\'t exist in any modern deployment. The frame format and addressing survived; the medium-access protocol got replaced wholesale. Few protocols have undergone that level of internal change while keeping the same name.` + text: `In the late 1970s and early 1980s, the LAN wars had three contenders: **[[ethernet|Ethernet]]** (Xerox/DEC/Intel), **Token Ring** (IBM), and **Token Bus** (later FDDI). For ten years it was unclear which would win. By 1995, Ethernet had won everywhere except inside IBM shops. Why?\n\n**Ethernet was cheap.** Coaxial cable + a tap was cheaper than the complex MAU (Multi-station Attachment Unit) for Token Ring. The economics scaled badly for Ethernet at very high station counts (collisions dominated), but most LANs were small enough that the cost difference mattered more than the performance penalty.\n\n**Ethernet was permissive.** You could mix vendors. Add a new station without configuring the network. Plug things in and they worked. Token Ring required careful ring management; FDDI required ring monitors and station ID coordination. The "just plug it in" property of Ethernet was the same property that would later define Wi-Fi.\n\n**Ethernet evolved.** When 10 Mbps over coax (10BASE-5, 10BASE-2) became limiting, 10BASE-T over twisted pair appeared. When that became limiting, 100BASE-TX. Then 1000BASE-T. Then 10GBASE-T. Each generation reused the cabling investment (mostly) and stayed backward-compatible at the frame format. Token Ring couldn't evolve as smoothly; it stayed at 16 Mbps long after Ethernet had gone to 100 and beyond.\n\n**Ethernet abandoned collision detection.** The most distinctive thing about original Ethernet β€” CSMA/CD, where stations sensed the carrier before transmitting and detected collisions during transmission β€” is gone. Modern Ethernet is full-duplex switched. Every station has its own dedicated link to the switch; there are no collisions. The thing that made Ethernet *Ethernet* in the textbook diagram of 1985 doesn't exist in any modern deployment. The frame format and addressing survived; the medium-access protocol got replaced wholesale. Few protocols have undergone that level of internal change while keeping the same name.` }, { type: 'narrative', title: 'The Failure Modes', - text: `[[ethernet|Ethernet]]\'s historical failure mode was the **broadcast storm** β€” connect two switches in a loop, both forward broadcasts to each other, the loop multiplies the traffic exponentially until the network melts in seconds. [[pioneer:radia-perlman|Perlman]]\'s Spanning Tree Protocol (STP, 1985) and its descendants (RSTP, MSTP) elect a topology tree and block redundant ports. Without STP, every multi-switch Ethernet would routinely die from operator error. The modern alternative β€” TRILL, SPB, or just careful manual configuration β€” solves the same problem differently.\n\n[[arp|ARP]]\'s failure mode is **ARP spoofing**. ARP has no authentication. Anyone on the segment can send unsolicited "I\'m 10.0.0.1, MAC = my-MAC" replies; victim hosts cache the lie; their traffic to 10.0.0.1 goes to the attacker. This is the basis of man-in-the-middle attacks on LANs and is trivial to execute (any \`ettercap\` script can do it). Mitigations exist (Dynamic ARP Inspection in enterprise switches, static ARP entries for critical hosts) but require deployment. Most office LANs are still vulnerable.\n\nA third shared failure mode: **MAC flooding**. Switches have finite-size MAC tables. Flooding them with random MAC addresses causes most switches to fall back to "hub mode" (flood everything to every port), letting an attacker passively sniff the segment. Defense: port security with a per-port MAC limit, sticky MAC learning. Again, requires configuration that\'s often skipped.` + text: `[[ethernet|Ethernet]]'s historical failure mode was the **broadcast storm** β€” connect two switches in a loop, both forward broadcasts to each other, the loop multiplies the traffic exponentially until the network melts in seconds. [[pioneer:radia-perlman|Perlman]]'s Spanning Tree Protocol (STP, 1985) and its descendants (RSTP, MSTP) elect a topology tree and block redundant ports. Without STP, every multi-switch Ethernet would routinely die from operator error. The modern alternative β€” TRILL, SPB, or just careful manual configuration β€” solves the same problem differently.\n\n[[arp|ARP]]'s failure mode is **ARP spoofing**. ARP has no authentication. Anyone on the segment can send unsolicited "I'm 10.0.0.1, MAC = my-MAC" replies; victim hosts cache the lie; their traffic to 10.0.0.1 goes to the attacker. This is the basis of man-in-the-middle attacks on LANs and is trivial to execute (any \`ettercap\` script can do it). Mitigations exist (Dynamic ARP Inspection in enterprise switches, static ARP entries for critical hosts) but require deployment. Most office LANs are still vulnerable.\n\nA third shared failure mode: **MAC flooding**. Switches have finite-size MAC tables. Flooding them with random MAC addresses causes most switches to fall back to "hub mode" (flood everything to every port), letting an attacker passively sniff the segment. Defense: port security with a per-port MAC limit, sticky MAC learning. Again, requires configuration that's often skipped.` }, { type: 'narrative', - title: 'What\'s Next', - text: `Active work in 2025:\n\n- **800 Gbps Ethernet** (802.3df, 2024) ships in hyperscaler data centers. 1.6 Tbps is the next target.\n- **Single-pair Ethernet (10BASE-T1S, 100BASE-T1, 1000BASE-T1)** for automotive and industrial. One pair of wires instead of four; multi-drop topology. Replacing CAN bus in cars over the next decade.\n- **TSN β€” Time-Sensitive Networking** brings deterministic latency to Ethernet for industrial control and audio/video. Time-aware shaping, frame preemption, IEEE 802.1AS time sync. The "Ethernet for real-time" story finally credible.\n- **MACsec (802.1AE)** for link-layer encryption. Encrypts frames between switches, separately from IPsec/TLS at higher layers. Standard for hyperscaler east-west traffic.\n- **IPv6 + ND replacing IPv4 + ARP** continues slowly. IPv6 Neighbor Discovery (ND) does ARP\'s job over ICMPv6, with additional features for stateless address autoconfiguration. The transition is ~30% complete by traffic volume, ~5% by deployed device count.\n- **The truth about Ethernet**: the frame format from 1980 is still the frame format. The bandwidth has grown 80,000Γ— (10 Mbps β†’ 800 Gbps). The collision-detection medium-access protocol is gone. The protocol that runs the planet is the protocol that\'s changed everywhere except where its name is.` + title: "What's Next", + text: `Active work in 2025:\n\n- **800 Gbps Ethernet** (802.3df, 2024) ships in hyperscaler data centers. 1.6 Tbps is the next target.\n- **Single-pair Ethernet (10BASE-T1S, 100BASE-T1, 1000BASE-T1)** for automotive and industrial. One pair of wires instead of four; multi-drop topology. Replacing CAN bus in cars over the next decade.\n- **TSN β€” Time-Sensitive Networking** brings deterministic latency to Ethernet for industrial control and audio/video. Time-aware shaping, frame preemption, IEEE 802.1AS time sync. The "Ethernet for real-time" story finally credible.\n- **MACsec (802.1AE)** for link-layer encryption. Encrypts frames between switches, separately from IPsec/TLS at higher layers. Standard for hyperscaler east-west traffic.\n- **IPv6 + ND replacing IPv4 + ARP** continues slowly. IPv6 Neighbor Discovery (ND) does ARP's job over ICMPv6, with additional features for stateless address autoconfiguration. The transition is ~30% complete by traffic volume, ~5% by deployed device count.\n- **The truth about Ethernet**: the frame format from 1980 is still the frame format. The bandwidth has grown 80,000Γ— (10 Mbps β†’ 800 Gbps). The collision-detection medium-access protocol is gone. The protocol that runs the planet is the protocol that's changed everywhere except where its name is.` } ] }; diff --git a/src/lib/data/subcategory-stories/mail-file-transfer.ts b/src/lib/data/subcategory-stories/mail-file-transfer.ts index b9bdc18..be7b59d 100644 --- a/src/lib/data/subcategory-stories/mail-file-transfer.ts +++ b/src/lib/data/subcategory-stories/mail-file-transfer.ts @@ -3,12 +3,12 @@ import type { SubcategoryStory } from './types'; export const mailFileTransferStory: SubcategoryStory = { subcategoryId: 'mail-file-transfer', tagline: - "The oldest application protocols β€” text on the wire, store-and-forward, and the surprising afterlife of 50-year-old designs", + 'The oldest application protocols β€” text on the wire, store-and-forward, and the surprising afterlife of 50-year-old designs', sections: [ { type: 'narrative', title: 'The Survivors of the 1970s', - text: `Long before the World Wide Web, before [[tcp|TCP/IP]], before personal computers, the ARPANET had two killer apps: **file transfer** and **electronic mail**. The protocols that carried them were defined in the early 1970s and β€” astonishingly β€” are still running the world\'s mail and a meaningful chunk of its file transfer in 2025.\n\n- **[[ftp|FTP]]** ([[rfc:114|RFC 114]], 1971; modernized as [[rfc:959|RFC 959]], 1985) is the oldest protocol in this app. It defines two separate connections β€” a *control* connection for commands and a *data* connection for the file itself β€” and a rich set of commands (LIST, RETR, STOR, RNFR, RNTO). FTP\'s design is older than TCP itself; the original ran on NCP, the pre-TCP ARPANET protocol.\n- **[[smtp|SMTP]]** ([[rfc:821|RFC 821]], 1982; modernized as [[rfc:5321|RFC 5321]], 2008) defines how mail servers hand mail to each other. Send a message; the SMTP server takes responsibility for delivering it; if the receiving server is unreachable, queue and retry until success or bounce. The store-and-forward model is the same one Ray Tomlinson invented in 1971 when he chose \`@\` as the separator between user and host.\n- **[[imap|IMAP]]** ([[rfc:1064|RFC 1064]], 1988; current spec [[rfc:3501|RFC 3501]], 2003) is how your mail *client* talks to your mail *server*. Unlike POP3 (which downloads and deletes), IMAP lets the server be the source of truth β€” multiple devices see the same folders, the same read/unread state, the same starred messages.\n\nAll three are *text-based protocols*. You can speak them by hand with a telnet session. They were designed when "the network" meant a few dozen academic machines and "security" meant trusting everyone who had an account. Every modern deployment wraps them in TLS, layers anti-spam on top, and gates them behind authentication β€” but the wire formats are unchanged.\n\nThe 50-year survival of these protocols is the most striking fact about them. Other 1970s designs got swept away. These didn\'t.` + text: `Long before the World Wide Web, before [[tcp|TCP/IP]], before personal computers, the ARPANET had two killer apps: **file transfer** and **electronic mail**. The protocols that carried them were defined in the early 1970s and β€” astonishingly β€” are still running the world's mail and a meaningful chunk of its file transfer in 2025.\n\n- **[[ftp|FTP]]** ([[rfc:114|RFC 114]], 1971; modernized as [[rfc:959|RFC 959]], 1985) is the oldest protocol in this app. It defines two separate connections β€” a *control* connection for commands and a *data* connection for the file itself β€” and a rich set of commands (LIST, RETR, STOR, RNFR, RNTO). FTP's design is older than TCP itself; the original ran on NCP, the pre-TCP ARPANET protocol.\n- **[[smtp|SMTP]]** ([[rfc:821|RFC 821]], 1982; modernized as [[rfc:5321|RFC 5321]], 2008) defines how mail servers hand mail to each other. Send a message; the SMTP server takes responsibility for delivering it; if the receiving server is unreachable, queue and retry until success or bounce. The store-and-forward model is the same one Ray Tomlinson invented in 1971 when he chose \`@\` as the separator between user and host.\n- **[[imap|IMAP]]** ([[rfc:1064|RFC 1064]], 1988; current spec [[rfc:3501|RFC 3501]], 2003) is how your mail *client* talks to your mail *server*. Unlike POP3 (which downloads and deletes), IMAP lets the server be the source of truth β€” multiple devices see the same folders, the same read/unread state, the same starred messages.\n\nAll three are *text-based protocols*. You can speak them by hand with a telnet session. They were designed when "the network" meant a few dozen academic machines and "security" meant trusting everyone who had an account. Every modern deployment wraps them in TLS, layers anti-spam on top, and gates them behind authentication β€” but the wire formats are unchanged.\n\nThe 50-year survival of these protocols is the most striking fact about them. Other 1970s designs got swept away. These didn't.` }, { type: 'pioneers', @@ -21,7 +21,7 @@ export const mailFileTransferStory: SubcategoryStory = { title: 'Inventor of Network Email', org: 'BBN Technologies', contribution: - "Implemented the first network email between two ARPANET hosts in late 1971 using a program called SNDMSG. To distinguish a user\\'s mailbox from a host name, Tomlinson picked the \`@\` symbol from his Model 33 Teletype keyboard β€” a choice that put @ on every business card in the world fifty years later. Email predated the [[smtp|SMTP]] specification by a decade; SMTP came later to standardize what was already happening." + "Implemented the first network email between two ARPANET hosts in late 1971 using a program called SNDMSG. To distinguish a user\\'s mailbox from a host name, Tomlinson picked the `@` symbol from his Model 33 Teletype keyboard β€” a choice that put @ on every business card in the world fifty years later. Email predated the [[smtp|SMTP]] specification by a decade; SMTP came later to standardize what was already happening." }, { id: 'jon-postel', @@ -46,7 +46,7 @@ export const mailFileTransferStory: SubcategoryStory = { title: 'Author of FTP', org: 'MIT', contribution: - "Wrote [[rfc:114|RFC 114]] (1971) β€” the original [[ftp|FTP]] specification, predating TCP/IP. Bhushan was a graduate student at MIT working on the early ARPANET; FTP was needed because researchers wanted to share files between sites and there was no standard way to do it. The protocol has been revised many times (959, 2228, 2428) but the core command-response shape from 1971 remains." + 'Wrote [[rfc:114|RFC 114]] (1971) β€” the original [[ftp|FTP]] specification, predating TCP/IP. Bhushan was a graduate student at MIT working on the early ARPANET; FTP was needed because researchers wanted to share files between sites and there was no standard way to do it. The protocol has been revised many times (959, 2228, 2428) but the core command-response shape from 1971 remains.' } ] }, @@ -57,55 +57,54 @@ export const mailFileTransferStory: SubcategoryStory = { year: 1971, title: 'FTP First Specified (RFC 114)', description: - "Bhushan publishes the first FTP. Originally ran on NCP, the pre-TCP ARPANET protocol. The oldest application protocol still in production use today." + 'Bhushan publishes the first FTP. Originally ran on NCP, the pre-TCP ARPANET protocol. The oldest application protocol still in production use today.' }, { year: 1971, title: 'Ray Tomlinson Sends First Network Email', description: - "Tomlinson uses SNDMSG to send a message between two ARPANET-connected PDP-10s at BBN. Picks \`@\` to separate user from host." + 'Tomlinson uses SNDMSG to send a message between two ARPANET-connected PDP-10s at BBN. Picks `@` to separate user from host.' }, { year: 1982, title: 'SMTP (RFC 821) + Message Format (RFC 822)', description: - "[[pioneer:jon-postel|Postel]] writes the [[smtp|SMTP]] spec, codifying what ARPANET sites had already been doing for a decade. Both RFCs published the same month; both still operational as updated [[rfc:5321|RFC 5321]] and RFC 5322." + '[[pioneer:jon-postel|Postel]] writes the [[smtp|SMTP]] spec, codifying what ARPANET sites had already been doing for a decade. Both RFCs published the same month; both still operational as updated [[rfc:5321|RFC 5321]] and RFC 5322.' }, { year: 1984, title: 'POP1 (RFC 918)', description: - "Post Office Protocol v1 ships β€” \"download mail to my workstation, delete it from the server.\" The right design when your workstation is your only mail device; the wrong design once mobile arrives." + 'Post Office Protocol v1 ships β€” "download mail to my workstation, delete it from the server." The right design when your workstation is your only mail device; the wrong design once mobile arrives.' }, { year: 1985, title: 'FTP RFC 959', description: - "The current [[ftp|FTP]] specification. Cleans up the 1971 design without breaking it. Active vs passive mode is documented; this still trips up firewalls 40 years later." + 'The current [[ftp|FTP]] specification. Cleans up the 1971 design without breaking it. Active vs passive mode is documented; this still trips up firewalls 40 years later.' }, { year: 1988, title: 'IMAP Begins', description: - '[[imap|IMAP]] proposed by Mark Crispin at Stanford. \"What if the server holds canonical state and the client is a view?\" Becomes a long-running counterpoint to POP3.' + '[[imap|IMAP]] proposed by Mark Crispin at Stanford. "What if the server holds canonical state and the client is a view?" Becomes a long-running counterpoint to POP3.' }, { year: 1995, title: 'SFTP and SCP Over SSH', description: - "SCP and SFTP β€” file transfer over [[ssh|SSH]] β€” ship with OpenSSH. Eventually displaces FTP for most secure-file-transfer use cases inside organizations. FTP retreats to anonymous file mirrors." + 'SCP and SFTP β€” file transfer over [[ssh|SSH]] β€” ship with OpenSSH. Eventually displaces FTP for most secure-file-transfer use cases inside organizations. FTP retreats to anonymous file mirrors.' }, { year: 1998, title: 'FTPS β€” FTP Over TLS', description: - "FTPS adds [[tls|TLS]] to FTP\'s control and data connections. Maintains FTP\'s wire protocol; adds encryption. Used heavily in regulated industries (banking, healthcare) where FTP was already deployed." + "FTPS adds [[tls|TLS]] to FTP's control and data connections. Maintains FTP's wire protocol; adds encryption. Used heavily in regulated industries (banking, healthcare) where FTP was already deployed." }, { year: 2003, title: 'IMAP4rev1 (RFC 3501)', - description: - 'The IMAP4rev1 spec used by every modern mail client.' + description: 'The IMAP4rev1 spec used by every modern mail client.' }, { year: 2004, @@ -117,13 +116,13 @@ export const mailFileTransferStory: SubcategoryStory = { year: 2007, title: 'DKIM, SPF Standardized', description: - "DomainKeys Identified Mail and Sender Policy Framework finally give SMTP a way to verify mail origins. {{dmarc|DMARC}} (2015) glues them together with reporting and policy. Spam is reduced from existential threat to manageable nuisance." + 'DomainKeys Identified Mail and Sender Policy Framework finally give SMTP a way to verify mail origins. {{dmarc|DMARC}} (2015) glues them together with reporting and policy. Spam is reduced from existential threat to manageable nuisance.' }, { year: 2018, title: 'JMAP First Stable (RFC 8620)', description: - "Fastmail leads JMAP β€” JSON Meta Application Protocol β€” as a modern HTTP-based replacement for IMAP. Slow adoption; IMAP\'s install base is enormous." + "Fastmail leads JMAP β€” JSON Meta Application Protocol β€” as a modern HTTP-based replacement for IMAP. Slow adoption; IMAP's install base is enormous." }, { year: 2024, @@ -144,7 +143,7 @@ export const mailFileTransferStory: SubcategoryStory = { 'Push β€” sender to receiver', '1 (control + data multiplexed)', 'Originally none; modern: SMTP-AUTH + STARTTLS', - "Mail submission (587) + server-to-server delivery (25)" + 'Mail submission (587) + server-to-server delivery (25)' ] }, { @@ -153,7 +152,7 @@ export const mailFileTransferStory: SubcategoryStory = { 'Pull β€” client reads from server', '1 (with IDLE for push-like behavior)', 'Password (over TLS) or OAuth 2.0', - "Every mail client (Outlook, Apple Mail, Thunderbird, Gmail/iOS); ~all webmail" + 'Every mail client (Outlook, Apple Mail, Thunderbird, Gmail/iOS); ~all webmail' ] }, { @@ -162,7 +161,7 @@ export const mailFileTransferStory: SubcategoryStory = { 'Bidirectional β€” STOR uploads, RETR downloads', '2 (control 21 + data port negotiated)', 'Anonymous or password; FTPS for TLS', - "Public file mirrors, legacy enterprise integration, some scientific data" + 'Public file mirrors, legacy enterprise integration, some scientific data' ] } ], @@ -198,43 +197,43 @@ export const mailFileTransferStory: SubcategoryStory = { U2->>M: IMAP FETCH unread messages M-->>U2: Mail delivered`, caption: - "Email's store-and-forward architecture means there's no end-to-end \"connection\" between sender and recipient. A message hops through one or more MTAs, each taking responsibility before the next, with retries on failure. This is why email tolerates network outages and recipient downtime β€” the queueing was designed in from 1971.", + 'Email\'s store-and-forward architecture means there\'s no end-to-end "connection" between sender and recipient. A message hops through one or more MTAs, each taking responsibility before the next, with retries on failure. This is why email tolerates network outages and recipient downtime β€” the queueing was designed in from 1971.', steps: { - 0: '**Phase 1 β€” Submission.** Alice composes mail in Apple Mail. The MUA submits to *her own provider\'s* SMTP server β€” never directly to the recipient. This separation is what enables spam filtering and authenticated submission.', + 0: "**Phase 1 β€” Submission.** Alice composes mail in Apple Mail. The MUA submits to *her own provider's* SMTP server β€” never directly to the recipient. This separation is what enables spam filtering and authenticated submission.", 1: 'Mail client connects to its submission server on **port 587** with STARTTLS and SMTP-AUTH. Port 25 is server-to-server only on modern networks; submission has its own port.', 2: 'Server accepts and replies **250 OK**, queueing the message. From here, Alice\'s sending is "done" β€” but the message has not yet reached Bob.', 3: '**Phase 2 β€” Lookup.** The sending MTA needs to find where to deliver. It asks DNS.', 4: 'SMTP server asks DNS for the **MX records** of `foo.org`. MX records point at mail servers, with priorities for failover.', 5: 'DNS returns `mx.foo.org` at priority 10 (the lower the priority, the higher the preference β€” yes, backwards from intuition).', - 6: '**Phase 3 β€” Server-to-server relay.** Now the actual SMTP conversation between two organizations\' mail servers.', + 6: "**Phase 3 β€” Server-to-server relay.** Now the actual SMTP conversation between two organizations' mail servers.", 7: 'S1 connects to S2 on **port 25** and negotiates STARTTLS (opportunistic β€” if S2 supports TLS, the conversation gets encrypted; if not, falls back to cleartext).', 8: 'S1 sends **MAIL FROM** β€” declaring the envelope sender. This is the "return-path" used for bounces, not necessarily what the user sees in the From header.', 9: 'S2 accepts the sender with **250 ok**.', 10: 'S1 sends **RCPT TO** β€” one recipient per RCPT command. (Multiple recipients = multiple RCPT TO lines.)', 11: 'S2 accepts the recipient with **250 ok**. (Could reject here for "user does not exist," "mailbox full," etc.)', 12: 'S1 sends **DATA**, then headers, body, and a terminating `CRLF.CRLF`. Everything between is the message proper.', - 13: 'S2 confirms with **250 queued**. The message is now S2\'s responsibility. S1 can delete its copy.', - 14: '**Phase 4 β€” Local delivery.** S2 has accepted the message; now it has to deposit it in Bob\'s mailbox.', - 15: 'S2 hands off via **LMTP** (Local Mail Transfer Protocol) or direct write to the mailbox store. This step happens entirely inside S2\'s infrastructure.', + 13: "S2 confirms with **250 queued**. The message is now S2's responsibility. S1 can delete its copy.", + 14: "**Phase 4 β€” Local delivery.** S2 has accepted the message; now it has to deposit it in Bob's mailbox.", + 15: "S2 hands off via **LMTP** (Local Mail Transfer Protocol) or direct write to the mailbox store. This step happens entirely inside S2's infrastructure.", 16: '**Phase 5 β€” Recipient reads.** Bob is on Gmail. His client never sees SMTP; it uses IMAP to fetch.', - 17: 'Bob\'s mail client sends **IMAP FETCH** to ask for new messages.', - 18: 'Server returns the mail. **From Alice\'s perspective the message was sent hours ago; from Bob\'s perspective it just arrived.** The store-and-forward architecture made each hop independent.' + 17: "Bob's mail client sends **IMAP FETCH** to ask for new messages.", + 18: "Server returns the mail. **From Alice's perspective the message was sent hours ago; from Bob's perspective it just arrived.** The store-and-forward architecture made each hop independent." } }, { type: 'callout', - title: 'Why Email Survived (and FTP Didn\'t Quite)', - text: `[[smtp|SMTP]] is still the world\'s mail transport in 2025. [[ftp|FTP]] is barely alive. Both date from the same era. What\'s the difference?\n\n**Email has no replacement at scale.** Chat protocols (Slack, WhatsApp, iMessage, Teams) are silos β€” Gmail can\'t message a WhatsApp user. Federated chat (XMPP, Matrix) lost the consumer market. The "universal address" property of \`alice@example.com\` β€” anyone can email anyone, no platform required β€” has no successor. As long as that property matters, SMTP runs.\n\n**FTP has obvious replacements.** SFTP (over [[ssh|SSH]]) gives the same file-transfer semantics with encryption and authentication built in. HTTPS lets you serve files with finer-grained access control, resumable downloads, and CDN caching. \`rsync\` does incremental sync better than FTP ever did. \`aws s3 cp\` is what people actually run when they want to "transfer a file" in 2025. FTP had everywhere to go but down.\n\n**Mail accreted modern features without breaking the wire.** Anti-spam (DKIM, SPF, DMARC), TLS encryption (STARTTLS, MTA-STS), authentication (SMTP-AUTH, OAuth 2.0), structured content (MIME), webmail β€” all layered on top of 1982 SMTP without changing the basic envelope-headers-body shape. A 1995 Eudora client can technically still send mail to a Gmail user (Gmail might reject it for spam reasons, but the protocol path works).\n\nFTP\'s active-mode-vs-passive-mode connection complexity and unencrypted-by-default design made it a worse fit for the modern Internet. Mail\'s loose store-and-forward and text-extensibility made it a better one. Sometimes a protocol survives because it\'s exactly the right shape for the next forty years of demand.` + title: "Why Email Survived (and FTP Didn't Quite)", + text: `[[smtp|SMTP]] is still the world's mail transport in 2025. [[ftp|FTP]] is barely alive. Both date from the same era. What's the difference?\n\n**Email has no replacement at scale.** Chat protocols (Slack, WhatsApp, iMessage, Teams) are silos β€” Gmail can't message a WhatsApp user. Federated chat (XMPP, Matrix) lost the consumer market. The "universal address" property of \`alice@example.com\` β€” anyone can email anyone, no platform required β€” has no successor. As long as that property matters, SMTP runs.\n\n**FTP has obvious replacements.** SFTP (over [[ssh|SSH]]) gives the same file-transfer semantics with encryption and authentication built in. HTTPS lets you serve files with finer-grained access control, resumable downloads, and CDN caching. \`rsync\` does incremental sync better than FTP ever did. \`aws s3 cp\` is what people actually run when they want to "transfer a file" in 2025. FTP had everywhere to go but down.\n\n**Mail accreted modern features without breaking the wire.** Anti-spam (DKIM, SPF, DMARC), TLS encryption (STARTTLS, MTA-STS), authentication (SMTP-AUTH, OAuth 2.0), structured content (MIME), webmail β€” all layered on top of 1982 SMTP without changing the basic envelope-headers-body shape. A 1995 Eudora client can technically still send mail to a Gmail user (Gmail might reject it for spam reasons, but the protocol path works).\n\nFTP's active-mode-vs-passive-mode connection complexity and unencrypted-by-default design made it a worse fit for the modern Internet. Mail's loose store-and-forward and text-extensibility made it a better one. Sometimes a protocol survives because it's exactly the right shape for the next forty years of demand.` }, { type: 'narrative', title: 'The Failure Modes', - text: `[[smtp|SMTP]]\'s failure mode is **deliverability**. Sending mail technically still works; getting it into the recipient\'s inbox (not spam folder, not rejected) is a different question. The industry that ranks "sender reputation" β€” IP reputation, domain reputation, content reputation, DKIM alignment, SPF pass, DMARC policy β€” is a billion-dollar market because the SMTP protocol gives the receiving server total discretion to reject. A new domain sending mail to Gmail starts in the spam folder no matter what the headers say. The protocol works; the policy environment is treacherous.\n\n[[imap|IMAP]]\'s failure mode is **performance**. IMAP was designed when "fetching a message" meant a few dozen kilobytes; modern messages have HTML, embedded images, attachments. A folder with 50,000 messages takes IMAP a long time to sync. \`CONDSTORE\`, \`QRESYNC\`, and other extensions try to fix this, but the protocol\'s text-based, line-oriented design fundamentally can\'t hit JMAP-level efficiency. The mobile-app workaround: cache aggressively, sync incrementally, and lie about completeness in the UI.\n\n[[ftp|FTP]]\'s failure mode is **NAT and firewalls**. FTP\'s two-connection design (control + data) was elegant in 1971; in 2025 it\'s a NAT-traversal nightmare. The data connection IP is announced in the control stream (as ASCII text); routers running FTP-ALG try to rewrite this and often fail. Passive mode reverses the connection direction but requires the server to accept connections on dynamic high ports β€” many firewalls block this. The "FTP just doesn\'t work over our network" story is the protocol\'s slow death.` + text: `[[smtp|SMTP]]'s failure mode is **deliverability**. Sending mail technically still works; getting it into the recipient's inbox (not spam folder, not rejected) is a different question. The industry that ranks "sender reputation" β€” IP reputation, domain reputation, content reputation, DKIM alignment, SPF pass, DMARC policy β€” is a billion-dollar market because the SMTP protocol gives the receiving server total discretion to reject. A new domain sending mail to Gmail starts in the spam folder no matter what the headers say. The protocol works; the policy environment is treacherous.\n\n[[imap|IMAP]]'s failure mode is **performance**. IMAP was designed when "fetching a message" meant a few dozen kilobytes; modern messages have HTML, embedded images, attachments. A folder with 50,000 messages takes IMAP a long time to sync. \`CONDSTORE\`, \`QRESYNC\`, and other extensions try to fix this, but the protocol's text-based, line-oriented design fundamentally can't hit JMAP-level efficiency. The mobile-app workaround: cache aggressively, sync incrementally, and lie about completeness in the UI.\n\n[[ftp|FTP]]'s failure mode is **NAT and firewalls**. FTP's two-connection design (control + data) was elegant in 1971; in 2025 it's a NAT-traversal nightmare. The data connection IP is announced in the control stream (as ASCII text); routers running FTP-ALG try to rewrite this and often fail. Passive mode reverses the connection direction but requires the server to accept connections on dynamic high ports β€” many firewalls block this. The "FTP just doesn't work over our network" story is the protocol's slow death.` }, { type: 'narrative', - title: 'What\'s Next', - text: `Active work in 2025:\n\n- **JMAP** (RFC 8620) continues slow adoption as the spiritual IMAP successor. JSON over HTTPS, designed for mobile-first sync. Fastmail uses it natively; Apple Mail, Thunderbird, and Roundcube have client support. The catch: nearly every existing mail server speaks IMAP, and rewriting that side is enormous work.\n- **MTA-STS + DANE + BIMI** continue closing the SMTP security gaps. MTA-STS forces TLS between mail servers using a published policy; DANE binds TLS certs to DNSSEC; BIMI shows brand logos in supporting mail clients. Email\'s security keeps getting better without changing the protocol.\n- **OAuth 2.0 for SMTP/IMAP** β€” Microsoft 365 and Google Workspace require OAuth 2.0 for client mail access. Password-based mail is dying inside enterprises (already gone at Microsoft as of 2022).\n- **Encrypted mail (S/MIME, PGP)** remains niche. Apple Mail and Outlook ship S/MIME for enterprise; consumer adoption is rare. The "no end-to-end encrypted alternative to email at scale" problem is still open.\n- **FTP slow extinction**. Public FTP mirrors (kernel.org, Debian, GNU) have mostly moved to HTTPS. SFTP handles secure file transfer. Cloud object storage (S3, GCS) handles bulk transfer. FTP in 2030 will mostly exist as a legacy compatibility shim in enterprise integration platforms.\n- **The truth about these protocols**: they\'re too embedded to die and too old-fashioned to attract new development. They\'ll outlive most of the protocols designed in the last 20 years.` + title: "What's Next", + text: `Active work in 2025:\n\n- **JMAP** (RFC 8620) continues slow adoption as the spiritual IMAP successor. JSON over HTTPS, designed for mobile-first sync. Fastmail uses it natively; Apple Mail, Thunderbird, and Roundcube have client support. The catch: nearly every existing mail server speaks IMAP, and rewriting that side is enormous work.\n- **MTA-STS + DANE + BIMI** continue closing the SMTP security gaps. MTA-STS forces TLS between mail servers using a published policy; DANE binds TLS certs to DNSSEC; BIMI shows brand logos in supporting mail clients. Email's security keeps getting better without changing the protocol.\n- **OAuth 2.0 for SMTP/IMAP** β€” Microsoft 365 and Google Workspace require OAuth 2.0 for client mail access. Password-based mail is dying inside enterprises (already gone at Microsoft as of 2022).\n- **Encrypted mail (S/MIME, PGP)** remains niche. Apple Mail and Outlook ship S/MIME for enterprise; consumer adoption is rare. The "no end-to-end encrypted alternative to email at scale" problem is still open.\n- **FTP slow extinction**. Public FTP mirrors (kernel.org, Debian, GNU) have mostly moved to HTTPS. SFTP handles secure file transfer. Cloud object storage (S3, GCS) handles bulk transfer. FTP in 2030 will mostly exist as a legacy compatibility shim in enterprise integration platforms.\n- **The truth about these protocols**: they're too embedded to die and too old-fashioned to attract new development. They'll outlive most of the protocols designed in the last 20 years.` } ] }; diff --git a/src/lib/data/subcategory-stories/naming.ts b/src/lib/data/subcategory-stories/naming.ts index b49ef42..4c41bc9 100644 --- a/src/lib/data/subcategory-stories/naming.ts +++ b/src/lib/data/subcategory-stories/naming.ts @@ -3,7 +3,7 @@ import type { SubcategoryStory } from './types'; export const namingStory: SubcategoryStory = { subcategoryId: 'naming', tagline: - "The distributed database that lets humans find machines β€” and the single most consequential cache in computing", + 'The distributed database that lets humans find machines β€” and the single most consequential cache in computing', sections: [ { type: 'narrative', @@ -21,7 +21,7 @@ export const namingStory: SubcategoryStory = { title: 'Inventor of DNS', org: 'USC ISI', contribution: - "Designed and implemented [[dns|DNS]] in 1983 ([[rfc:1034|RFC 1034]], [[rfc:1035|RFC 1035]]). The hierarchical zone-delegation model, the recursive vs iterative split, the resource-record types, the on-the-wire packet format β€” all Mockapetris. The first DNS server was JEEVES, written in TOPS-20 assembler. BIND, the dominant DNS server for the next 35 years, was a clean-room re-implementation by Berkeley grad students using the spec. Mockapetris also chaired the IETF (1994–1996).", + 'Designed and implemented [[dns|DNS]] in 1983 ([[rfc:1034|RFC 1034]], [[rfc:1035|RFC 1035]]). The hierarchical zone-delegation model, the recursive vs iterative split, the resource-record types, the on-the-wire packet format β€” all Mockapetris. The first DNS server was JEEVES, written in TOPS-20 assembler. BIND, the dominant DNS server for the next 35 years, was a clean-room re-implementation by Berkeley grad students using the spec. Mockapetris also chaired the IETF (1994–1996).', imagePath: 'https://upload.wikimedia.org/wikipedia/commons/thumb/3/3e/Paul_Mockapetris.jpg/330px-Paul_Mockapetris.jpg' }, @@ -32,7 +32,7 @@ export const namingStory: SubcategoryStory = { title: 'IANA & Root Zone Steward', org: 'USC ISI', contribution: - "Managed the [[dns|DNS]] root zone and the top-level domain assignments for over a decade as IANA, often single-handedly. The famous \"Postel test\" of January 1998 β€” Postel asked eight of the twelve root servers to temporarily take their root zone from his own server rather than the one operated by Network Solutions, to demonstrate that root authority should be technical, not political. The US government was not amused; ICANN was formed later that year to replace Postel's role with a multi-stakeholder body.", + 'Managed the [[dns|DNS]] root zone and the top-level domain assignments for over a decade as IANA, often single-handedly. The famous "Postel test" of January 1998 β€” Postel asked eight of the twelve root servers to temporarily take their root zone from his own server rather than the one operated by Network Solutions, to demonstrate that root authority should be technical, not political. The US government was not amused; ICANN was formed later that year to replace Postel\'s role with a multi-stakeholder body.', imagePath: 'https://upload.wikimedia.org/wikipedia/commons/thumb/5/53/Jon_Postel_sitting_in_office_%28cropped%29.jpg/330px-Jon_Postel_sitting_in_office_%28cropped%29.jpg' }, @@ -54,19 +54,19 @@ export const namingStory: SubcategoryStory = { year: 1973, title: 'HOSTS.TXT Begins', description: - "Elizabeth Feinler at SRI maintains a single text file mapping ARPANET hosts to addresses. Distribution: FTP overnight." + 'Elizabeth Feinler at SRI maintains a single text file mapping ARPANET hosts to addresses. Distribution: FTP overnight.' }, { year: 1983, title: 'DNS Standardized (RFCs 1034, 1035)', description: - "[[pioneer:paul-mockapetris|Mockapetris]] publishes the design that will run the Internet. Hierarchical namespace, distributed authority, caching." + '[[pioneer:paul-mockapetris|Mockapetris]] publishes the design that will run the Internet. Hierarchical namespace, distributed authority, caching.' }, { year: 1984, title: 'BIND 1.0 Released', description: - "Berkeley Internet Name Domain β€” a clean-room reimplementation by Doug Terry, Mark Painter, David Riggle, and Songnian Zhou. Becomes the dominant DNS server for 30+ years." + 'Berkeley Internet Name Domain β€” a clean-room reimplementation by Doug Terry, Mark Painter, David Riggle, and Songnian Zhou. Becomes the dominant DNS server for 30+ years.' }, { year: 1998, @@ -78,7 +78,7 @@ export const namingStory: SubcategoryStory = { year: 2008, title: 'Kaminsky DNS Cache Poisoning', description: - "Dan Kaminsky discovers that the 16-bit DNS transaction ID is too small to prevent off-path poisoning. Coordinated patch deploys randomized source ports to add ~16 more bits of entropy. The fix is wire-compatible; recursive resolvers everywhere update within months." + 'Dan Kaminsky discovers that the 16-bit DNS transaction ID is too small to prevent off-path poisoning. Coordinated patch deploys randomized source ports to add ~16 more bits of entropy. The fix is wire-compatible; recursive resolvers everywhere update within months.' }, { year: 2010, @@ -96,7 +96,7 @@ export const namingStory: SubcategoryStory = { year: 2018, title: 'DNS over HTTPS (DoH) Standardized (RFC 8484)', description: - "Encapsulating DNS queries in HTTPS to the resolver. Mozilla and Google enable it by default in their browsers, drawing fire from ISPs and governments that relied on DNS visibility for filtering, analytics, and law enforcement." + 'Encapsulating DNS queries in HTTPS to the resolver. Mozilla and Google enable it by default in their browsers, drawing fire from ISPs and governments that relied on DNS visibility for filtering, analytics, and law enforcement.' }, { year: 2022, @@ -128,15 +128,30 @@ export const namingStory: SubcategoryStory = { }, { label: 'DNS over TLS (DoT)', - values: ['[[tcp|TCP]] + [[tls|TLS]]', '853', '[[tls|TLS]] 1.2+', 'OS-level resolvers (Android Private DNS)'] + values: [ + '[[tcp|TCP]] + [[tls|TLS]]', + '853', + '[[tls|TLS]] 1.2+', + 'OS-level resolvers (Android Private DNS)' + ] }, { label: 'DNS over HTTPS (DoH)', - values: ['[[http2|HTTP/2]] + [[tls|TLS]]', '443', '[[tls|TLS]] 1.2+', 'Browser-level (Chrome, Firefox); hides DNS from local network'] + values: [ + '[[http2|HTTP/2]] + [[tls|TLS]]', + '443', + '[[tls|TLS]] 1.2+', + 'Browser-level (Chrome, Firefox); hides DNS from local network' + ] }, { label: 'DNS over QUIC (DoQ)', - values: ['[[quic|QUIC]] (UDP)', '853', 'Mandatory [[tls|TLS]] 1.3', 'Lower latency than DoH; emerging adoption'] + values: [ + '[[quic|QUIC]] (UDP)', + '853', + 'Mandatory [[tls|TLS]] 1.3', + 'Lower latency than DoH; emerging adoption' + ] } ], note: "All four are wire-compatible at the *DNS payload* level. The transport changed; the message format didn't. That's the depth of Mockapetris's original design." @@ -165,7 +180,7 @@ export const namingStory: SubcategoryStory = { caption: "The first query for a name walks the tree β€” root β†’ TLD β†’ authoritative. Every subsequent query within the TTL window is served from the resolver's cache. Caching is what makes DNS *fast*. Cache poisoning is what makes DNS *dangerous*.", steps: { - 0: '**The query begins.** Your laptop wants to load `www.example.com`. The OS asks the configured DNS resolver β€” usually your ISP\'s, or 8.8.8.8, or 1.1.1.1.', + 0: "**The query begins.** Your laptop wants to load `www.example.com`. The OS asks the configured DNS resolver β€” usually your ISP's, or 8.8.8.8, or 1.1.1.1.", 1: 'Client sends the query to its **recursive resolver**. (The client itself is a "stub resolver" β€” it does no work beyond asking once.)', 2: '**Cache miss.** The recursive resolver checks its cache. If it had answered this name in the last TTL window, it would serve from cache and be done. First-time queries β€” and rare names β€” recurse.', 3: 'Resolver asks a **root server**. There are 13 root server addresses (a-m.root-servers.net), heavily anycast-replicated worldwide. The resolver knows them from a built-in hints file.', @@ -191,7 +206,7 @@ export const namingStory: SubcategoryStory = { }, { type: 'narrative', - title: 'What\'s Next', + title: "What's Next", text: `Active work in 2025:\n\n- **{{dnssec|DNSSEC}} validation in stub resolvers** β€” pushed by Apple in iOS/macOS and increasingly enabled by default. The end-to-end chain finally completes when the *client*, not just the recursive resolver, validates signatures.\n- **Encrypted Client Hello (ECH)** uses DNS to publish keys that hide SNI from passive network observers. Now default in Chrome and Firefox; the last metadata leak in TLS is closing.\n- **Oblivious DNS over HTTPS (ODoH)** separates *who is asking* from *what they're asking*. A relay knows the client but not the query; a target knows the query but not the client. Apple's iCloud Private Relay uses a similar architecture.\n- **The political fight over DoH.** Several governments (UK, Russia, China, parts of EU) have moved to restrict or ban encrypted DNS. The protocol is decided; the question of who can run a recursive resolver, and whether ISPs can mandate their own, is not.\n\nThe protocol Mockapetris designed in 1983 is barely changed. Everything new is happening around its edges.` } ] diff --git a/src/lib/data/subcategory-stories/network-services.ts b/src/lib/data/subcategory-stories/network-services.ts index fe22aad..577b10b 100644 --- a/src/lib/data/subcategory-stories/network-services.ts +++ b/src/lib/data/subcategory-stories/network-services.ts @@ -3,12 +3,12 @@ import type { SubcategoryStory } from './types'; export const networkServicesStory: SubcategoryStory = { subcategoryId: 'network-services', tagline: - 'Invisible plumbing β€” the protocols that make a network \"just work\" without anyone configuring anything', + 'Invisible plumbing β€” the protocols that make a network "just work" without anyone configuring anything', sections: [ { type: 'narrative', title: 'The Plumbing You Never See', - text: `When you plug a laptop into a network and a webpage loads, dozens of protocol conversations have already happened β€” none of them initiated by you. They\'re the invisible plumbing, and four protocols dominate that category:\n\n- **[[dhcp|DHCP]]** ([[rfc:2131|RFC 2131]], 1997) handed you an IP address, a subnet mask, a default gateway, and a [[dns|DNS]] resolver. Without it, you\'d have to know all four and type them in. DHCP is why "join a network" is one click.\n- **[[ntp|NTP]]** ([[rfc:5905|RFC 5905]], 2010 β€” earlier RFCs back to 1985) synchronized your clock to within tens of milliseconds of UTC. Modern cryptography depends on accurate clocks (certificates have validity windows; Kerberos tickets have 5-minute skew tolerance; OAuth tokens have \`exp\` claims). NTP is why your laptop\'s clock is right even if you never set it.\n- **[[mdns-dns-sd|mDNS/DNS-SD]]** ([[rfc:6762|RFC 6762]] / [[rfc:6763|RFC 6763]], 2013) made your printer visible to your laptop on the local network with no configuration. Originally Apple\'s Bonjour; standardized via the IETF. Multicast DNS queries on the local link discover \`_printer._tcp.local\`, \`_airplay._tcp.local\`, \`_googlecast._tcp.local\`.\n- **[[nat-traversal|NAT traversal]]** (a family of techniques β€” {{stun|STUN}}, {{turn|TURN}}, {{ice|ICE}}, hole-punching) lets two devices behind different NATs talk directly. Without it, peer-to-peer video calling, online gaming, and decentralized apps would all be impossible (or relayed through expensive servers). The protocol stack that makes "two phones on cellular networks can video-call each other" actually work.\n\nNone of these are protocols you ever choose. They\'re what makes the network *feel* invisible. They\'re also among the most operationally critical pieces of infrastructure on the Internet β€” when DHCP breaks, no one gets online; when NTP drifts, half your security stack starts rejecting connections; when mDNS chatters, your office Wi-Fi gets noisy; when NAT traversal fails, your video call drops.` + text: `When you plug a laptop into a network and a webpage loads, dozens of protocol conversations have already happened β€” none of them initiated by you. They're the invisible plumbing, and four protocols dominate that category:\n\n- **[[dhcp|DHCP]]** ([[rfc:2131|RFC 2131]], 1997) handed you an IP address, a subnet mask, a default gateway, and a [[dns|DNS]] resolver. Without it, you'd have to know all four and type them in. DHCP is why "join a network" is one click.\n- **[[ntp|NTP]]** ([[rfc:5905|RFC 5905]], 2010 β€” earlier RFCs back to 1985) synchronized your clock to within tens of milliseconds of UTC. Modern cryptography depends on accurate clocks (certificates have validity windows; Kerberos tickets have 5-minute skew tolerance; OAuth tokens have \`exp\` claims). NTP is why your laptop's clock is right even if you never set it.\n- **[[mdns-dns-sd|mDNS/DNS-SD]]** ([[rfc:6762|RFC 6762]] / [[rfc:6763|RFC 6763]], 2013) made your printer visible to your laptop on the local network with no configuration. Originally Apple's Bonjour; standardized via the IETF. Multicast DNS queries on the local link discover \`_printer._tcp.local\`, \`_airplay._tcp.local\`, \`_googlecast._tcp.local\`.\n- **[[nat-traversal|NAT traversal]]** (a family of techniques β€” {{stun|STUN}}, {{turn|TURN}}, {{ice|ICE}}, hole-punching) lets two devices behind different NATs talk directly. Without it, peer-to-peer video calling, online gaming, and decentralized apps would all be impossible (or relayed through expensive servers). The protocol stack that makes "two phones on cellular networks can video-call each other" actually work.\n\nNone of these are protocols you ever choose. They're what makes the network *feel* invisible. They're also among the most operationally critical pieces of infrastructure on the Internet β€” when DHCP breaks, no one gets online; when NTP drifts, half your security stack starts rejecting connections; when mDNS chatters, your office Wi-Fi gets noisy; when NAT traversal fails, your video call drops.` }, { type: 'pioneers', @@ -21,7 +21,7 @@ export const networkServicesStory: SubcategoryStory = { title: 'DHCP Implementer / Stewart', org: 'Internet Software Consortium / Apple / Independent', contribution: - "Implemented and maintained ISC DHCP β€” the reference open-source DHCP server and client for two decades β€” and authored major DHCP-related RFCs including IPv6 DHCP, dynamic DNS updates, and the modern DHCPv4 reliability extensions. ISC DHCP shipped in essentially every Linux distribution, BSD, and embedded router for years; Lemon\\'s sustained engineering is one of the reasons \"plug it in and it works\" is a universal expectation." + 'Implemented and maintained ISC DHCP β€” the reference open-source DHCP server and client for two decades β€” and authored major DHCP-related RFCs including IPv6 DHCP, dynamic DNS updates, and the modern DHCPv4 reliability extensions. ISC DHCP shipped in essentially every Linux distribution, BSD, and embedded router for years; Lemon\\\'s sustained engineering is one of the reasons "plug it in and it works" is a universal expectation.' }, { id: 'david-mills', @@ -48,7 +48,7 @@ export const networkServicesStory: SubcategoryStory = { title: 'NAT Traversal Researcher', org: 'MIT / Yale / EPFL', contribution: - "Co-authored the seminal 2005 USENIX paper \"Peer-to-Peer Communication Across Network Address Translators\" with Pyda Srisuresh and Dan Kegel. The paper laid out the taxonomy of NAT behaviors (full cone, restricted cone, port-restricted cone, symmetric) and the hole-punching techniques that became {{stun|STUN}} / {{turn|TURN}} / {{ice|ICE}}. Without this work, modern peer-to-peer (WebRTC, BitTorrent peer discovery, IPFS, blockchain peer networks) would be vastly more expensive or impossible." + 'Co-authored the seminal 2005 USENIX paper "Peer-to-Peer Communication Across Network Address Translators" with Pyda Srisuresh and Dan Kegel. The paper laid out the taxonomy of NAT behaviors (full cone, restricted cone, port-restricted cone, symmetric) and the hole-punching techniques that became {{stun|STUN}} / {{turn|TURN}} / {{ice|ICE}}. Without this work, modern peer-to-peer (WebRTC, BitTorrent peer discovery, IPFS, blockchain peer networks) would be vastly more expensive or impossible.' } ] }, @@ -59,7 +59,7 @@ export const networkServicesStory: SubcategoryStory = { year: 1981, title: 'NTP First Version (RFC 778)', description: - "[[pioneer:david-mills|Mills]] publishes the first NTP version. Time synchronization on the early Internet was previously ad-hoc; NTP would standardize it for 40+ years." + '[[pioneer:david-mills|Mills]] publishes the first NTP version. Time synchronization on the early Internet was previously ad-hoc; NTP would standardize it for 40+ years.' }, { year: 1985, @@ -71,7 +71,7 @@ export const networkServicesStory: SubcategoryStory = { year: 1993, title: 'DHCP RFC 1531', description: - "[[dhcp|DHCP]] extends BOOTP with dynamic address pools and leases. Every workstation can get an address without a configured mapping." + '[[dhcp|DHCP]] extends BOOTP with dynamic address pools and leases. Every workstation can get an address without a configured mapping.' }, { year: 1997, @@ -89,55 +89,55 @@ export const networkServicesStory: SubcategoryStory = { year: 2005, title: 'Bryan Ford Taxonomizes NAT Behavior', description: - "The seminal NAT-traversal paper. Defines hole-punching for [[udp|UDP]] and [[tcp|TCP]] through symmetric NATs. The foundation for WebRTC\'s ICE/STUN/TURN." + "The seminal NAT-traversal paper. Defines hole-punching for [[udp|UDP]] and [[tcp|TCP]] through symmetric NATs. The foundation for WebRTC's ICE/STUN/TURN." }, { year: 2005, title: 'STUN RFC 3489', description: - "Session Traversal Utilities for NAT β€” the first IETF protocol that lets a client behind a NAT learn its public-facing address." + 'Session Traversal Utilities for NAT β€” the first IETF protocol that lets a client behind a NAT learn its public-facing address.' }, { year: 2008, title: 'STUN RFC 5389', description: - "STUN revised. The original protocol\'s name is changed (\"Simple\" β†’ \"Session\") to reflect its role beyond pure address discovery." + 'STUN revised. The original protocol\'s name is changed ("Simple" β†’ "Session") to reflect its role beyond pure address discovery.' }, { year: 2010, title: 'ICE RFC 5245', description: - "Interactive Connectivity Establishment β€” the framework that gathers all possible network candidates and probes connectivity to find the best path between two NAT-bound peers. The foundation of WebRTC NAT traversal." + 'Interactive Connectivity Establishment β€” the framework that gathers all possible network candidates and probes connectivity to find the best path between two NAT-bound peers. The foundation of WebRTC NAT traversal.' }, { year: 2010, title: 'NTP RFC 5905', description: - "The current NTP specification (NTPv4). Adds extension fields, improved security." + 'The current NTP specification (NTPv4). Adds extension fields, improved security.' }, { year: 2013, title: 'mDNS/DNS-SD Standardized (RFCs 6762/6763)', description: - "After a decade of Bonjour-as-Apple, the IETF finalizes the standards. Linux Avahi and Windows native mDNS interop with Apple\'s implementation." + "After a decade of Bonjour-as-Apple, the IETF finalizes the standards. Linux Avahi and Windows native mDNS interop with Apple's implementation." }, { year: 2017, title: 'NTS β€” Network Time Security (RFC 8915 draft)', description: - "NTP gets a modern security story. Authenticated NTP messages without the per-association key configuration NTP authentication had previously required. RFC 8915 publishes in 2020." + 'NTP gets a modern security story. Authenticated NTP messages without the per-association key configuration NTP authentication had previously required. RFC 8915 publishes in 2020.' }, { year: 2020, title: 'NTS RFC 8915', description: - "Network Time Security ships. The first widely-deployable, scalable authenticated NTP. Cloudflare runs time.cloudflare.com with NTS; Netnod, Hetzner, and others follow." + 'Network Time Security ships. The first widely-deployable, scalable authenticated NTP. Cloudflare runs time.cloudflare.com with NTS; Netnod, Hetzner, and others follow.' }, { year: 2024, title: 'IPv6-only Networks Grow', description: - "Apple, T-Mobile, Verizon, and major datacenters run IPv6-only networks with NAT64/DNS64 for legacy IPv4 traffic. NAT traversal still matters because IPv6 firewalls block inbound β€” but the address-exhaustion driver for NAT is fading." + 'Apple, T-Mobile, Verizon, and major datacenters run IPv6-only networks with NAT64/DNS64 for legacy IPv4 traffic. NAT traversal still matters because IPv6 firewalls block inbound β€” but the address-exhaustion driver for NAT is fading.' } ] }, @@ -151,8 +151,8 @@ export const networkServicesStory: SubcategoryStory = { values: [ 'Assigns IP, mask, gateway, DNS', 'When you join the network (and lease renewals)', - "\"No network connection\" β€” you have no IP", - "DHCPv6 (for IPv6 stateful); SLAAC for stateless IPv6" + '"No network connection" β€” you have no IP', + 'DHCPv6 (for IPv6 stateful); SLAAC for stateless IPv6' ] }, { @@ -160,17 +160,17 @@ export const networkServicesStory: SubcategoryStory = { values: [ 'Syncs system clock to UTC', 'Continuously (background)', - "Time wrong β†’ cert errors, auth failures, log analysis chaos", - "NTS (authenticated NTP); chrony as the reference daemon" + 'Time wrong β†’ cert errors, auth failures, log analysis chaos', + 'NTS (authenticated NTP); chrony as the reference daemon' ] }, { label: '[[mdns-dns-sd|mDNS / DNS-SD]]', values: [ 'Local-network name resolution + service discovery', - 'When you ask for a \`.local\` name or browse for a service type', - "\"Printer doesn\'t show up\" β€” service discovery silently fails", - "Used by AirPlay, Chromecast, AirPrint, Matter device commissioning" + 'When you ask for a `.local` name or browse for a service type', + '"Printer doesn\'t show up" β€” service discovery silently fails', + 'Used by AirPlay, Chromecast, AirPrint, Matter device commissioning' ] }, { @@ -178,12 +178,12 @@ export const networkServicesStory: SubcategoryStory = { values: [ 'Establishes peer-to-peer through NATs', 'When two peers want a direct connection', - "Video call goes through a relay (slow), or fails entirely", - "WebRTC, peer-to-peer gaming, BitTorrent, IPFS" + 'Video call goes through a relay (slow), or fails entirely', + 'WebRTC, peer-to-peer gaming, BitTorrent, IPFS' ] } ], - note: "These four are independent β€” your laptop runs DHCP at boot, NTP continuously, mDNS on demand, and ICE only when an app needs peer-to-peer. They\'re grouped here because they\'re what makes \"the network just works.\"" + note: 'These four are independent β€” your laptop runs DHCP at boot, NTP continuously, mDNS on demand, and ICE only when an app needs peer-to-peer. They\'re grouped here because they\'re what makes "the network just works."' }, { type: 'animated-sequence', @@ -207,7 +207,7 @@ export const networkServicesStory: SubcategoryStory = { caption: "DHCP's 4-step DORA (Discover, Offer, Request, Acknowledge) is one of the most-executed protocol exchanges on the Internet. Every laptop on every cafΓ© Wi-Fi runs it within seconds of joining. The broadcast-based design β€” needed because the client has no IP yet β€” is why DHCP is a link-local protocol; it doesn't cross routers without a relay.", steps: { - 0: '**The setup.** A new device joins a network. It has no IP address, doesn\'t know the gateway, has no DNS server. Everything below has to bootstrap from nothing.', + 0: "**The setup.** A new device joins a network. It has no IP address, doesn't know the gateway, has no DNS server. Everything below has to bootstrap from nothing.", 1: '**D β€” Discover.** Client broadcasts a DHCPDISCOVER with source 0.0.0.0 (no IP) and destination 255.255.255.255 (everyone on this segment). The MAC source is the real NIC MAC, so servers can reply.', 2: '**Server sees the broadcast.** Any DHCP server on the segment picks it up. The server checks its address pool and finds a free IP to offer.', 3: '**O β€” Offer.** Server broadcasts a DHCPOFFER (also broadcast because the client has no IP to unicast to yet) offering 192.168.1.42, subnet mask, default gateway, DNS resolver, and lease duration.', @@ -216,7 +216,7 @@ export const networkServicesStory: SubcategoryStory = { 6: '**A β€” Ack.** The chosen server confirms with DHCPACK. The lease is now committed. Default lease is 24 hours in most home routers, longer in enterprise.', 7: '**Configure the interface.** Client sets its IP, subnet mask, default gateway, and DNS resolver from the ACK. The client is now properly on the network.', 8: '**Bootstrap services.** With IP + gateway + DNS, the client can now start NTP (to fix the clock), resolve hostnames, and do whatever the user actually wanted to do.', - 9: '**Lease renewal.** At T/2 elapsed (half the lease), the client tries to renew with the *same* server. This is unicast β€” no need to broadcast since the client knows the server\'s address.', + 9: "**Lease renewal.** At T/2 elapsed (half the lease), the client tries to renew with the *same* server. This is unicast β€” no need to broadcast since the client knows the server's address.", 10: 'Client sends a **unicast DHCPREQUEST** to renew.', 11: 'Server confirms with **DHCPACK**, extending the lease. If the server fails to respond, the client falls back to broadcasting at T*7/8 to find any DHCP server. The address space is reclaimed cleanly when leases expire.' } @@ -224,17 +224,17 @@ export const networkServicesStory: SubcategoryStory = { { type: 'callout', title: 'The NAT Problem in One Paragraph', - text: `**Network Address Translation** was a hack from the 1990s to stretch the IPv4 address space. Your home router gets one public IP from your ISP; it shares that one address across all your devices by mangling the source IP and port of outgoing packets and remembering the mapping so it can route the replies back. It worked. It also broke the fundamental Internet model.\n\nThe original Internet assumption: every host has a globally-routable address and can be reached by any other host. NAT broke that. Behind NAT, *your devices can talk out but the world can\'t talk in*. This is fine for browsing the web β€” you initiate; the server replies. It\'s catastrophic for any protocol where someone needs to call *you* β€” incoming SIP calls, peer-to-peer file sharing, hosted games, decentralized apps.\n\nThe NAT-traversal stack ({{stun|STUN}} / {{turn|TURN}} / {{ice|ICE}}) is the workaround. **{{stun|STUN}}** lets you discover what your public IP+port looks like from outside, so you can publish it. **Hole-punching** is the trick where two peers simultaneously send packets to each other β€” both NATs see "an outgoing packet" and open the return path. **{{turn|TURN}}** is the fallback when hole-punching fails β€” both peers send to a public relay, which forwards. **{{ice|ICE}}** orchestrates trying every candidate and picking the best one.\n\n[[ipv6|IPv6]] was supposed to eliminate the need for all this by giving every device a globally routable address. It mostly hasn\'t β€” IPv6 firewalls still block inbound by default for security reasons, so NAT traversal still applies. The 1990s hack is still everyone\'s problem in 2025.` + text: `**Network Address Translation** was a hack from the 1990s to stretch the IPv4 address space. Your home router gets one public IP from your ISP; it shares that one address across all your devices by mangling the source IP and port of outgoing packets and remembering the mapping so it can route the replies back. It worked. It also broke the fundamental Internet model.\n\nThe original Internet assumption: every host has a globally-routable address and can be reached by any other host. NAT broke that. Behind NAT, *your devices can talk out but the world can't talk in*. This is fine for browsing the web β€” you initiate; the server replies. It's catastrophic for any protocol where someone needs to call *you* β€” incoming SIP calls, peer-to-peer file sharing, hosted games, decentralized apps.\n\nThe NAT-traversal stack ({{stun|STUN}} / {{turn|TURN}} / {{ice|ICE}}) is the workaround. **{{stun|STUN}}** lets you discover what your public IP+port looks like from outside, so you can publish it. **Hole-punching** is the trick where two peers simultaneously send packets to each other β€” both NATs see "an outgoing packet" and open the return path. **{{turn|TURN}}** is the fallback when hole-punching fails β€” both peers send to a public relay, which forwards. **{{ice|ICE}}** orchestrates trying every candidate and picking the best one.\n\n[[ipv6|IPv6]] was supposed to eliminate the need for all this by giving every device a globally routable address. It mostly hasn't β€” IPv6 firewalls still block inbound by default for security reasons, so NAT traversal still applies. The 1990s hack is still everyone's problem in 2025.` }, { type: 'narrative', title: 'The Failure Modes', - text: `[[dhcp|DHCP]]\'s failure mode is **lease conflicts**. If two DHCP servers run on the same broadcast domain (intentionally or by accident β€” someone plugged a home router into the corporate LAN backwards), clients get conflicting addresses and unpredictable connectivity. The classic "rogue DHCP server" incident takes down whole networks until found. The defense β€” DHCP snooping in switches β€” exists but isn\'t universal.\n\n[[ntp|NTP]]\'s failure mode is **trust**. Until NTS (2020), NTP had no authentication in practice. A malicious upstream server could lie about the time, breaking everything downstream that depended on it. NTP also can\'t handle clock jumps gracefully β€” \`ntpdate\` style step adjustments break running processes (Java GC pauses, database transactions, log timestamps). chrony\'s slewing approach (slowly drift the clock toward correct) is the modern answer; pre-chrony NTP just stepped.\n\n[[mdns-dns-sd|mDNS]]\'s failure mode is **traffic on busy networks**. Multicast on a wireless network is sent at the lowest common rate of all clients on the channel; in a conference Wi-Fi with hundreds of devices, mDNS traffic can dominate the network. Apple\'s Bonjour Sleep Proxy and various "mDNS reflector" features in enterprise APs exist to filter the chatter. The 2017 release notes for Cisco/Aruba/Meraki all include some flavor of mDNS optimization.\n\n[[nat-traversal|NAT traversal]]\'s failure mode is **the symmetric NAT**. Most home NATs are well-behaved enough for hole-punching to work; some carrier-grade NATs (CGNAT) used by cellular networks are symmetric β€” they assign a different external port per *destination*. Hole-punching can\'t work in that case; TURN relay is the only option. Roughly 5–15% of WebRTC calls end up requiring TURN; the bandwidth cost for the relay operator is real.` + text: `[[dhcp|DHCP]]'s failure mode is **lease conflicts**. If two DHCP servers run on the same broadcast domain (intentionally or by accident β€” someone plugged a home router into the corporate LAN backwards), clients get conflicting addresses and unpredictable connectivity. The classic "rogue DHCP server" incident takes down whole networks until found. The defense β€” DHCP snooping in switches β€” exists but isn't universal.\n\n[[ntp|NTP]]'s failure mode is **trust**. Until NTS (2020), NTP had no authentication in practice. A malicious upstream server could lie about the time, breaking everything downstream that depended on it. NTP also can't handle clock jumps gracefully β€” \`ntpdate\` style step adjustments break running processes (Java GC pauses, database transactions, log timestamps). chrony's slewing approach (slowly drift the clock toward correct) is the modern answer; pre-chrony NTP just stepped.\n\n[[mdns-dns-sd|mDNS]]'s failure mode is **traffic on busy networks**. Multicast on a wireless network is sent at the lowest common rate of all clients on the channel; in a conference Wi-Fi with hundreds of devices, mDNS traffic can dominate the network. Apple's Bonjour Sleep Proxy and various "mDNS reflector" features in enterprise APs exist to filter the chatter. The 2017 release notes for Cisco/Aruba/Meraki all include some flavor of mDNS optimization.\n\n[[nat-traversal|NAT traversal]]'s failure mode is **the symmetric NAT**. Most home NATs are well-behaved enough for hole-punching to work; some carrier-grade NATs (CGNAT) used by cellular networks are symmetric β€” they assign a different external port per *destination*. Hole-punching can't work in that case; TURN relay is the only option. Roughly 5–15% of WebRTC calls end up requiring TURN; the bandwidth cost for the relay operator is real.` }, { type: 'narrative', - title: 'What\'s Next', - text: `Active work in 2025:\n\n- **NTS** (Network Time Security) is rolling out at major time providers (Cloudflare, Netnod). The first credible authenticated NTP in production. NTP\'s 40-year security gap is finally closing.\n- **DHCP options for IoT** β€” DHCPv6 keeps getting options for device-management URLs, manufacturer hints, and Matter commissioning. Even DHCP β€” designed in 1993 β€” keeps growing.\n- **Matter / Thread commissioning** uses mDNS extensively for device discovery on the home network. The Matter spec mandates DNS-SD service browsing for smart-home device pairing β€” extending Bonjour into every consumer-IoT product.\n- **IPv6-only networks** + NAT64 + DNS64 are growing in mobile carriers and datacenter networks. The "every device has a routable address" promise is finally semi-real; NAT traversal still matters because firewalls still block inbound, but the variety of NAT pathologies is reducing.\n- **Tailscale-style mesh VPNs** (Tailscale, Headscale, Netbird, NetMaker) are essentially "NAT traversal as a service" β€” they bundle STUN/TURN/ICE, key management, and routing into one product. The protocols underneath are the same ICE family; the developer experience is finally good.\n- **TLS-protected DHCP** (DHCP over TLS) remains a niche request. DHCP\'s plaintext design is increasingly out of step with the rest of the network stack, but the broadcast-based first-message design is hard to encrypt.\n- **The truth about these protocols**: they don\'t need to change much. The job is invisible, the protocols mostly work, the operational pain is in the configuration and tooling around them rather than in the protocols themselves.` + title: "What's Next", + text: `Active work in 2025:\n\n- **NTS** (Network Time Security) is rolling out at major time providers (Cloudflare, Netnod). The first credible authenticated NTP in production. NTP's 40-year security gap is finally closing.\n- **DHCP options for IoT** β€” DHCPv6 keeps getting options for device-management URLs, manufacturer hints, and Matter commissioning. Even DHCP β€” designed in 1993 β€” keeps growing.\n- **Matter / Thread commissioning** uses mDNS extensively for device discovery on the home network. The Matter spec mandates DNS-SD service browsing for smart-home device pairing β€” extending Bonjour into every consumer-IoT product.\n- **IPv6-only networks** + NAT64 + DNS64 are growing in mobile carriers and datacenter networks. The "every device has a routable address" promise is finally semi-real; NAT traversal still matters because firewalls still block inbound, but the variety of NAT pathologies is reducing.\n- **Tailscale-style mesh VPNs** (Tailscale, Headscale, Netbird, NetMaker) are essentially "NAT traversal as a service" β€” they bundle STUN/TURN/ICE, key management, and routing into one product. The protocols underneath are the same ICE family; the developer experience is finally good.\n- **TLS-protected DHCP** (DHCP over TLS) remains a niche request. DHCP's plaintext design is increasingly out of step with the rest of the network stack, but the broadcast-based first-message design is hard to encrypt.\n- **The truth about these protocols**: they don't need to change much. The job is invisible, the protocols mostly work, the operational pain is in the configuration and tooling around them rather than in the protocols themselves.` } ] }; diff --git a/src/lib/data/subcategory-stories/pan-proximity.ts b/src/lib/data/subcategory-stories/pan-proximity.ts index 6d30fb9..f1eb35c 100644 --- a/src/lib/data/subcategory-stories/pan-proximity.ts +++ b/src/lib/data/subcategory-stories/pan-proximity.ts @@ -2,13 +2,12 @@ import type { SubcategoryStory } from './types'; export const panProximityStory: SubcategoryStory = { subcategoryId: 'pan-proximity', - tagline: - "Short-range wireless β€” four protocols for four different versions of \"close\"", + tagline: 'Short-range wireless β€” four protocols for four different versions of "close"', sections: [ { type: 'narrative', - title: 'Different Definitions of \"Nearby\"', - text: `Within ten meters of any office desk in 2025 there are probably a dozen wireless protocols in active use. Not Wi-Fi β€” different protocols, each optimized for a different mix of *range*, *power*, *bandwidth*, and *topology*. They\'re the Personal Area Network (PAN) and proximity family.\n\n- **[[bluetooth|Bluetooth]]** (1998–) covers ~10 meters at moderate power, gigabit-class speeds on the latest standards. Originated as a cable replacement (named after a 10th-century Viking king who united warring tribes β€” the metaphor was uniting incompatible serial standards). Now the universal wireless for headphones, keyboards, fitness trackers, beacons, IoT.\n- **[[nfc|NFC]]** (2002–) covers ~4 *centimeters*. Almost-touching range, deliberately. Powers contactless payments (Apple Pay, Google Pay), transit cards, key fobs, tap-to-share, ID verification. The short range is the security feature.\n- **[[uwb|Ultra-Wideband]]** (UWB, mid-2000s commercial; revived 2019–) covers ~50 meters with *centimeter-accurate ranging*. Spread across a wide frequency band so it can be used alongside other protocols without interference. Apple AirTags, Samsung SmartTag+, BMW digital car keys, indoor positioning.\n- **[[zigbee|Zigbee]]** (2003–) covers tens of meters per hop, but builds **multi-hop mesh networks** so a single mesh can cover an entire building. Low power, low data rate, designed for battery-operated sensors and actuators. Powers smart-home devices (Philips Hue bulbs, IKEA Tradfri, Aqara sensors) and industrial automation.\n\nThese aren\'t alternatives. They\'re different points in a four-dimensional design space (range Γ— bandwidth Γ— power Γ— topology). Your phone has hardware for all four. Your smart home runs three of them simultaneously. The fragmentation is a feature β€” no single protocol could serve all the use cases optimally.` + title: 'Different Definitions of "Nearby"', + text: `Within ten meters of any office desk in 2025 there are probably a dozen wireless protocols in active use. Not Wi-Fi β€” different protocols, each optimized for a different mix of *range*, *power*, *bandwidth*, and *topology*. They're the Personal Area Network (PAN) and proximity family.\n\n- **[[bluetooth|Bluetooth]]** (1998–) covers ~10 meters at moderate power, gigabit-class speeds on the latest standards. Originated as a cable replacement (named after a 10th-century Viking king who united warring tribes β€” the metaphor was uniting incompatible serial standards). Now the universal wireless for headphones, keyboards, fitness trackers, beacons, IoT.\n- **[[nfc|NFC]]** (2002–) covers ~4 *centimeters*. Almost-touching range, deliberately. Powers contactless payments (Apple Pay, Google Pay), transit cards, key fobs, tap-to-share, ID verification. The short range is the security feature.\n- **[[uwb|Ultra-Wideband]]** (UWB, mid-2000s commercial; revived 2019–) covers ~50 meters with *centimeter-accurate ranging*. Spread across a wide frequency band so it can be used alongside other protocols without interference. Apple AirTags, Samsung SmartTag+, BMW digital car keys, indoor positioning.\n- **[[zigbee|Zigbee]]** (2003–) covers tens of meters per hop, but builds **multi-hop mesh networks** so a single mesh can cover an entire building. Low power, low data rate, designed for battery-operated sensors and actuators. Powers smart-home devices (Philips Hue bulbs, IKEA Tradfri, Aqara sensors) and industrial automation.\n\nThese aren't alternatives. They're different points in a four-dimensional design space (range Γ— bandwidth Γ— power Γ— topology). Your phone has hardware for all four. Your smart home runs three of them simultaneously. The fragmentation is a feature β€” no single protocol could serve all the use cases optimally.` }, { type: 'pioneers', @@ -18,19 +17,19 @@ export const panProximityStory: SubcategoryStory = { id: 'jaap-haartsen', name: 'Jaap Haartsen', years: '1963–', - title: '\"Father of Bluetooth\"', + title: '"Father of Bluetooth"', org: 'Ericsson', contribution: - "Designed [[bluetooth|Bluetooth]] at Ericsson in 1994. The original use case was eliminating the cable between a phone and a headset; the architecture (small piconets, frequency hopping for interference resilience, master/slave roles) scaled to almost any short-range use case. The protocol was named for the 10th-century Danish king Harald Bluetooth, who united Scandinavian tribes β€” the metaphor was uniting incompatible mobile-device standards. Haartsen and his Ericsson team partnered with IBM, Intel, Nokia, and Toshiba to form the Bluetooth SIG in 1998." + 'Designed [[bluetooth|Bluetooth]] at Ericsson in 1994. The original use case was eliminating the cable between a phone and a headset; the architecture (small piconets, frequency hopping for interference resilience, master/slave roles) scaled to almost any short-range use case. The protocol was named for the 10th-century Danish king Harald Bluetooth, who united Scandinavian tribes β€” the metaphor was uniting incompatible mobile-device standards. Haartsen and his Ericsson team partnered with IBM, Intel, Nokia, and Toshiba to form the Bluetooth SIG in 1998.' }, { id: 'charles-walton', name: 'Charles Walton', years: '1921–2011', - title: '\"Father of RFID\"', + title: '"Father of RFID"', org: 'Independent / Proximity Devices', contribution: - "Patented (1973) the first portable RFID system β€” a passive, battery-less tag that could be read by a nearby reader. The patent expired in 1990; the technology underpinned everything from livestock tracking to building access control to (eventually) [[nfc|NFC]] payment. NFC is structurally a descendant of Walton\\'s RFID β€” same near-field magnetic coupling, same passive-tag option, with bidirectional data exchange added on top. Walton reportedly earned about \$3 million in license fees from the patent." + "Patented (1973) the first portable RFID system β€” a passive, battery-less tag that could be read by a nearby reader. The patent expired in 1990; the technology underpinned everything from livestock tracking to building access control to (eventually) [[nfc|NFC]] payment. NFC is structurally a descendant of Walton\\'s RFID β€” same near-field magnetic coupling, same passive-tag option, with bidirectional data exchange added on top. Walton reportedly earned about $3 million in license fees from the patent." }, { id: 'larry-fullerton', @@ -59,85 +58,85 @@ export const panProximityStory: SubcategoryStory = { year: 1973, title: 'RFID First Patent', description: - "[[pioneer:charles-walton|Walton]] patents the first portable RFID system β€” passive tags read by nearby readers. The basis for NFC three decades later." + '[[pioneer:charles-walton|Walton]] patents the first portable RFID system β€” passive tags read by nearby readers. The basis for NFC three decades later.' }, { year: 1994, title: 'Bluetooth Conceived at Ericsson', description: - "[[pioneer:jaap-haartsen|Haartsen]] starts [[bluetooth|Bluetooth]] at Ericsson as a cable-replacement technology for phones and accessories." + '[[pioneer:jaap-haartsen|Haartsen]] starts [[bluetooth|Bluetooth]] at Ericsson as a cable-replacement technology for phones and accessories.' }, { year: 1998, title: 'Bluetooth SIG Founded', description: - "Ericsson, IBM, Intel, Nokia, Toshiba form the Bluetooth Special Interest Group. Bluetooth 1.0 ships in 1999." + 'Ericsson, IBM, Intel, Nokia, Toshiba form the Bluetooth Special Interest Group. Bluetooth 1.0 ships in 1999.' }, { year: 2002, title: 'FCC Approves Commercial UWB', description: - "Federal Communications Commission opens unlicensed [[uwb|ultra-wideband]] operation in the 3.1–10.6 GHz range. Time Domain, Freescale, Intel all start commercial UWB development." + 'Federal Communications Commission opens unlicensed [[uwb|ultra-wideband]] operation in the 3.1–10.6 GHz range. Time Domain, Freescale, Intel all start commercial UWB development.' }, { year: 2002, title: 'NFC Forum Founded', description: - "Nokia, Philips, and Sony form the NFC Forum to standardize what would become contactless payment, transit, and proximity-pairing on phones." + 'Nokia, Philips, and Sony form the NFC Forum to standardize what would become contactless payment, transit, and proximity-pairing on phones.' }, { year: 2003, title: 'Zigbee Alliance Formed', description: - "[[zigbee|Zigbee]] launches as a low-power mesh networking standard for sensors and actuators. ZigBee 1.0 ships in 2004." + '[[zigbee|Zigbee]] launches as a low-power mesh networking standard for sensors and actuators. ZigBee 1.0 ships in 2004.' }, { year: 2006, title: 'NFC RFID Standards (ISO/IEC 18092)', description: - "NFC standardized at ISO. Supports passive tags (like Walton\'s RFID), reader/writer mode, and peer-to-peer mode." + "NFC standardized at ISO. Supports passive tags (like Walton's RFID), reader/writer mode, and peer-to-peer mode." }, { year: 2010, title: 'Bluetooth 4.0 β€” BLE', description: - "Bluetooth Low Energy (BLE) ships β€” a fundamental redesign for sub-milliwatt power, suitable for coin-cell batteries lasting years. The breakthrough that makes \"the IoT\" practical for sensor-class devices." + 'Bluetooth Low Energy (BLE) ships β€” a fundamental redesign for sub-milliwatt power, suitable for coin-cell batteries lasting years. The breakthrough that makes "the IoT" practical for sensor-class devices.' }, { year: 2014, title: 'Apple Pay Launches', description: - "Apple Pay uses NFC for in-store contactless payment. Drives mainstream consumer awareness of NFC; within two years, every major Android phone has matching support." + 'Apple Pay uses NFC for in-store contactless payment. Drives mainstream consumer awareness of NFC; within two years, every major Android phone has matching support.' }, { year: 2015, title: 'Bluetooth Mesh', description: - "Bluetooth SIG adds mesh networking, competing directly with Zigbee for smart-home and industrial use cases." + 'Bluetooth SIG adds mesh networking, competing directly with Zigbee for smart-home and industrial use cases.' }, { year: 2019, title: 'Apple iPhone 11 β€” U1 Chip / UWB', description: - "Apple ships UWB in iPhone 11 with the U1 chip. The first mainstream consumer device with precision-ranging UWB. AirDrop becomes direction-aware; AirTags ship in 2021 using UWB for precise finding." + 'Apple ships UWB in iPhone 11 with the U1 chip. The first mainstream consumer device with precision-ranging UWB. AirDrop becomes direction-aware; AirTags ship in 2021 using UWB for precise finding.' }, { year: 2020, title: 'BMW Digital Key Plus β€” UWB Car Access', description: - "BMW launches Digital Key Plus using UWB. Your iPhone is now a car key with precise proximity awareness (the car detects when you walk up to it from outside, vs sit in the driver\'s seat)." + "BMW launches Digital Key Plus using UWB. Your iPhone is now a car key with precise proximity awareness (the car detects when you walk up to it from outside, vs sit in the driver's seat)." }, { year: 2022, title: 'Matter Launches (Thread + Wi-Fi)', description: - "Apple, Google, Amazon, and Samsung\'s unified smart-home protocol uses Thread (an IPv6 mesh, similar layer to Zigbee) and Wi-Fi. Zigbee continues to coexist; new devices increasingly bridge to Matter." + "Apple, Google, Amazon, and Samsung's unified smart-home protocol uses Thread (an IPv6 mesh, similar layer to Zigbee) and Wi-Fi. Zigbee continues to coexist; new devices increasingly bridge to Matter." }, { year: 2024, title: 'Bluetooth 6.0 β€” Channel Sounding', description: - "Bluetooth gains UWB-like precision ranging via Channel Sounding. The boundary between BT and UWB blurs for proximity use cases." + 'Bluetooth gains UWB-like precision ranging via Channel Sounding. The boundary between BT and UWB blurs for proximity use cases.' } ] }, @@ -151,9 +150,9 @@ export const panProximityStory: SubcategoryStory = { values: [ '~10 m (Class 2); ~100 m (Class 1)', '~2 Mbps (BLE 5) to ~50 Mbps (BR/EDR)', - "BLE: ΞΌW–mW; classic: tens of mW", - "Star (piconet, master + ≀7 slaves); now mesh too", - "Headphones, keyboards, fitness trackers, beacons" + 'BLE: ΞΌW–mW; classic: tens of mW', + 'Star (piconet, master + ≀7 slaves); now mesh too', + 'Headphones, keyboards, fitness trackers, beacons' ] }, { @@ -161,9 +160,9 @@ export const panProximityStory: SubcategoryStory = { values: [ '~4 cm', '~424 Kbps', - "Passive tag: zero (powered by reader\'s field)", - "Reader + passive tag, or peer-to-peer", - "Contactless payment, transit, key cards, tap-to-share" + "Passive tag: zero (powered by reader's field)", + 'Reader + passive tag, or peer-to-peer', + 'Contactless payment, transit, key cards, tap-to-share' ] }, { @@ -171,9 +170,9 @@ export const panProximityStory: SubcategoryStory = { values: [ '~50 m line of sight', '~110 Mbps (rarely used at full rate)', - "Tens of mW per measurement, idle off", - "Anchor + tag, or peer-to-peer", - "Precise indoor/asset location, AirTag-class finding, secure car key" + 'Tens of mW per measurement, idle off', + 'Anchor + tag, or peer-to-peer', + 'Precise indoor/asset location, AirTag-class finding, secure car key' ] }, { @@ -181,9 +180,9 @@ export const panProximityStory: SubcategoryStory = { values: [ '~10–30 m per hop, building-scale via mesh', '~250 Kbps', - "ΞΌW–mW (designed for coin-cell years)", - "Mesh β€” every router-class node forwards for others", - "Smart-home (bulbs, sensors, switches), industrial automation" + 'ΞΌW–mW (designed for coin-cell years)', + 'Mesh β€” every router-class node forwards for others', + 'Smart-home (bulbs, sensors, switches), industrial automation' ] } ], @@ -215,10 +214,10 @@ export const panProximityStory: SubcategoryStory = { "[[bluetooth|BLE]]'s advertising-then-connect dance is what lets sensor-class devices run on coin cells for years. The peripheral broadcasts a small ADV packet at long intervals; the central scans and connects on demand. Once connected, both sides wake briefly per connection interval and sleep otherwise. Average current is microamps.", steps: { 0: '**Phase 1 β€” Advertising.** A BLE peripheral (smartwatch, sensor, beacon) advertises its presence by broadcasting on three known channels. The central (your phone) scans those channels passively.', - 1: 'Peripheral wakes every 100ms–1s and **broadcasts an ADV_IND packet** on channels 37, 38, and 39 (BLE\'s three advertising channels). When sleeping, it draws microamps.', + 1: "Peripheral wakes every 100ms–1s and **broadcasts an ADV_IND packet** on channels 37, 38, and 39 (BLE's three advertising channels). When sleeping, it draws microamps.", 2: '**Central scans** the same three channels. Most of the time central is also off; it wakes to scan briefly. Both sides spend almost no time on.', - 3: 'Central catches an ADV_IND. The packet carries a UUID identifying the device or service, the peripheral\'s name, and its signal strength (RSSI).', - 4: 'Central may optionally send a **SCAN_REQ** to ask for more advertising data the peripheral didn\'t fit in the initial ADV.', + 3: "Central catches an ADV_IND. The packet carries a UUID identifying the device or service, the peripheral's name, and its signal strength (RSSI).", + 4: "Central may optionally send a **SCAN_REQ** to ask for more advertising data the peripheral didn't fit in the initial ADV.", 5: 'Peripheral replies with **SCAN_RSP** carrying additional metadata.', 6: '**Phase 2 β€” Connection request.** Central decides to connect.', 7: 'Central sends **CONNECT_REQ** with connection parameters: how often the two will exchange data (interval), how many intervals the peripheral can skip if it has nothing to say (latency), how long without contact before the connection is declared dead (supervision timeout).', @@ -235,17 +234,17 @@ export const panProximityStory: SubcategoryStory = { { type: 'callout', title: 'Why Short Range Is a Feature', - text: `Engineering instinct says "longer range is always better." For short-range wireless, that instinct is wrong. Short range is a *feature*, not a limitation.\n\n**[[nfc|NFC]]\'s 4 cm is a security primitive.** Your phone can\'t be NFC-eavesdropped from across the room. To skim your contactless card, an attacker must physically touch (or come within a few cm of) you. Compare this to RFID-equipped passport designs, which were *deliberately* given short range so they couldn\'t be remotely scanned. Range is part of the threat model.\n\n**[[zigbee|Zigbee]]\'s short per-hop range enables mesh resilience.** A bulb 100 meters from the controller can\'t hear it directly β€” but six bulbs in between can each hop the message. If one bulb fails, the mesh routes around it. A long-range broadcast protocol would have one giant collision domain; the short-range mesh is built around it.\n\n**[[uwb|UWB]]\'s wide bandwidth at low power gives centimeter ranging.** Most radios measure distance crudely (signal strength, basically); UWB pulses are so short that the propagation time can be measured directly. Time-of-flight measurement at GHz bandwidths gives ~10 cm precision. AirTags would be much less useful if they could only tell you "somewhere in your house"; the precise-finding mode lets your iPhone show you a direction arrow.\n\n**[[bluetooth|Bluetooth]]\'s 10 meter range matches the form factor.** Your earbuds need to talk to your phone in your pocket, not your phone two rooms away. Higher power would waste battery; longer range would expose more devices to interference.\n\nEach of these protocols is *deliberately* short range because that\'s what their use case demands. The "long range is better" instinct comes from cellular and Wi-Fi, where coverage is the value proposition. For proximity wireless, *limited* coverage *is* the value proposition.` + text: `Engineering instinct says "longer range is always better." For short-range wireless, that instinct is wrong. Short range is a *feature*, not a limitation.\n\n**[[nfc|NFC]]'s 4 cm is a security primitive.** Your phone can't be NFC-eavesdropped from across the room. To skim your contactless card, an attacker must physically touch (or come within a few cm of) you. Compare this to RFID-equipped passport designs, which were *deliberately* given short range so they couldn't be remotely scanned. Range is part of the threat model.\n\n**[[zigbee|Zigbee]]'s short per-hop range enables mesh resilience.** A bulb 100 meters from the controller can't hear it directly β€” but six bulbs in between can each hop the message. If one bulb fails, the mesh routes around it. A long-range broadcast protocol would have one giant collision domain; the short-range mesh is built around it.\n\n**[[uwb|UWB]]'s wide bandwidth at low power gives centimeter ranging.** Most radios measure distance crudely (signal strength, basically); UWB pulses are so short that the propagation time can be measured directly. Time-of-flight measurement at GHz bandwidths gives ~10 cm precision. AirTags would be much less useful if they could only tell you "somewhere in your house"; the precise-finding mode lets your iPhone show you a direction arrow.\n\n**[[bluetooth|Bluetooth]]'s 10 meter range matches the form factor.** Your earbuds need to talk to your phone in your pocket, not your phone two rooms away. Higher power would waste battery; longer range would expose more devices to interference.\n\nEach of these protocols is *deliberately* short range because that's what their use case demands. The "long range is better" instinct comes from cellular and Wi-Fi, where coverage is the value proposition. For proximity wireless, *limited* coverage *is* the value proposition.` }, { type: 'narrative', title: 'The Failure Modes', - text: `[[bluetooth|Bluetooth]]\'s failure mode is **pairing UX**. The classic Bluetooth pairing flow (long press the button, find on the phone, enter PIN, accept) is consistently rated one of the worst UX moments in consumer electronics. Apple\'s Magic Pairing (a proprietary extension) made AirPods drastically better than generic BT pairing. The BT SIG\'s answer β€” Cross-Transport Key Derivation, Fast Pair β€” addresses some of the worst, but generic Bluetooth pairing is still a frequent support call. Security-wise, multiple specs (KNOB, BIAS, BLUFFS, BLESA) have shown serial weaknesses in BT pairing crypto; the SIG patches and the cycle continues.\n\n[[nfc|NFC]]\'s failure mode is **the misread**. NFC requires near-touching alignment between reader antenna and tag antenna. Misaligned passes β€” bag tap-to-pay on an awkwardly-angled reader β€” fail silently. Modern phones include haptic feedback for successful taps; older systems just left you wondering if it worked. NFC has no security failure mode worth mentioning β€” the 4 cm range is the defense.\n\n[[uwb|UWB]]\'s failure mode is **multipath**. Indoor environments reflect radio waves off walls; UWB\'s precision ranging can be confused by which path it measured. Modern UWB chipsets (Apple U1, Qorvo, NXP) include channel impulse response analysis to handle multipath, but \"first-arrival\" detection in cluttered environments is still hard.\n\n[[zigbee|Zigbee]]\'s failure mode is **interoperability**. The Zigbee spec is large; the application-layer profiles (Zigbee Home Automation, Zigbee Light Link, Zigbee 3.0) overlap and historically didn\'t interoperate. A Hue bulb didn\'t talk to a Lightify bulb didn\'t talk to a Wink hub. The Zigbee Alliance\'s answer in 2017 β€” Zigbee 3.0 β€” converged the profiles, but the install base is fragmented. Matter (2022, on top of Thread, not Zigbee) is an explicit answer to the interop mess β€” same goal, fresh start, better governance.` + text: `[[bluetooth|Bluetooth]]'s failure mode is **pairing UX**. The classic Bluetooth pairing flow (long press the button, find on the phone, enter PIN, accept) is consistently rated one of the worst UX moments in consumer electronics. Apple's Magic Pairing (a proprietary extension) made AirPods drastically better than generic BT pairing. The BT SIG's answer β€” Cross-Transport Key Derivation, Fast Pair β€” addresses some of the worst, but generic Bluetooth pairing is still a frequent support call. Security-wise, multiple specs (KNOB, BIAS, BLUFFS, BLESA) have shown serial weaknesses in BT pairing crypto; the SIG patches and the cycle continues.\n\n[[nfc|NFC]]'s failure mode is **the misread**. NFC requires near-touching alignment between reader antenna and tag antenna. Misaligned passes β€” bag tap-to-pay on an awkwardly-angled reader β€” fail silently. Modern phones include haptic feedback for successful taps; older systems just left you wondering if it worked. NFC has no security failure mode worth mentioning β€” the 4 cm range is the defense.\n\n[[uwb|UWB]]'s failure mode is **multipath**. Indoor environments reflect radio waves off walls; UWB's precision ranging can be confused by which path it measured. Modern UWB chipsets (Apple U1, Qorvo, NXP) include channel impulse response analysis to handle multipath, but "first-arrival" detection in cluttered environments is still hard.\n\n[[zigbee|Zigbee]]'s failure mode is **interoperability**. The Zigbee spec is large; the application-layer profiles (Zigbee Home Automation, Zigbee Light Link, Zigbee 3.0) overlap and historically didn't interoperate. A Hue bulb didn't talk to a Lightify bulb didn't talk to a Wink hub. The Zigbee Alliance's answer in 2017 β€” Zigbee 3.0 β€” converged the profiles, but the install base is fragmented. Matter (2022, on top of Thread, not Zigbee) is an explicit answer to the interop mess β€” same goal, fresh start, better governance.` }, { type: 'narrative', - title: 'What\'s Next', - text: `Active work in 2025:\n\n- **Bluetooth LE Audio + Auracast** broadcasts audio to many earbud-equipped listeners at once. Use cases: airport announcements, gym TVs, audio assistive listening in theaters. Slowly rolling out as new hardware ships.\n- **Bluetooth 6.0 Channel Sounding** brings precision ranging to BT, blurring the line with [[uwb|UWB]]. Expect "find my" features that work without a dedicated UWB chip in future devices.\n- **UWB everywhere** β€” UWB chips are spreading from flagship phones to mid-tier, from cars to smart-home hubs. The next 3–5 years will normalize centimeter-accurate ranging as a phone primitive.\n- **Matter / Thread continued growth** β€” most new smart-home devices ship Matter-over-Thread. Zigbee\'s install base is huge but the new growth is Matter. Many bridges (Hue, SmartThings, Aqara) translate between Zigbee and Matter.\n- **NFC for digital identity** β€” driver\'s licenses, passports, and government IDs are increasingly carried as NFC-readable credentials on phones. Apple Wallet IDs in US states; the EU\'s eIDAS 2.0 framework expects NFC-based national ID by 2026.\n- **The interesting frontier**: precision proximity. Knowing not just \"the user is nearby\" but \"the user is sitting in the driver\'s seat\" or \"the user is approaching the front door from outside\" is the next-generation interaction primitive. UWB plus BT plus mature multipath handling is what enables it.` + title: "What's Next", + text: `Active work in 2025:\n\n- **Bluetooth LE Audio + Auracast** broadcasts audio to many earbud-equipped listeners at once. Use cases: airport announcements, gym TVs, audio assistive listening in theaters. Slowly rolling out as new hardware ships.\n- **Bluetooth 6.0 Channel Sounding** brings precision ranging to BT, blurring the line with [[uwb|UWB]]. Expect "find my" features that work without a dedicated UWB chip in future devices.\n- **UWB everywhere** β€” UWB chips are spreading from flagship phones to mid-tier, from cars to smart-home hubs. The next 3–5 years will normalize centimeter-accurate ranging as a phone primitive.\n- **Matter / Thread continued growth** β€” most new smart-home devices ship Matter-over-Thread. Zigbee's install base is huge but the new growth is Matter. Many bridges (Hue, SmartThings, Aqara) translate between Zigbee and Matter.\n- **NFC for digital identity** β€” driver's licenses, passports, and government IDs are increasingly carried as NFC-readable credentials on phones. Apple Wallet IDs in US states; the EU's eIDAS 2.0 framework expects NFC-based national ID by 2026.\n- **The interesting frontier**: precision proximity. Knowing not just "the user is nearby" but "the user is sitting in the driver's seat" or "the user is approaching the front door from outside" is the next-generation interaction primitive. UWB plus BT plus mature multipath handling is what enables it.` } ] }; diff --git a/src/lib/data/subcategory-stories/realtime-web.ts b/src/lib/data/subcategory-stories/realtime-web.ts index 70f594f..831cb96 100644 --- a/src/lib/data/subcategory-stories/realtime-web.ts +++ b/src/lib/data/subcategory-stories/realtime-web.ts @@ -3,7 +3,7 @@ import type { SubcategoryStory } from './types'; export const realtimeWebStory: SubcategoryStory = { subcategoryId: 'realtime-web', tagline: - "Breaking out of request/response β€” server push and full-duplex on a protocol that was never meant for either", + 'Breaking out of request/response β€” server push and full-duplex on a protocol that was never meant for either', sections: [ { type: 'narrative', @@ -29,7 +29,7 @@ export const realtimeWebStory: SubcategoryStory = { title: 'Coined "Comet"', org: 'Lightstreamer / Independent', contribution: - "Coined {{comet|\"Comet\"}} in 2006 as the umbrella term for long-polling and streaming techniques people were using to fake server push over plain HTTP. The name stuck through the late-2000s era and is the reason \"the Comet pattern\" is still recognizable shorthand for HTTP-push hacks." + 'Coined {{comet|"Comet"}} in 2006 as the umbrella term for long-polling and streaming techniques people were using to fake server push over plain HTTP. The name stuck through the late-2000s era and is the reason "the Comet pattern" is still recognizable shorthand for HTTP-push hacks.' }, { name: 'Bert Belder', @@ -37,7 +37,7 @@ export const realtimeWebStory: SubcategoryStory = { title: 'WebSocket Implementer / Node.js Core', org: 'StrongLoop / npm', contribution: - "Co-authored the \`ws\` library β€” the dominant Node.js [[websockets|WebSocket]] implementation β€” which made server-side WebSocket trivially deployable from JavaScript. Node + ws + Socket.IO turned \"real-time web\" from a Tomcat/Comet engineering project into a weekend hack. The ergonomics shift mattered as much as the protocol." + 'Co-authored the `ws` library β€” the dominant Node.js [[websockets|WebSocket]] implementation β€” which made server-side WebSocket trivially deployable from JavaScript. Node + ws + Socket.IO turned "real-time web" from a Tomcat/Comet engineering project into a weekend hack. The ergonomics shift mattered as much as the protocol.' } ] }, @@ -48,13 +48,13 @@ export const realtimeWebStory: SubcategoryStory = { year: 2000, title: 'XMLHttpRequest Ships', description: - "Microsoft ships XMLHttpRequest in IE5 (1999); other browsers follow. The first real way to do background HTTP from JavaScript. The first practical polling implementations follow within a year." + 'Microsoft ships XMLHttpRequest in IE5 (1999); other browsers follow. The first real way to do background HTTP from JavaScript. The first practical polling implementations follow within a year.' }, { year: 2004, title: 'Gmail Launches with AJAX', description: - "Gmail makes AJAX mainstream. The pattern: poll for new mail every few minutes. Latency is fine for mail; users tolerate it. Realtime apps are still hard." + 'Gmail makes AJAX mainstream. The pattern: poll for new mail every few minutes. Latency is fine for mail; users tolerate it. Realtime apps are still hard.' }, { year: 2006, @@ -66,7 +66,7 @@ export const realtimeWebStory: SubcategoryStory = { year: 2009, title: 'SSE Standardized (W3C HTML5)', description: - "[[sse|Server-Sent Events]] ships with an EventSource API. Reconnection, Last-Event-ID, named event types. Server-to-client only β€” which is the entire point." + '[[sse|Server-Sent Events]] ships with an EventSource API. Reconnection, Last-Event-ID, named event types. Server-to-client only β€” which is the entire point.' }, { year: 2011, @@ -84,13 +84,13 @@ export const realtimeWebStory: SubcategoryStory = { year: 2015, title: 'WebSocket Adoption Mainstreams', description: - "Slack, Discord, Trello, Figma, Google Docs all run on WebSockets. Production scaling lessons β€” sticky load balancing, server-side connection pooling, presence systems β€” become widely documented." + 'Slack, Discord, Trello, Figma, Google Docs all run on WebSockets. Production scaling lessons β€” sticky load balancing, server-side connection pooling, presence systems β€” become widely documented.' }, { year: 2018, title: 'SSE Returns for LLMs', description: - "OpenAI ships streaming completions over [[sse|SSE]] for ChatGPT-like UX. The token-by-token effect requires server-push but not client-push β€” SSE is the natural fit. Anthropic, Google, Mistral all follow the same pattern." + 'OpenAI ships streaming completions over [[sse|SSE]] for ChatGPT-like UX. The token-by-token effect requires server-push but not client-push β€” SSE is the natural fit. Anthropic, Google, Mistral all follow the same pattern.' }, { year: 2021, @@ -102,13 +102,13 @@ export const realtimeWebStory: SubcategoryStory = { year: 2023, title: 'WebTransport in Chrome', description: - "WebTransport β€” QUIC streams exposed to browsers β€” ships in Chrome. Possible WebSocket successor: lower latency, multiple independent streams, unreliable datagrams when wanted. Slow uptake outside Google products so far." + 'WebTransport β€” QUIC streams exposed to browsers β€” ships in Chrome. Possible WebSocket successor: lower latency, multiple independent streams, unreliable datagrams when wanted. Slow uptake outside Google products so far.' }, { year: 2024, title: 'SSE Everywhere', description: - "Every major LLM provider streams via SSE. Server-driven UI frameworks (React Server Components, HTMX) lean heavily on SSE. The boring older protocol gets a second act." + 'Every major LLM provider streams via SSE. Server-driven UI frameworks (React Server Components, HTMX) lean heavily on SSE. The boring older protocol gets a second act.' } ] }, @@ -122,9 +122,9 @@ export const realtimeWebStory: SubcategoryStory = { values: [ 'Server β†’ client only', 'Plain HTTP (works over [[http1|h1]], [[http2|h2]], [[http3|h3]])', - "Text β€” \`data:\` lines separated by blank lines", + 'Text β€” `data:` lines separated by blank lines', 'Built-in β€” auto-reconnects with Last-Event-ID', - "LLM streaming, notifications, server-driven UI updates" + 'LLM streaming, notifications, server-driven UI updates' ] }, { @@ -133,12 +133,12 @@ export const realtimeWebStory: SubcategoryStory = { 'Full-duplex', 'HTTP upgrade then custom framing over TCP', 'Binary frames with opcode + masking', - 'Application\'s problem', - "Chat, collaborative editing, multiplayer games, anything client-push-heavy" + "Application's problem", + 'Chat, collaborative editing, multiplayer games, anything client-push-heavy' ] } ], - note: "If your traffic is one-way (server β†’ client), [[sse|SSE]] is simpler, plays nice with HTTP infrastructure, and has cleaner failure semantics. If the client also needs to push frequently, [[websockets|WebSockets]]." + note: 'If your traffic is one-way (server β†’ client), [[sse|SSE]] is simpler, plays nice with HTTP infrastructure, and has cleaner failure semantics. If the client also needs to push frequently, [[websockets|WebSockets]].' }, { type: 'animated-sequence', @@ -169,7 +169,7 @@ export const realtimeWebStory: SubcategoryStory = { C->>S: frame chat S-->>C: frame ack`, caption: - "Each step reduces latency or improves resource use over the last. [[websockets|WebSocket]] is the only one where both sides can send asynchronously; the others are still server-driven.", + 'Each step reduces latency or improves resource use over the last. [[websockets|WebSocket]] is the only one where both sides can send asynchronously; the others are still server-driven.', steps: { 0: '**Polling β€” the original hack.** Before SSE or WebSockets, the only way to get server-pushed data was to ask the server, over and over, for new data. Most requests came back empty.', 1: 'Client asks **GET /messages**.', @@ -203,12 +203,12 @@ export const realtimeWebStory: SubcategoryStory = { { type: 'narrative', title: 'The Failure Modes', - text: `[[sse|SSE]]\'s failure mode is the **stuck connection**. The protocol is one-way, so the client can\'t directly tell the server "I\'m still here." Reconnects happen on transport failure, but a half-open TCP connection β€” where the server has died but the network never reports it β€” can leave the client silently waiting for events that will never arrive. Application-level heartbeats (server sends a keepalive comment every ~15s) are the standard fix.\n\n[[websockets|WebSockets]]\'s failure mode is **state divergence**. Both client and server hold state; they must agree on it. When the connection drops mid-message, who owns the unacknowledged messages? When the client reconnects, did it miss events while disconnected? The protocol gives you no help. Every WebSocket-based app implements its own sequence numbers, replay buffers, and reconciliation. The good ones (Figma, Linear, Notion) are real distributed systems behind a simple-looking UI.\n\nBoth share a third failure mode: **server-side scalability**. Each connection costs server memory and an open file descriptor. Twitter\'s 2010 streaming firehose required dedicated servers per few thousand connections. Modern stacks (Phoenix on the BEAM, Go with goroutines) push that to ~1M connections per box, but only with careful tuning. Real-time always pays in server resources.` + text: `[[sse|SSE]]'s failure mode is the **stuck connection**. The protocol is one-way, so the client can't directly tell the server "I'm still here." Reconnects happen on transport failure, but a half-open TCP connection β€” where the server has died but the network never reports it β€” can leave the client silently waiting for events that will never arrive. Application-level heartbeats (server sends a keepalive comment every ~15s) are the standard fix.\n\n[[websockets|WebSockets]]'s failure mode is **state divergence**. Both client and server hold state; they must agree on it. When the connection drops mid-message, who owns the unacknowledged messages? When the client reconnects, did it miss events while disconnected? The protocol gives you no help. Every WebSocket-based app implements its own sequence numbers, replay buffers, and reconciliation. The good ones (Figma, Linear, Notion) are real distributed systems behind a simple-looking UI.\n\nBoth share a third failure mode: **server-side scalability**. Each connection costs server memory and an open file descriptor. Twitter's 2010 streaming firehose required dedicated servers per few thousand connections. Modern stacks (Phoenix on the BEAM, Go with goroutines) push that to ~1M connections per box, but only with careful tuning. Real-time always pays in server resources.` }, { type: 'narrative', - title: 'What\'s Next', - text: `Active work in 2025:\n\n- **WebTransport** is the proposed successor to [[websockets|WebSocket]] β€” built on [[quic|QUIC]], with native stream multiplexing, unreliable datagrams when wanted, and no proxy-Upgrade nonsense. Shipping in Chrome; slow elsewhere.\n- **HTTP/3 over QUIC** changes [[sse|SSE]]\'s scaling story β€” one QUIC connection can carry many SSE streams without TCP head-of-line blocking. Cloudflare and Fastly are quietly making this the default.\n- **Server-driven UI** frameworks (HTMX, Phoenix LiveView, Inertia.js, React Server Components) lean on SSE for their UI updates β€” the boring older protocol is having a second moment because the new use case fits it perfectly.\n- **LLM streaming** is now the dominant new use case for [[sse|SSE]]. Every chat-like AI product ships an SSE endpoint; the token-by-token effect is canonical.\n- **The death of polling** is overstated. Mobile push notifications, periodic background sync, and "check every N seconds" are still the right answer for many product surfaces. Realtime is expensive; not everything needs it.` + title: "What's Next", + text: `Active work in 2025:\n\n- **WebTransport** is the proposed successor to [[websockets|WebSocket]] β€” built on [[quic|QUIC]], with native stream multiplexing, unreliable datagrams when wanted, and no proxy-Upgrade nonsense. Shipping in Chrome; slow elsewhere.\n- **HTTP/3 over QUIC** changes [[sse|SSE]]'s scaling story β€” one QUIC connection can carry many SSE streams without TCP head-of-line blocking. Cloudflare and Fastly are quietly making this the default.\n- **Server-driven UI** frameworks (HTMX, Phoenix LiveView, Inertia.js, React Server Components) lean on SSE for their UI updates β€” the boring older protocol is having a second moment because the new use case fits it perfectly.\n- **LLM streaming** is now the dominant new use case for [[sse|SSE]]. Every chat-like AI product ships an SSE endpoint; the token-by-token effect is canonical.\n- **The death of polling** is overstated. Mobile push notifications, periodic background sync, and "check every N seconds" are still the right answer for many product surfaces. Realtime is expensive; not everything needs it.` } ] }; diff --git a/src/lib/data/subcategory-stories/reliable-streams.ts b/src/lib/data/subcategory-stories/reliable-streams.ts index 62c9e1c..78d3f08 100644 --- a/src/lib/data/subcategory-stories/reliable-streams.ts +++ b/src/lib/data/subcategory-stories/reliable-streams.ts @@ -3,12 +3,12 @@ import type { SubcategoryStory } from './types'; export const reliableStreamsStory: SubcategoryStory = { subcategoryId: 'reliable-streams', tagline: - 'Turning best-effort {{ip|IP}} into ordered, reliable streams β€” and the fifty-year fight against {{congestion-collapse|congestion collapse}}', + 'Turning best-effort [[ip|IP]] into ordered, reliable streams β€” and the fifty-year fight against {{congestion-collapse|congestion collapse}}', sections: [ { type: 'narrative', title: 'The Reliability Contract', - text: `{{ip|IP}} promises almost nothing. Packets can be lost, reordered, duplicated, corrupted, or just dropped on the floor. That is by design β€” keeping the network layer dumb is what lets the Internet scale. But almost no application can use the network in that raw form. They want a *byte stream*: write bytes here, read identical bytes there, in order.\n\n**[[tcp|TCP]]** (1981) is the original reliable-stream contract. It bolted onto [[ip|IP]] everything a stream needs β€” sequence numbers, acknowledgments, retransmission, flow control, and (after 1986) {{congestion-control|congestion control}}. For 40+ years, almost every Internet conversation that wasn't streaming media or DNS rode on TCP.\n\n**[[sctp|SCTP]]** (2000) is the protocol you wish TCP had been: multiple independent streams in one association (no {{head-of-line-blocking|HoL blocking}}), multi-homing for free failover, message-oriented instead of byte-oriented. It is technically superior to TCP for almost every workload β€” and almost nobody uses it, because middleboxes don't speak it. The story of SCTP is the story of how the Internet's *deployed* base shapes what protocols can succeed, regardless of merit.\n\n**[[mptcp|MPTCP]]** (2013) is the workaround for SCTP's loss. Keep the TCP wire format that middleboxes accept, but bond multiple TCP subflows across multiple paths into one logical stream. Apple ships it for Siri. Korean carriers use it to bond LTE+Wi-Fi. The protocol is a careful exercise in *backwards-compatible innovation*.\n\nAll three share one quiet inheritance: they all use {{congestion-control|congestion control}} algorithms derived from a single 1988 paper.` + text: `[[ip|IP]] promises almost nothing. Packets can be lost, reordered, duplicated, corrupted, or just dropped on the floor. That is by design β€” keeping the network layer dumb is what lets the Internet scale. But almost no application can use the network in that raw form. They want a *byte stream*: write bytes here, read identical bytes there, in order.\n\n**[[tcp|TCP]]** (1981) is the original reliable-stream contract. It bolted onto [[ip|IP]] everything a stream needs β€” sequence numbers, acknowledgments, retransmission, flow control, and (after 1986) {{congestion-control|congestion control}}. For 40+ years, almost every Internet conversation that wasn't streaming media or DNS rode on TCP.\n\n**[[sctp|SCTP]]** (2000) is the protocol you wish TCP had been: multiple independent streams in one association (no {{head-of-line-blocking|HoL blocking}}), multi-homing for free failover, message-oriented instead of byte-oriented. It is technically superior to TCP for almost every workload β€” and almost nobody uses it, because middleboxes don't speak it. The story of SCTP is the story of how the Internet's *deployed* base shapes what protocols can succeed, regardless of merit.\n\n**[[mptcp|MPTCP]]** (2013) is the workaround for SCTP's loss. Keep the TCP wire format that middleboxes accept, but bond multiple TCP subflows across multiple paths into one logical stream. Apple ships it for Siri. Korean carriers use it to bond LTE+Wi-Fi. The protocol is a careful exercise in *backwards-compatible innovation*.\n\nAll three share one quiet inheritance: they all use {{congestion-control|congestion control}} algorithms derived from a single 1988 paper.` }, { type: 'pioneers', @@ -66,13 +66,13 @@ export const reliableStreamsStory: SubcategoryStory = { year: 1981, title: 'TCP RFC 793 Published', description: - "The reference TCP spec. Three-way handshake, sliding window, retransmission, flow control. Congestion control is *not* yet present β€” that omission will nearly destroy the Internet five years later." + 'The reference TCP spec. Three-way handshake, sliding window, retransmission, flow control. Congestion control is *not* yet present β€” that omission will nearly destroy the Internet five years later.' }, { year: 1986, title: 'Congestion Collapse', description: - "The path between LBL and UC Berkeley β€” 400 yards apart β€” collapses to 40 bps from a nominal 32 kbps. The cause: TCP retransmits compounding network overload until the network drowns in retries." + 'The path between LBL and UC Berkeley β€” 400 yards apart β€” collapses to 40 bps from a nominal 32 kbps. The cause: TCP retransmits compounding network overload until the network drowns in retries.' }, { year: 1988, @@ -84,7 +84,7 @@ export const reliableStreamsStory: SubcategoryStory = { year: 1999, title: 'TCP Reno β†’ NewReno β†’ SACK', description: - 'A decade of incremental tuning. {{sack|Selective Acknowledgments}} (RFC 2018) let receivers tell senders *which* packets were lost, fixing the original ACK\'s ambiguity.' + "A decade of incremental tuning. {{sack|Selective Acknowledgments}} (RFC 2018) let receivers tell senders *which* packets were lost, fixing the original ACK's ambiguity." }, { year: 2000, @@ -102,7 +102,7 @@ export const reliableStreamsStory: SubcategoryStory = { year: 2013, title: 'MPTCP RFC 6824', description: - "[[mptcp|MPTCP]] bonds multiple TCP subflows into a single logical stream. Wire-compatible with middleboxes because each subflow *is* a normal TCP connection." + '[[mptcp|MPTCP]] bonds multiple TCP subflows into a single logical stream. Wire-compatible with middleboxes because each subflow *is* a normal TCP connection.' }, { year: 2016, @@ -151,7 +151,7 @@ export const reliableStreamsStory: SubcategoryStory = { ] } ], - note: '[[sctp|SCTP]] is technically the most capable, but its lack of NAT/firewall traversal kept it off the public Internet. [[mptcp|MPTCP]] is the pragmatic answer: take TCP\'s deployability and bolt the missing features on top.' + note: "[[sctp|SCTP]] is technically the most capable, but its lack of NAT/firewall traversal kept it off the public Internet. [[mptcp|MPTCP]] is the pragmatic answer: take TCP's deployability and bolt the missing features on top." }, { type: 'animated-sequence', @@ -207,11 +207,11 @@ export const reliableStreamsStory: SubcategoryStory = { { type: 'narrative', title: 'The Failure Mode That Defines the Family', - text: `Every reliable-stream protocol has the same nightmare: **head-of-line blocking**.\n\nIn [[tcp|TCP]], one lost packet stalls *every subsequent byte* until that packet is retransmitted and ACKed. If you're sending a 50 KB HTTP response and packet #3 is lost, the receiver buffers packets 4–35 but won't deliver them to the application until packet #3 arrives. Three round-trips of latency added.\n\n[[sctp|SCTP]] partially solved this with multiple streams: a loss on stream A doesn't stall stream B. But SCTP wasn't deployable.\n\n[[mptcp|MPTCP]] partially solved it differently: multiple subflows over different paths means *path-level* loss doesn't stall *application-level* delivery if you can re-issue on another path. But coordinating reorder across subflows is hard.\n\n[[quic|QUIC]] solved it completely by moving streams *into* the transport β€” but QUIC sits in [[datagram-transport|Datagram Transport]], not here, because it gave up TCP's wire format to do it.\n\nIn this family, the head-of-line ghost is permanent rent.` + text: `Every reliable-stream protocol has the same nightmare: **head-of-line blocking**.\n\nIn [[tcp|TCP]], one lost packet stalls *every subsequent byte* until that packet is retransmitted and ACKed. If you're sending a 50 KB HTTP response and packet #3 is lost, the receiver buffers packets 4–35 but won't deliver them to the application until packet #3 arrives. Three round-trips of latency added.\n\n[[sctp|SCTP]] partially solved this with multiple streams: a loss on stream A doesn't stall stream B. But SCTP wasn't deployable.\n\n[[mptcp|MPTCP]] partially solved it differently: multiple subflows over different paths means *path-level* loss doesn't stall *application-level* delivery if you can re-issue on another path. But coordinating reorder across subflows is hard.\n\n[[quic|QUIC]] solved it completely by moving streams *into* the transport β€” but QUIC sits in datagram transport, not here, because it gave up TCP's wire format to do it.\n\nIn this family, the head-of-line ghost is permanent rent.` }, { type: 'narrative', - title: 'What\'s Next', + title: "What's Next", text: `Active work in 2025:\n\n- **{{bbr|BBRv3}}** continues to roll out beyond Google's properties. Fairness with CUBIC under shared bottlenecks remains a live research area.\n- **Multipath TCP for 5G** (ATSSS β€” Access Traffic Steering, Switching, and Splitting) lets carriers bond cellular + Wi-Fi for handset traffic. Standardized in 3GPP Release 16.\n- **L4S** (Low Latency, Low Loss, Scalable throughput) adds an ECN-based signal so endpoints can react to congestion *before* loss. Requires both router and endpoint changes; deployment is slow.\n- **The slow death of TCP for new things.** Most green-field protocols (HTTP/3, WebTransport, Media-over-QUIC) skip TCP entirely. The Reliable Streams family isn't shrinking yet β€” but its growth has stopped.` } ] diff --git a/src/lib/data/subcategory-stories/resource-query-apis.ts b/src/lib/data/subcategory-stories/resource-query-apis.ts index 5a18cfc..da65df5 100644 --- a/src/lib/data/subcategory-stories/resource-query-apis.ts +++ b/src/lib/data/subcategory-stories/resource-query-apis.ts @@ -3,7 +3,7 @@ import type { SubcategoryStory } from './types'; export const resourceQueryApisStory: SubcategoryStory = { subcategoryId: 'resource-query-apis', tagline: - "Modeling data on the web β€” verbs and nouns ([[rest|REST]]) vs schemas and queries ([[graphql|GraphQL]])", + 'Modeling data on the web β€” verbs and nouns ([[rest|REST]]) vs schemas and queries ([[graphql|GraphQL]])', sections: [ { type: 'narrative', @@ -21,7 +21,7 @@ export const resourceQueryApisStory: SubcategoryStory = { title: 'Inventor of REST', org: 'UC Irvine / Apache / Adobe', contribution: - "Co-authored the [[http1|HTTP/1.0]] and [[http1|HTTP/1.1]] specifications in the late 1990s, then named the architectural style underlying the web in his 2000 PhD dissertation. The dissertation's Chapter 5 β€” 36 pages β€” is the entire formal definition of [[rest|REST]]. Co-founded the Apache HTTP Server Project. Fielding has spent 25 years gently noting that the vast majority of \"REST APIs\" violate his {{hateoas|HATEOAS}} constraint and are really just RPC-over-HTTP.", + 'Co-authored the [[http1|HTTP/1.0]] and [[http1|HTTP/1.1]] specifications in the late 1990s, then named the architectural style underlying the web in his 2000 PhD dissertation. The dissertation\'s Chapter 5 β€” 36 pages β€” is the entire formal definition of [[rest|REST]]. Co-founded the Apache HTTP Server Project. Fielding has spent 25 years gently noting that the vast majority of "REST APIs" violate his {{hateoas|HATEOAS}} constraint and are really just RPC-over-HTTP.', imagePath: 'https://upload.wikimedia.org/wikipedia/commons/thumb/5/52/Roy_Fielding_%28cropped%29.jpg/330px-Roy_Fielding_%28cropped%29.jpg' }, @@ -31,7 +31,7 @@ export const resourceQueryApisStory: SubcategoryStory = { title: 'Co-creator of GraphQL', org: 'Facebook / Robinhood / The Graph Foundation', contribution: - "Designed [[graphql|GraphQL]] at Facebook in 2012 with Nick Schrock and Dan Schafer to solve the mobile-fetch problem. Open-sourced in 2015 at React Conf. Later moved to Robinhood to apply GraphQL to financial-services APIs; now stewards the language as part of the GraphQL Foundation. The original internal name was \"SuperGraph\" β€” \"GraphQL\" came later because the wire format was a *query language*, not just a graph API." + 'Designed [[graphql|GraphQL]] at Facebook in 2012 with Nick Schrock and Dan Schafer to solve the mobile-fetch problem. Open-sourced in 2015 at React Conf. Later moved to Robinhood to apply GraphQL to financial-services APIs; now stewards the language as part of the GraphQL Foundation. The original internal name was "SuperGraph" β€” "GraphQL" came later because the wire format was a *query language*, not just a graph API.' }, { name: 'Sam Newman', @@ -48,15 +48,15 @@ export const resourceQueryApisStory: SubcategoryStory = { entries: [ { year: 2000, - title: 'Fielding\'s Dissertation Names REST', + title: "Fielding's Dissertation Names REST", description: - "[[pioneer:roy-fielding|Fielding]] formalizes the architectural style behind the web in *Architectural Styles and the Design of Network-based Software Architectures*. Six constraints: client-server, stateless, cacheable, uniform interface, layered system, code-on-demand." + '[[pioneer:roy-fielding|Fielding]] formalizes the architectural style behind the web in *Architectural Styles and the Design of Network-based Software Architectures*. Six constraints: client-server, stateless, cacheable, uniform interface, layered system, code-on-demand.' }, { year: 2006, title: 'AWS S3 Launches with REST API', description: - "Amazon Web Services ships S3 with a [[rest|REST]] API alongside SOAP. Developers overwhelmingly choose REST. The lesson β€” \"SOAP is for vendors, REST is for developers\" β€” shapes a decade of API design." + 'Amazon Web Services ships S3 with a [[rest|REST]] API alongside SOAP. Developers overwhelmingly choose REST. The lesson β€” "SOAP is for vendors, REST is for developers" β€” shapes a decade of API design.' }, { year: 2008, @@ -68,37 +68,37 @@ export const resourceQueryApisStory: SubcategoryStory = { year: 2012, title: 'Facebook Begins GraphQL', description: - "Lee Byron, Nick Schrock, and Dan Schafer start GraphQL internally to fix mobile-app fetch storms. The original problem: a Facebook News Feed screen made 30+ REST calls on slow 3G." + 'Lee Byron, Nick Schrock, and Dan Schafer start GraphQL internally to fix mobile-app fetch storms. The original problem: a Facebook News Feed screen made 30+ REST calls on slow 3G.' }, { year: 2015, title: 'GraphQL Open-Sourced', description: - "Facebook releases [[graphql|GraphQL]] at React.js Conf. GitHub announces its API v4 will be GraphQL within months. The schema-typed, client-driven query model spreads fast." + 'Facebook releases [[graphql|GraphQL]] at React.js Conf. GitHub announces its API v4 will be GraphQL within months. The schema-typed, client-driven query model spreads fast.' }, { year: 2018, title: 'GraphQL Foundation Forms', description: - "Linux Foundation takes stewardship from Facebook. The community proves the spec can outlive its original maintainers β€” a recurring fear with single-vendor open source." + 'Linux Foundation takes stewardship from Facebook. The community proves the spec can outlive its original maintainers β€” a recurring fear with single-vendor open source.' }, { year: 2020, title: 'OpenAPI 3.1 / JSON Schema Convergence', description: - "REST gets a typed-schema story too. OpenAPI 3.1 aligns with JSON Schema 2020-12. Tools like Speakeasy, Stainless, and Fern generate typed clients from OpenAPI specs β€” narrowing the developer-experience gap with GraphQL." + 'REST gets a typed-schema story too. OpenAPI 3.1 aligns with JSON Schema 2020-12. Tools like Speakeasy, Stainless, and Fern generate typed clients from OpenAPI specs β€” narrowing the developer-experience gap with GraphQL.' }, { year: 2022, title: 'tRPC + End-to-End Types', description: - "A wave of \"GraphQL without GraphQL\" β€” tRPC, Hono RPC, ts-rest β€” uses TypeScript inference to give clients end-to-end types without a separate schema language. Works only inside TypeScript monorepos, but where it works it's instant." + 'A wave of "GraphQL without GraphQL" β€” tRPC, Hono RPC, ts-rest β€” uses TypeScript inference to give clients end-to-end types without a separate schema language. Works only inside TypeScript monorepos, but where it works it\'s instant.' }, { year: 2024, title: 'GraphQL Federation Matures', description: - "Apollo Federation 2, GraphQL Mesh, and StepZen mature the \"multiple subgraphs composed into one\" pattern. GraphQL becomes the default API gateway for microservices at Netflix, Airbnb, Shopify." + 'Apollo Federation 2, GraphQL Mesh, and StepZen mature the "multiple subgraphs composed into one" pattern. GraphQL becomes the default API gateway for microservices at Netflix, Airbnb, Shopify.' } ] }, @@ -149,32 +149,32 @@ export const resourceQueryApisStory: SubcategoryStory = { caption: "Same data, two shapes. [[rest|REST]] makes the client orchestrate; [[graphql|GraphQL]] makes the server resolve. The cost of GraphQL's flexibility is that the server has to be ready for *any* query, which makes performance and authorization harder to reason about.", steps: { - 0: '**The REST way.** Each entity has its own URL. Fetching nested data β€” user, their posts, each post\'s comments β€” means several sequential requests because the client needs response N to know what to ask for in request N+1.', + 0: "**The REST way.** Each entity has its own URL. Fetching nested data β€” user, their posts, each post's comments β€” means several sequential requests because the client needs response N to know what to ask for in request N+1.", 1: 'Client asks for the **user**.', - 2: 'Server returns user fields. Now the client knows it can ask for this user\'s posts.', - 3: 'Client asks for the **user\'s posts**.', - 4: 'Server returns post summaries. Now the client has post IDs and can ask for each post\'s comments.', + 2: "Server returns user fields. Now the client knows it can ask for this user's posts.", + 3: "Client asks for the **user's posts**.", + 4: "Server returns post summaries. Now the client has post IDs and can ask for each post's comments.", 5: '**Client asks for comments β€” one request per post.** Or two requests, or fifty. The classic "N+1 query" problem of REST APIs.', 6: 'Server returns comments for each post in separate responses. The client now has all the data β€” but it took multiple round-trips and most of the bytes were headers.', 7: '**The GraphQL way.** One request describes the entire nested shape the client wants. The server resolves all of it at once and returns exactly what was asked for.', 8: 'Client sends **one POST to /graphql** with a query body specifying user β†’ posts β†’ comments β†’ author/body. The shape of the request mirrors the shape of the wanted response.', - 9: 'Server returns **nested JSON** matching the query shape exactly. One round-trip; zero over-fetch (no fields the client didn\'t ask for); zero under-fetch (everything the client needed in one trip). The cost: the server has to be smart enough to resolve any arbitrary tree shape efficiently.' + 9: "Server returns **nested JSON** matching the query shape exactly. One round-trip; zero over-fetch (no fields the client didn't ask for); zero under-fetch (everything the client needed in one trip). The cost: the server has to be smart enough to resolve any arbitrary tree shape efficiently." } }, { type: 'callout', title: 'HATEOAS β€” The Constraint Almost Nobody Implements', - text: `Fielding\'s [[rest|REST]] dissertation has a constraint called **{{hateoas|HATEOAS}}**: Hypermedia As The Engine of Application State. The idea: a client should discover what actions are possible by following hyperlinks in the response, not by reading API documentation that hardcodes URL patterns.\n\nA strictly RESTful response to \`GET /orders/42\` would include not just the order data but links: "to cancel, POST to /orders/42/cancel"; "to add a line item, POST to /orders/42/items." The client would never construct a URL β€” it would follow the links the server hands it. Add a new state transition, and clients pick it up for free.\n\nAlmost nobody does this. Production "REST" APIs are pattern-based: clients know that \`POST /orders/{id}/cancel\` exists because it's documented, not because the order resource told them. Fielding has spent twenty years gently insisting these aren't REST APIs β€” they're "HTTP RPC." The world has gently ignored him. The pragmatic working definition of REST has won, even if the formal definition has not.` + text: `Fielding's [[rest|REST]] dissertation has a constraint called **{{hateoas|HATEOAS}}**: Hypermedia As The Engine of Application State. The idea: a client should discover what actions are possible by following hyperlinks in the response, not by reading API documentation that hardcodes URL patterns.\n\nA strictly RESTful response to \`GET /orders/42\` would include not just the order data but links: "to cancel, POST to /orders/42/cancel"; "to add a line item, POST to /orders/42/items." The client would never construct a URL β€” it would follow the links the server hands it. Add a new state transition, and clients pick it up for free.\n\nAlmost nobody does this. Production "REST" APIs are pattern-based: clients know that \`POST /orders/{id}/cancel\` exists because it's documented, not because the order resource told them. Fielding has spent twenty years gently insisting these aren't REST APIs β€” they're "HTTP RPC." The world has gently ignored him. The pragmatic working definition of REST has won, even if the formal definition has not.` }, { type: 'narrative', title: 'The Failure Modes', - text: `[[rest|REST]]\'s failure mode is **chatty clients**. A list view that shows 50 items, each with three sub-resources, is 151 HTTP calls if you do it the obvious way. Workarounds β€” \`?include=\` query parameters, JSON:API\'s sparse fieldsets, custom batch endpoints β€” accrete until your REST API is a tangle of escape hatches. Caching helps if the data is cacheable; if it\'s personalized, it doesn\'t.\n\n[[graphql|GraphQL]]\'s failure mode is **expensive queries**. A client can ask for *anything* the schema allows, including \`users { friends { friends { friends { name } } } }\` β€” a query that explodes in cost. Solutions exist: query-cost analysis, persisted queries, automatic field-level rate-limiting β€” but they\'re all *additional work* the server has to do that REST avoids by simply not letting clients ask for arbitrary shapes. GraphQL also makes HTTP caching nearly useless: every query is a POST with a body, so CDNs can\'t cache it without a layer of indirection (persisted query hashes).\n\nThe two failure modes are mirror images. REST lets the server constrain everything but forces the client to coordinate. GraphQL lets the client request anything but forces the server to defend.` + text: `[[rest|REST]]'s failure mode is **chatty clients**. A list view that shows 50 items, each with three sub-resources, is 151 HTTP calls if you do it the obvious way. Workarounds β€” \`?include=\` query parameters, JSON:API's sparse fieldsets, custom batch endpoints β€” accrete until your REST API is a tangle of escape hatches. Caching helps if the data is cacheable; if it's personalized, it doesn't.\n\n[[graphql|GraphQL]]'s failure mode is **expensive queries**. A client can ask for *anything* the schema allows, including \`users { friends { friends { friends { name } } } }\` β€” a query that explodes in cost. Solutions exist: query-cost analysis, persisted queries, automatic field-level rate-limiting β€” but they're all *additional work* the server has to do that REST avoids by simply not letting clients ask for arbitrary shapes. GraphQL also makes HTTP caching nearly useless: every query is a POST with a body, so CDNs can't cache it without a layer of indirection (persisted query hashes).\n\nThe two failure modes are mirror images. REST lets the server constrain everything but forces the client to coordinate. GraphQL lets the client request anything but forces the server to defend.` }, { type: 'narrative', - title: 'What\'s Next', - text: `Active work in 2025:\n\n- **GraphQL Federation** is becoming the default architecture for large API gateways β€” multiple teams own subgraphs that compose into one client-facing schema. Apollo Federation, StepZen, GraphQL Mesh.\n- **REST + types** is closing the developer-experience gap with GraphQL. OpenAPI 3.1, Stainless, Speakeasy, Fern all generate typed clients from REST specs that feel nearly as good as GraphQL codegen.\n- **tRPC and friends** keep growing inside TypeScript monorepos. End-to-end inferred types, no schema language, no codegen. The boundary: any client outside the monorepo needs a real API.\n- **JSON:API** quietly powers a lot of \"strict REST with conventions\" deployments β€” the spec is unfashionable but solves the \"every REST API reinvents pagination\" problem.\n- **The unsexy truth**: most companies run both. REST for public/partner APIs and CDN-cacheable reads. GraphQL for first-party mobile and web clients. Choosing one and using it for everything is rare in practice.` + title: "What's Next", + text: `Active work in 2025:\n\n- **GraphQL Federation** is becoming the default architecture for large API gateways β€” multiple teams own subgraphs that compose into one client-facing schema. Apollo Federation, StepZen, GraphQL Mesh.\n- **REST + types** is closing the developer-experience gap with GraphQL. OpenAPI 3.1, Stainless, Speakeasy, Fern all generate typed clients from REST specs that feel nearly as good as GraphQL codegen.\n- **tRPC and friends** keep growing inside TypeScript monorepos. End-to-end inferred types, no schema language, no codegen. The boundary: any client outside the monorepo needs a real API.\n- **JSON:API** quietly powers a lot of "strict REST with conventions" deployments β€” the spec is unfashionable but solves the "every REST API reinvents pagination" problem.\n- **The unsexy truth**: most companies run both. REST for public/partner APIs and CDN-cacheable reads. GraphQL for first-party mobile and web clients. Choosing one and using it for everything is rare in practice.` } ] }; diff --git a/src/lib/data/subcategory-stories/routing.ts b/src/lib/data/subcategory-stories/routing.ts index 9b6342c..2d16f4a 100644 --- a/src/lib/data/subcategory-stories/routing.ts +++ b/src/lib/data/subcategory-stories/routing.ts @@ -21,7 +21,7 @@ export const routingStory: SubcategoryStory = { title: 'Inventor of Shortest-Path Algorithm', org: 'Eindhoven / UT Austin', contribution: - "In 1956 Dijkstra invented his shortest-path algorithm in about 20 minutes \"to demonstrate the capabilities of the ARMAC computer.\" Published in 1959 (\"A Note on Two Problems in Connexion with Graphs\"). [[ospf|OSPF]] runs Dijkstra's algorithm on the link-state database every time the topology changes β€” every Internet router that uses OSPF runs Dijkstra's 1956 algorithm thousands of times a day.", + 'In 1956 Dijkstra invented his shortest-path algorithm in about 20 minutes "to demonstrate the capabilities of the ARMAC computer." Published in 1959 ("A Note on Two Problems in Connexion with Graphs"). [[ospf|OSPF]] runs Dijkstra\'s algorithm on the link-state database every time the topology changes β€” every Internet router that uses OSPF runs Dijkstra\'s 1956 algorithm thousands of times a day.', imagePath: 'https://upload.wikimedia.org/wikipedia/commons/thumb/d/d9/Edsger_Wybe_Dijkstra.jpg/330px-Edsger_Wybe_Dijkstra.jpg' }, @@ -41,7 +41,7 @@ export const routingStory: SubcategoryStory = { title: 'Author of OSPF', org: 'Proteon / Cascade / Sycamore', contribution: - "Designed [[ospf|OSPF]] in 1989 as a replacement for RIP (the distance-vector protocol that took multi-minute convergence times in the 1980s Internet). Moy wrote OSPFv1 (RFC 1131, 1989), OSPFv2 (RFC 1247, 1991, then [[rfc:2328|RFC 2328]], 1998 β€” still the current spec), and the canonical book \"OSPF: Anatomy of an Internet Routing Protocol.\" OSPF's link-state design β€” flood the topology, run Dijkstra locally β€” is now standard for IGPs across vendors." + 'Designed [[ospf|OSPF]] in 1989 as a replacement for RIP (the distance-vector protocol that took multi-minute convergence times in the 1980s Internet). Moy wrote OSPFv1 (RFC 1131, 1989), OSPFv2 (RFC 1247, 1991, then [[rfc:2328|RFC 2328]], 1998 β€” still the current spec), and the canonical book "OSPF: Anatomy of an Internet Routing Protocol." OSPF\'s link-state design β€” flood the topology, run Dijkstra locally β€” is now standard for IGPs across vendors.' } ] }, @@ -52,13 +52,13 @@ export const routingStory: SubcategoryStory = { year: 1956, title: 'Dijkstra Invents Shortest-Path', description: - "[[pioneer:edsger-dijkstra|Dijkstra]] sketches his algorithm in a Dutch cafΓ©. It will become the engine of every link-state IGP three decades later." + '[[pioneer:edsger-dijkstra|Dijkstra]] sketches his algorithm in a Dutch cafΓ©. It will become the engine of every link-state IGP three decades later.' }, { year: 1982, title: 'EGP RFC 827', description: - "The first inter-AS protocol β€” strictly tree-shaped, assumed the Internet had a single backbone core (the ARPANET). It worked only because the early Internet was small and centralized." + 'The first inter-AS protocol β€” strictly tree-shaped, assumed the Internet had a single backbone core (the ARPANET). It worked only because the early Internet was small and centralized.' }, { year: 1989, @@ -76,13 +76,13 @@ export const routingStory: SubcategoryStory = { year: 1995, title: 'BGP-4 (RFC 1771)', description: - "BGP-4 adds {{cidr|CIDR}} support β€” variable-length prefixes instead of class A/B/C boundaries. CIDR is the only thing that staved off [[ipv4|IPv4]] address exhaustion through the 1990s." + 'BGP-4 adds {{cidr|CIDR}} support β€” variable-length prefixes instead of class A/B/C boundaries. CIDR is the only thing that staved off [[ip|IPv4]] address exhaustion through the 1990s.' }, { year: 1998, title: 'OSPFv2 Final (RFC 2328)', description: - "The OSPF spec that almost every router on Earth still implements unchanged. Multi-area hierarchy, MD5 authentication, type-of-service routing (rarely used)." + 'The OSPF spec that almost every router on Earth still implements unchanged. Multi-area hierarchy, MD5 authentication, type-of-service routing (rarely used).' }, { year: 1999, @@ -100,7 +100,7 @@ export const routingStory: SubcategoryStory = { year: 2008, title: 'YouTube Disappears for Two Hours', description: - 'Pakistan Telecom announces a more-specific BGP route to YouTube\'s prefix, intending to block YouTube locally. The announcement leaks to upstream PCCW Global and propagates globally. YouTube is unreachable for ~2 hours.' + "Pakistan Telecom announces a more-specific BGP route to YouTube's prefix, intending to block YouTube locally. The announcement leaks to upstream PCCW Global and propagates globally. YouTube is unreachable for ~2 hours." }, { year: 2021, @@ -112,7 +112,7 @@ export const routingStory: SubcategoryStory = { year: 2024, title: 'RPKI Coverage Crosses 50%', description: - 'Resource Public Key Infrastructure β€” cryptographically signed assertions of who owns which prefix β€” finally covers more than half of routed IPv4 space. The first credible defense against BGP hijacks since BGP\'s invention.' + "Resource Public Key Infrastructure β€” cryptographically signed assertions of who owns which prefix β€” finally covers more than half of routed IPv4 space. The first credible defense against BGP hijacks since BGP's invention." } ] }, @@ -124,7 +124,7 @@ export const routingStory: SubcategoryStory = { { label: '[[ospf|OSPF]]', values: [ - 'Within one {{as|AS}} (intra-domain)', + 'Within one {{autonomous-system|AS}} (intra-domain)', 'Link-state β€” every router knows full topology, runs [[pioneer:edsger-dijkstra|Dijkstra]] locally', 'Path cost (bandwidth-derived integer)', 'Full trust β€” all routers in the same administrative domain', @@ -134,7 +134,7 @@ export const routingStory: SubcategoryStory = { { label: '[[bgp|BGP]]', values: [ - 'Between {{as|ASes}} (inter-domain)', + 'Between {{autonomous-system|ASes}} (inter-domain)', 'Path-vector β€” exchange path lists, no shared topology', 'Local policy (LOCAL_PREF, AS_PATH length, MED, ...)', 'Zero trust β€” peers are competitors, customers, or random ISPs', @@ -164,7 +164,7 @@ export const routingStory: SubcategoryStory = { A->>A: Install route 192.0.2.0/24 via C Note over A,C: AS 64500 announces nothing back β€” customer does not transit for providers`, caption: - "BGP isn't about shortest path β€” it's about *policy*. The rule of thumb: prefer customer routes (you get paid), then peers (free), then transit (you pay). \"Hot potato routing\" β€” get the packet out your network as fast as possible β€” is policy expressed as IGP cost in step 5.", + 'BGP isn\'t about shortest path β€” it\'s about *policy*. The rule of thumb: prefer customer routes (you get paid), then peers (free), then transit (you pay). "Hot potato routing" β€” get the packet out your network as fast as possible β€” is policy expressed as IGP cost in step 5.', steps: { 0: '**The setup.** AS 64500 (a small content provider) has two ways to reach AS 13335 (Cloudflare): through its paid transit provider B, or through a free direct peering with C. Which path wins?', 1: '**Transit provider sends an UPDATE.** B says "I can reach 192.0.2.0/24 β€” the AS_PATH is [65001, 13335]." (Each AS prepends itself when forwarding.)', @@ -175,15 +175,15 @@ export const routingStory: SubcategoryStory = { 6: 'Step 3: **lowest MED** (Multi-Exit Discriminator). Hint set by the *neighbor* to influence which entry point you use. Usually ignored across ASes for trust reasons. Still tied.', 7: 'Step 4: **eBGP preferred over iBGP.** External BGP (between ASes) is preferred over internal BGP (within your AS). Both candidates are eBGP β€” still tied.', 8: 'Step 5: **lowest IGP cost to the next-hop wins.** The direct peer C is one hop away inside our network; the transit provider B is several hops further. C wins.', - 9: '**Selected via AS 65002.** The direct peer wins because it\'s closer in our internal topology AND because crossing it is free (peering is settlement-free; transit is paid).', + 9: "**Selected via AS 65002.** The direct peer wins because it's closer in our internal topology AND because crossing it is free (peering is settlement-free; transit is paid).", 10: 'Router **installs the route** in the forwarding table: traffic destined to 192.0.2.0/24 goes out the peering link to C.', - 11: '**Announcement back.** AS 64500 (a customer) doesn\'t re-announce this route to its providers β€” customers don\'t transit for their providers. This single-line policy rule is what makes the global routing table converge.' + 11: "**Announcement back.** AS 64500 (a customer) doesn't re-announce this route to its providers β€” customers don't transit for their providers. This single-line policy rule is what makes the global routing table converge." } }, { type: 'callout', title: 'BGP Runs on Trust That Nobody Should Have', - text: `For 30 years, [[bgp|BGP]] had no authentication. If you peered with another network, you trusted what they announced. If they announced Google's prefix from their own AS, your router believed them, and your packets to Google went to their network instead.\n\nThis isn't theoretical. [[outage:pakistan-youtube-2008|Pakistan Telecom took YouTube offline globally in 2008]] by announcing a more-specific route to its own prefix β€” an attempt to censor YouTube *locally* that leaked worldwide. China Telecom rerouted 15% of global Internet traffic through China for 18 minutes in April 2010. Russia rerouted Mastercard and Visa traffic in 2017. These weren\'t exploits β€” they were just BGP working as designed.\n\nThe partial fix arriving now is **{{rpki|RPKI}}** β€” Resource Public Key Infrastructure. Address owners cryptographically sign assertions: "AS 13335 is allowed to originate 1.1.1.0/24." Routers validate incoming announcements against these signatures. By 2024, RPKI coverage finally crossed 50% of routed IPv4. The next step β€” **BGPsec**, which would sign the entire AS_PATH, not just the origin β€” has been "shipping next year" since 2017. Path-level validation is hard.` + text: `For 30 years, [[bgp|BGP]] had no authentication. If you peered with another network, you trusted what they announced. If they announced Google's prefix from their own AS, your router believed them, and your packets to Google went to their network instead.\n\nThis isn't theoretical. [[outage:pakistan-youtube-2008|Pakistan Telecom took YouTube offline globally in 2008]] by announcing a more-specific route to its own prefix β€” an attempt to censor YouTube *locally* that leaked worldwide. China Telecom rerouted 15% of global Internet traffic through China for 18 minutes in April 2010. Russia rerouted Mastercard and Visa traffic in 2017. These weren't exploits β€” they were just BGP working as designed.\n\nThe partial fix arriving now is **{{rpki|RPKI}}** β€” Resource Public Key Infrastructure. Address owners cryptographically sign assertions: "AS 13335 is allowed to originate 1.1.1.0/24." Routers validate incoming announcements against these signatures. By 2024, RPKI coverage finally crossed 50% of routed IPv4. The next step β€” **BGPsec**, which would sign the entire AS_PATH, not just the origin β€” has been "shipping next year" since 2017. Path-level validation is hard.` }, { type: 'narrative', @@ -192,7 +192,7 @@ export const routingStory: SubcategoryStory = { }, { type: 'narrative', - title: 'What\'s Next', + title: "What's Next", text: `Active work in 2025:\n\n- **{{rpki|RPKI}} coverage** continues to grow toward universal β€” the goal is a tipping point where invalid announcements are dropped by enough networks that hijacks become unprofitable. AT&T, Telia, NTT, Comcast all now drop RPKI-invalid routes.\n- **BGPsec** β€” full AS_PATH signing β€” remains stuck in the "almost deployable" zone. Hardware capable of signing each hop at line rate is finally available, but ecosystem adoption is slow.\n- **Segment Routing (SRv6)** is replacing MPLS-TE in some ISP backbones. Encodes the explicit path in the [[ipv6|IPv6]] header itself; doesn't replace [[bgp|BGP]] but changes what an IGP needs to compute.\n- **The deprecation of public looking glasses** β€” many ISPs are turning off the public "show me your BGP table" tools that BGP researchers relied on for decades, citing security. The visible Internet is becoming less visible.\n\nRouting protocols themselves change slowly. The change is happening in *what runs on top of them* β€” verification, policy automation, observability.` } ] diff --git a/src/lib/data/subcategory-stories/rpc-styles.ts b/src/lib/data/subcategory-stories/rpc-styles.ts index cecd45b..ee59843 100644 --- a/src/lib/data/subcategory-stories/rpc-styles.ts +++ b/src/lib/data/subcategory-stories/rpc-styles.ts @@ -3,7 +3,7 @@ import type { SubcategoryStory } from './types'; export const rpcStylesStory: SubcategoryStory = { subcategoryId: 'rpc-styles', tagline: - "Call a remote function like a local one β€” the dream of remote procedure call across forty years of attempts", + 'Call a remote function like a local one β€” the dream of remote procedure call across forty years of attempts', sections: [ { type: 'narrative', @@ -53,7 +53,7 @@ export const rpcStylesStory: SubcategoryStory = { year: 1987, title: 'Sun RPC / ONC RPC', description: - "Sun ships RPC as the foundation for NFS. XDR for marshalling, portmap for service discovery. The first widely-deployed RPC outside research." + 'Sun ships RPC as the foundation for NFS. XDR for marshalling, portmap for service discovery. The first widely-deployed RPC outside research.' }, { year: 1991, @@ -65,13 +65,13 @@ export const rpcStylesStory: SubcategoryStory = { year: 1998, title: 'XML-RPC Published', description: - "Dave Winer's deliberately minimal XML-over-HTTP RPC. The spec fits on a napkin. Becomes the first widely-used \"RPC for the web.\"" + 'Dave Winer\'s deliberately minimal XML-over-HTTP RPC. The spec fits on a napkin. Becomes the first widely-used "RPC for the web."' }, { year: 1999, title: 'SOAP 1.0', description: - "Microsoft + Userland + others publish [[soap|SOAP]] β€” XML-RPC reframed for enterprise. WSDL for service description; XML Schema for types. Adoption explodes through 2005." + 'Microsoft + Userland + others publish [[soap|SOAP]] β€” XML-RPC reframed for enterprise. WSDL for service description; XML Schema for types. Adoption explodes through 2005.' }, { year: 2005, @@ -83,7 +83,7 @@ export const rpcStylesStory: SubcategoryStory = { year: 2008, title: 'Protocol Buffers Open-Sourced', description: - "Google releases protobuf β€” the typed binary serialization format used internally since 2001. Schemas in \`.proto\` files generate strongly-typed code in C++, Java, Python, Go." + 'Google releases protobuf β€” the typed binary serialization format used internally since 2001. Schemas in `.proto` files generate strongly-typed code in C++, Java, Python, Go.' }, { year: 2015, @@ -107,7 +107,7 @@ export const rpcStylesStory: SubcategoryStory = { year: 2024, title: 'Buf Connect Protocol', description: - "Connect β€” a gRPC-compatible protocol that also speaks plain HTTP/JSON β€” splits the difference between gRPC and REST. Same .proto definitions, runs in browsers without a proxy." + 'Connect β€” a gRPC-compatible protocol that also speaks plain HTTP/JSON β€” splits the difference between gRPC and REST. Same .proto definitions, runs in browsers without a proxy.' } ] }, @@ -142,7 +142,7 @@ export const rpcStylesStory: SubcategoryStory = { 'Protocol Buffers (binary)', '.proto IDL (typed, versioned)', '[[http2|HTTP/2]] streaming', - "Heavy β€” generates clients in C++, Java, Go, Python, Ruby, JS, etc.", + 'Heavy β€” generates clients in C++, Java, Go, Python, Ruby, JS, etc.', 'Internal microservices at scale; mobile-to-backend with typed contracts' ] } @@ -189,7 +189,7 @@ export const rpcStylesStory: SubcategoryStory = { 12: 'Server responds to and acks message 2 in one frame.', 13: 'Client sends message 3.', 14: 'Server responds. The two sides keep ping-ponging until either closes the stream.', - 15: '**One HTTP/2 connection** carries all of these calls (and dozens more in parallel for other RPCs). HTTP/2\'s frame multiplexing means small messages from different streams interleave without blocking each other.' + 15: "**One HTTP/2 connection** carries all of these calls (and dozens more in parallel for other RPCs). HTTP/2's frame multiplexing means small messages from different streams interleave without blocking each other." } }, { @@ -200,12 +200,12 @@ export const rpcStylesStory: SubcategoryStory = { { type: 'narrative', title: 'The Failure Modes', - text: `[[soap|SOAP]]\'s failure mode is **schema drift**. WSDL pinned the contract at design time, but when servers changed types or added required fields without coordinating client updates, clients broke. WSDL versioning was clunky, and there was no standard way to evolve a contract gracefully. Most enterprises wrote their own change-control processes around SOAP services.\n\n[[json-rpc|JSON-RPC]]\'s failure mode is **no contract at all**. Because there is no schema, what passes for an API is documentation β€” and documentation drifts from implementation. Wallets and blockchain nodes have lived with this for a decade; the workaround is "be very conservative about changing anything." Adding a field is usually safe; renaming is not.\n\n[[grpc|gRPC]]\'s failure mode is **proxy hostility**. HTTP/2 trailers (used for status) aren\'t spoken by browsers, by many corporate proxies, or by old load balancers. Production gRPC at the edge typically requires a proxy (Envoy) to translate. gRPC-Web and the newer Connect protocol exist precisely to escape this. The lesson: every RPC framework eventually meets a middlebox it can\'t pass through.` + text: `[[soap|SOAP]]'s failure mode is **schema drift**. WSDL pinned the contract at design time, but when servers changed types or added required fields without coordinating client updates, clients broke. WSDL versioning was clunky, and there was no standard way to evolve a contract gracefully. Most enterprises wrote their own change-control processes around SOAP services.\n\n[[json-rpc|JSON-RPC]]'s failure mode is **no contract at all**. Because there is no schema, what passes for an API is documentation β€” and documentation drifts from implementation. Wallets and blockchain nodes have lived with this for a decade; the workaround is "be very conservative about changing anything." Adding a field is usually safe; renaming is not.\n\n[[grpc|gRPC]]'s failure mode is **proxy hostility**. HTTP/2 trailers (used for status) aren't spoken by browsers, by many corporate proxies, or by old load balancers. Production gRPC at the edge typically requires a proxy (Envoy) to translate. gRPC-Web and the newer Connect protocol exist precisely to escape this. The lesson: every RPC framework eventually meets a middlebox it can't pass through.` }, { type: 'narrative', - title: 'What\'s Next', - text: `Active work in 2025:\n\n- **Connect protocol** (Buf, 2024) β€” a [[grpc|gRPC]]-compatible protocol that also speaks plain HTTP/JSON, eliminating the browser-proxy problem. Same .proto files generate clients for both transports.\n- **Cap\'n Proto + Tonic + Twirp** β€” lighter alternatives to full gRPC, each with niche followings. Twirp keeps protobuf but drops streaming and HTTP/2 for simpler operations.\n- **OpenAPI codegen catching up** β€” Stainless, Speakeasy, Fern generate typed clients from OpenAPI specs that rival the gRPC developer experience. The line between "typed REST" and "JSON-over-HTTP RPC" is dissolving.\n- **Schema-on-the-wire** experiments (Cap\'n Proto, Apache Avro for streaming) keep niche traction in data pipelines and storage formats.\n- **The unsexy truth**: [[grpc|gRPC]] won internal microservice RPC. [[json-rpc|JSON-RPC]] won blockchain and editor protocols. [[soap|SOAP]] is in maintenance. New API design in 2025 picks gRPC if everything is yours and behind your edge; picks typed REST/OpenAPI if anything is public.` + title: "What's Next", + text: `Active work in 2025:\n\n- **Connect protocol** (Buf, 2024) β€” a [[grpc|gRPC]]-compatible protocol that also speaks plain HTTP/JSON, eliminating the browser-proxy problem. Same .proto files generate clients for both transports.\n- **Cap'n Proto + Tonic + Twirp** β€” lighter alternatives to full gRPC, each with niche followings. Twirp keeps protobuf but drops streaming and HTTP/2 for simpler operations.\n- **OpenAPI codegen catching up** β€” Stainless, Speakeasy, Fern generate typed clients from OpenAPI specs that rival the gRPC developer experience. The line between "typed REST" and "JSON-over-HTTP RPC" is dissolving.\n- **Schema-on-the-wire** experiments (Cap'n Proto, Apache Avro for streaming) keep niche traction in data pipelines and storage formats.\n- **The unsexy truth**: [[grpc|gRPC]] won internal microservice RPC. [[json-rpc|JSON-RPC]] won blockchain and editor protocols. [[soap|SOAP]] is in maintenance. New API design in 2025 picks gRPC if everything is yours and behind your edge; picks typed REST/OpenAPI if anything is public.` } ] }; diff --git a/src/lib/data/subcategory-stories/secure-channels-vpn.ts b/src/lib/data/subcategory-stories/secure-channels-vpn.ts index 59d1aa9..7399729 100644 --- a/src/lib/data/subcategory-stories/secure-channels-vpn.ts +++ b/src/lib/data/subcategory-stories/secure-channels-vpn.ts @@ -3,12 +3,12 @@ import type { SubcategoryStory } from './types'; export const secureChannelsVpnStory: SubcategoryStory = { subcategoryId: 'secure-channels-vpn', tagline: - "Encrypting traffic at different layers, for different threat models β€” transport, app, network, and the minimalist successor", + 'Encrypting traffic at different layers, for different threat models β€” transport, app, network, and the minimalist successor', sections: [ { type: 'narrative', title: 'Four Answers, Four Layers', - text: `In 1990 you could read almost any traffic on the Internet by tapping the wire. Telnet sent passwords in cleartext. SMTP carried mail with the sender\'s name attached. FTP transferred files unauthenticated. The web (when it arrived a year later) was unencrypted. Anyone with a packet sniffer on the right network segment could read everything.\n\nFour responses emerged at four different layers of the stack:\n\n- **[[tls|TLS]]** (originally SSL, 1995) encrypts at the **transport layer**, sitting between TCP and the application. Web browsers connect, do a handshake, then read and write to a normal socket β€” except the socket is encrypted. Everything that used HTTP, SMTP, IMAP, LDAP eventually got a TLS variant. TLS is the encryption layer of the modern Internet.\n- **[[ssh|SSH]]** (1995) replaces Telnet for **remote shell access**, at the **application layer**. Designed by Tatu YlΓΆnen at the Helsinki University of Technology after his university\'s network was sniffed for passwords. SSH became the universal "log into a server" protocol; it also grew port forwarding, tunneling, and SCP/SFTP for file transfer.\n- **[[ipsec|IPsec]]** (1995–1998) encrypts at the **network layer**, inside IP itself. Designed for site-to-site VPNs and for the never-quite-fulfilled IPv6 mandate. Operates either in transport mode (encrypt the payload, leave the IP header) or tunnel mode (encrypt the whole IP packet inside another). Famously complex; runs almost every enterprise VPN deployed before ~2020.\n- **[[wireguard|WireGuard]]** (2016) is the **minimalist successor** to IPsec. ~4,000 lines of kernel code (versus IPsec\'s ~400,000). Fixed modern cryptography (no negotiation). Connectionless. Designed by Jason Donenfeld in part out of frustration with the IPsec complexity stack. Merged into the Linux kernel in 2020; now ships in macOS, Windows, every major VPN provider.\n\nEach lives at a different layer because each addresses a different problem. You can run TLS *inside* an IPsec tunnel; you can SSH *over* a WireGuard interface; you can run WireGuard *over* TLS to escape a restrictive firewall. The encryption layers compose.` + text: `In 1990 you could read almost any traffic on the Internet by tapping the wire. Telnet sent passwords in cleartext. SMTP carried mail with the sender's name attached. FTP transferred files unauthenticated. The web (when it arrived a year later) was unencrypted. Anyone with a packet sniffer on the right network segment could read everything.\n\nFour responses emerged at four different layers of the stack:\n\n- **[[tls|TLS]]** (originally SSL, 1995) encrypts at the **transport layer**, sitting between TCP and the application. Web browsers connect, do a handshake, then read and write to a normal socket β€” except the socket is encrypted. Everything that used HTTP, SMTP, IMAP, LDAP eventually got a TLS variant. TLS is the encryption layer of the modern Internet.\n- **[[ssh|SSH]]** (1995) replaces Telnet for **remote shell access**, at the **application layer**. Designed by Tatu YlΓΆnen at the Helsinki University of Technology after his university's network was sniffed for passwords. SSH became the universal "log into a server" protocol; it also grew port forwarding, tunneling, and SCP/SFTP for file transfer.\n- **[[ipsec|IPsec]]** (1995–1998) encrypts at the **network layer**, inside IP itself. Designed for site-to-site VPNs and for the never-quite-fulfilled IPv6 mandate. Operates either in transport mode (encrypt the payload, leave the IP header) or tunnel mode (encrypt the whole IP packet inside another). Famously complex; runs almost every enterprise VPN deployed before ~2020.\n- **[[wireguard|WireGuard]]** (2016) is the **minimalist successor** to IPsec. ~4,000 lines of kernel code (versus IPsec's ~400,000). Fixed modern cryptography (no negotiation). Connectionless. Designed by Jason Donenfeld in part out of frustration with the IPsec complexity stack. Merged into the Linux kernel in 2020; now ships in macOS, Windows, every major VPN provider.\n\nEach lives at a different layer because each addresses a different problem. You can run TLS *inside* an IPsec tunnel; you can SSH *over* a WireGuard interface; you can run WireGuard *over* TLS to escape a restrictive firewall. The encryption layers compose.` }, { type: 'pioneers', @@ -18,7 +18,7 @@ export const secureChannelsVpnStory: SubcategoryStory = { id: 'taher-elgamal', name: 'Taher Elgamal', years: '1955–', - title: '\"Father of SSL\"', + title: '"Father of SSL"', org: 'Netscape / RSA Security / Salesforce', contribution: "Led the cryptography team at Netscape that designed SSL 2.0 (1995) and SSL 3.0 (1996) β€” the foundations of what would become [[tls|TLS]]. Elgamal also invented the ElGamal encryption and signature schemes during his PhD at Stanford under Martin Hellman. Without SSL there is no e-commerce; without e-commerce the web economy is unrecognizable. Few protocols have had higher economic impact than Elgamal\\'s 1995 work." @@ -30,7 +30,7 @@ export const secureChannelsVpnStory: SubcategoryStory = { title: 'IPsec / IKE Implementer', org: 'SafeNet / Independent', contribution: - "Maintained the reference implementation of [[ipsec|IPsec]] / IKE used by half the industry (Racoon, isakmpd). Authored or co-authored ~30 IPsec-related RFCs, including significant parts of IKEv2. Kivinen\\'s sustained engineering work is one of the reasons IPsec went from \"unimplementable in practice\" to \"the default enterprise VPN for 25 years.\"" + 'Maintained the reference implementation of [[ipsec|IPsec]] / IKE used by half the industry (Racoon, isakmpd). Authored or co-authored ~30 IPsec-related RFCs, including significant parts of IKEv2. Kivinen\\\'s sustained engineering work is one of the reasons IPsec went from "unimplementable in practice" to "the default enterprise VPN for 25 years."' }, { id: 'jason-donenfeld', @@ -58,13 +58,13 @@ export const secureChannelsVpnStory: SubcategoryStory = { year: 1995, title: 'SSL 2.0 (Netscape)', description: - "Netscape ships SSL 2.0 in Navigator. Cryptographically weak (multiple flaws); replaced within a year by SSL 3.0." + 'Netscape ships SSL 2.0 in Navigator. Cryptographically weak (multiple flaws); replaced within a year by SSL 3.0.' }, { year: 1995, title: 'SSH 1.0 (YlΓΆnen)', description: - '[[ssh|SSH]] replaces Telnet for remote login. Within a year it\'s standard on every Unix.' + "[[ssh|SSH]] replaces Telnet for remote login. Within a year it's standard on every Unix." }, { year: 1995, @@ -82,7 +82,7 @@ export const secureChannelsVpnStory: SubcategoryStory = { year: 2005, title: 'IKEv2 / IPsec Stabilizes', description: - "After a decade of IKEv1 (Internet Key Exchange v1) frustration, IKEv2 ships ([[ipsec|RFC 4306]], later 5996). Most modern IPsec deployments use IKEv2." + 'After a decade of IKEv1 (Internet Key Exchange v1) frustration, IKEv2 ships ([[ipsec|RFC 4306]], later 5996). Most modern IPsec deployments use IKEv2.' }, { year: 2008, @@ -100,7 +100,7 @@ export const secureChannelsVpnStory: SubcategoryStory = { year: 2016, title: 'WireGuard First Release', description: - "[[pioneer:jason-donenfeld|Donenfeld]] publishes WireGuard 0.1. Initial reception in the cryptography community is enthusiastic β€” \"finally, a VPN protocol you can read in an afternoon.\"" + '[[pioneer:jason-donenfeld|Donenfeld]] publishes WireGuard 0.1. Initial reception in the cryptography community is enthusiastic β€” "finally, a VPN protocol you can read in an afternoon."' }, { year: 2018, @@ -112,19 +112,19 @@ export const secureChannelsVpnStory: SubcategoryStory = { year: 2020, title: 'WireGuard Mainlined in Linux 5.6', description: - "Linus Torvalds merges WireGuard into the Linux kernel after years of \"please can we have this.\" Within months it ships in major distros and is the default of new VPN services (Mullvad, Tailscale, NordVPN\'s NordLynx)." + 'Linus Torvalds merges WireGuard into the Linux kernel after years of "please can we have this." Within months it ships in major distros and is the default of new VPN services (Mullvad, Tailscale, NordVPN\'s NordLynx).' }, { year: 2021, title: 'Tailscale Mainstream Adoption', description: - "Tailscale β€” a WireGuard-based zero-config mesh VPN with NAT punch-through and coordination server β€” explodes in adoption. Demonstrates that \"WireGuard plus a control plane\" is the future of \"how do I connect my laptop to my home server.\"" + 'Tailscale β€” a WireGuard-based zero-config mesh VPN with NAT punch-through and coordination server β€” explodes in adoption. Demonstrates that "WireGuard plus a control plane" is the future of "how do I connect my laptop to my home server."' }, { year: 2024, title: 'Post-Quantum TLS Rolls Out', description: - "Chrome, Cloudflare, Apple roll out hybrid post-quantum key exchange (X25519+Kyber/MLKEM) in TLS 1.3 connections by default. The first widely-deployed PQC in production." + 'Chrome, Cloudflare, Apple roll out hybrid post-quantum key exchange (X25519+Kyber/MLKEM) in TLS 1.3 connections by default. The first widely-deployed PQC in production.' } ] }, @@ -140,7 +140,7 @@ export const secureChannelsVpnStory: SubcategoryStory = { 'HTTPS, IMAPS, SMTPS, any TCP service', '1-RTT (TLS 1.3); 2-RTT (older)', 'X.509 certificate hierarchy', - "Record protocol with handshake / app data / alert layers" + 'Record protocol with handshake / app data / alert layers' ] }, { @@ -150,7 +150,7 @@ export const secureChannelsVpnStory: SubcategoryStory = { 'Remote shell, tunneling, file transfer', 'Custom β€” diffie-hellman + key auth', 'Server host keys + user keys (no PKI)', - "Binary packet protocol over TCP" + 'Binary packet protocol over TCP' ] }, { @@ -158,9 +158,9 @@ export const secureChannelsVpnStory: SubcategoryStory = { values: [ 'Network (inside IP)', 'Site-to-site VPN, IPv6 mandate', - "IKEv2 β€” typically 4 messages", - "Pre-shared keys, X.509, or EAP", - "ESP (encrypted payload) and AH (auth header)" + 'IKEv2 β€” typically 4 messages', + 'Pre-shared keys, X.509, or EAP', + 'ESP (encrypted payload) and AH (auth header)' ] }, { @@ -169,12 +169,12 @@ export const secureChannelsVpnStory: SubcategoryStory = { 'Network (UDP-based virtual interface)', 'Modern VPN β€” point-to-point and mesh', '1-RTT β€” Noise IK pattern', - "Public keys exchanged out of band (simple)", - "UDP datagrams β€” no TCP fallback, no algorithm negotiation" + 'Public keys exchanged out of band (simple)', + 'UDP datagrams β€” no TCP fallback, no algorithm negotiation' ] } ], - note: "These don\\'t compete the way most protocol families do. Different layers, different use cases. The replacement question is mostly *IPsec β†’ WireGuard* (where the answer is \"yes, almost always for new deployments\")." + note: 'These don\\\'t compete the way most protocol families do. Different layers, different use cases. The replacement question is mostly *IPsec β†’ WireGuard* (where the answer is "yes, almost always for new deployments").' }, { type: 'animated-sequence', @@ -199,12 +199,12 @@ export const secureChannelsVpnStory: SubcategoryStory = { steps: { 0: '**The win.** TLS 1.2 needed 2 full round trips (4 messages) before any app data could flow β€” TCP added 1 more. TLS 1.3 cuts that to 1 RTT for the handshake, and 0 RTT on session resumption. The savings are enormous on high-latency mobile links.', 1: 'Client opens with **ClientHello**: supported TLS versions, cipher suites it accepts, *and* a `key_share` β€” a Diffie-Hellman public key. This bold "send key material in the first message" choice is what enables 1-RTT.', - 2: 'Server **picks a cipher suite** from the client\'s offered list and immediately derives handshake encryption keys using its own ephemeral DH private key + the client\'s `key_share`. No back-and-forth negotiation.', + 2: "Server **picks a cipher suite** from the client's offered list and immediately derives handshake encryption keys using its own ephemeral DH private key + the client's `key_share`. No back-and-forth negotiation.", 3: 'Server sends **ServerHello** with its `key_share` (so the client can derive the same handshake keys) plus EncryptedExtensions (additional negotiation, now encrypted).', 4: 'Server sends **Certificate** β€” encrypted with the handshake key. Notable: the cert itself is encrypted, defeating passive observers from learning *which* certificate (and thus which hostname) is in play.', 5: 'Server sends **CertificateVerify** β€” a signature over the handshake transcript proving the server owns the private key for the cert.', 6: 'Server sends **Finished** β€” a MAC over the entire transcript so far, proving both sides agreed on the same handshake.', - 7: '**Client verifies.** It checks the certificate chain against its trust store and validates the CertificateVerify signature. If anything\'s wrong, the connection aborts here.', + 7: "**Client verifies.** It checks the certificate chain against its trust store and validates the CertificateVerify signature. If anything's wrong, the connection aborts here.", 8: 'Client sends its own **Finished** β€” its MAC over the transcript, proving it saw the same handshake messages.', 9: 'Client sends **application data** encrypted under freshly-derived application keys. The first useful request rides in the same RTT as the Finished β€” net: 1 round trip from "connect" to "request sent."', 10: 'Server responds with **application data** under the same keys. The connection is now established and encrypted; everything from here is just data.', @@ -214,17 +214,17 @@ export const secureChannelsVpnStory: SubcategoryStory = { { type: 'callout', title: 'Why WireGuard Beat IPsec', - text: `[[ipsec|IPsec]] is a marvel of engineering. It supports every cipher, every key-exchange algorithm, every NAT-traversal mode, every X.509 PKI scheme, every EAP authentication method. It can run in transport mode or tunnel mode, with ESP or AH, in tunnel mode with or without traffic-flow confidentiality, with extended-sequence-number replay protection, with NAT-T encapsulation. The IKEv2 negotiation alone has dozens of attribute classes.\n\nThis is the source of its problem. *Algorithm agility* β€” the ability to negotiate among many crypto choices β€” is what kept SSL/TLS upgradeable, but it\'s also what made many of its worst bugs possible (POODLE, FREAK, Logjam). IPsec multiplied this by adding negotiation between every layer of the stack.\n\n[[wireguard|WireGuard]] made the opposite bet:\n\n- **Fixed cryptography**: Curve25519 for key exchange, ChaCha20-Poly1305 for symmetric encryption, BLAKE2s for hashing. No negotiation. If a primitive is broken, the protocol version is incremented and clients/servers update together.\n- **No PKI**: every peer has a single Curve25519 public key. You configure peers by their public keys, like SSH \`authorized_keys\`. No certificates, no CAs, no expiration ceremonies.\n- **Stateless on the wire**: each packet stands alone. No "connection." If the server reboots or a NAT mapping changes, the next packet just works.\n- **Connectionless from the kernel\'s view**: WireGuard creates a regular network interface (\`wg0\`). Routes go to it like any other interface. The kernel doesn\'t know it\'s a VPN.\n\nThe codebase: ~4,000 lines of kernel C. Linux\'s IPsec stack: ~400,000 lines. Donenfeld\'s thesis was simple β€” *crypto code you can audit fits in your head*. The audit was done by Tor Project security researchers and found nothing. The protocol shipped. The result is the first VPN protocol most security engineers genuinely *trust* without caveats.` + text: `[[ipsec|IPsec]] is a marvel of engineering. It supports every cipher, every key-exchange algorithm, every NAT-traversal mode, every X.509 PKI scheme, every EAP authentication method. It can run in transport mode or tunnel mode, with ESP or AH, in tunnel mode with or without traffic-flow confidentiality, with extended-sequence-number replay protection, with NAT-T encapsulation. The IKEv2 negotiation alone has dozens of attribute classes.\n\nThis is the source of its problem. *Algorithm agility* β€” the ability to negotiate among many crypto choices β€” is what kept SSL/TLS upgradeable, but it's also what made many of its worst bugs possible (POODLE, FREAK, Logjam). IPsec multiplied this by adding negotiation between every layer of the stack.\n\n[[wireguard|WireGuard]] made the opposite bet:\n\n- **Fixed cryptography**: Curve25519 for key exchange, ChaCha20-Poly1305 for symmetric encryption, BLAKE2s for hashing. No negotiation. If a primitive is broken, the protocol version is incremented and clients/servers update together.\n- **No PKI**: every peer has a single Curve25519 public key. You configure peers by their public keys, like SSH \`authorized_keys\`. No certificates, no CAs, no expiration ceremonies.\n- **Stateless on the wire**: each packet stands alone. No "connection." If the server reboots or a NAT mapping changes, the next packet just works.\n- **Connectionless from the kernel's view**: WireGuard creates a regular network interface (\`wg0\`). Routes go to it like any other interface. The kernel doesn't know it's a VPN.\n\nThe codebase: ~4,000 lines of kernel C. Linux's IPsec stack: ~400,000 lines. Donenfeld's thesis was simple β€” *crypto code you can audit fits in your head*. The audit was done by Tor Project security researchers and found nothing. The protocol shipped. The result is the first VPN protocol most security engineers genuinely *trust* without caveats.` }, { type: 'narrative', title: 'The Failure Modes', - text: `[[tls|TLS]]\'s failure mode is **certificate validation**. The cryptography is solid; the trust model is the weak link. A misissued certificate from a single trusted CA can MITM any site on the Internet. {{ct|Certificate Transparency}} is the public ledger of all issued certs; HPKP (Public Key Pinning) was an attempt at user-controlled pinning that got removed because mistakes broke entire sites. Let\'s Encrypt democratized cert issuance, but the underlying X.509/CA model is still the most fragile part of the stack.\n\n[[ssh|SSH]]\'s failure mode is **trust on first use**. The first time you connect to a host, you accept its public key as-is. If the host\'s key changes (legitimate rotation? attacker MITM?), SSH warns you, but most users just delete the line in \`known_hosts\` and reconnect. SSH certificate authorities (smallstep, Teleport, Vault SSH backend) fix this but require deployment.\n\n[[ipsec|IPsec]]\'s failure mode is **interop**. Two correctly-implemented IPsec stacks may fail to talk to each other because they pick different defaults. The "IKEv2 connection works between Cisco and Palo Alto if you set X, Y, and Z correctly" stories fill the support forums. {{ikev2|IKEv2}} reduced the variance, but the legacy of IKEv1 still haunts deployments.\n\n[[wireguard|WireGuard]]\'s failure mode is **roaming and mobility**. WireGuard\'s connectionless model is elegant β€” except every peer\'s configuration includes a fixed UDP endpoint. When a phone moves from Wi-Fi to LTE, the endpoint changes; the server has to learn the new one. WireGuard handles this (the server\'s endpoint floats to wherever the latest authenticated packet came from), but the *initial* connection from a roaming client requires the server to have a stable address. Mesh deployments need a coordination plane β€” Tailscale, Headscale, Netbird, NetMaker exist precisely to add this layer.` + text: `[[tls|TLS]]'s failure mode is **certificate validation**. The cryptography is solid; the trust model is the weak link. A misissued certificate from a single trusted CA can MITM any site on the Internet. {{certificate-transparency|Certificate Transparency}} is the public ledger of all issued certs; HPKP (Public Key Pinning) was an attempt at user-controlled pinning that got removed because mistakes broke entire sites. Let's Encrypt democratized cert issuance, but the underlying X.509/CA model is still the most fragile part of the stack.\n\n[[ssh|SSH]]'s failure mode is **trust on first use**. The first time you connect to a host, you accept its public key as-is. If the host's key changes (legitimate rotation? attacker MITM?), SSH warns you, but most users just delete the line in \`known_hosts\` and reconnect. SSH certificate authorities (smallstep, Teleport, Vault SSH backend) fix this but require deployment.\n\n[[ipsec|IPsec]]'s failure mode is **interop**. Two correctly-implemented IPsec stacks may fail to talk to each other because they pick different defaults. The "IKEv2 connection works between Cisco and Palo Alto if you set X, Y, and Z correctly" stories fill the support forums. {{ikev2|IKEv2}} reduced the variance, but the legacy of IKEv1 still haunts deployments.\n\n[[wireguard|WireGuard]]'s failure mode is **roaming and mobility**. WireGuard's connectionless model is elegant β€” except every peer's configuration includes a fixed UDP endpoint. When a phone moves from Wi-Fi to LTE, the endpoint changes; the server has to learn the new one. WireGuard handles this (the server's endpoint floats to wherever the latest authenticated packet came from), but the *initial* connection from a roaming client requires the server to have a stable address. Mesh deployments need a coordination plane β€” Tailscale, Headscale, Netbird, NetMaker exist precisely to add this layer.` }, { type: 'narrative', - title: 'What\'s Next', - text: `Active work in 2025:\n\n- **Post-quantum TLS** is rolling out. Chrome, Cloudflare, Apple have already deployed hybrid X25519+ML-KEM (Kyber) by default. NIST PQC standards finalized in 2024; the migration phase is now.\n- **Encrypted Client Hello (ECH)** hides the SNI (which hostname the client is asking for) from passive observers. Default-on in Chrome and Firefox in 2024. The last unencrypted metadata in a TLS connection is gone.\n- **WireGuard in everything** β€” every major commercial VPN now offers WireGuard. Cloudflare WARP, Tailscale, Mullvad, NordVPN, Surfshark. The transition from OpenVPN/IPsec is essentially complete for consumer VPNs.\n- **SSH certificates** are slowly displacing \`authorized_keys\` files in enterprise environments. Short-lived certificates issued by a CA (HashiCorp Vault, smallstep CA, Teleport) provide centralized control and automatic expiry.\n- **MASQUE** (proxy traffic inside QUIC) is the next generation of "VPN" β€” used by iCloud Private Relay and Cloudflare\'s Privacy Gateway. Not a replacement for site-to-site IPsec, but a replacement for the "encrypted DNS + proxy" pattern that consumer VPNs deliver.\n- **Memory-safe TLS implementations** (rustls, BoringSSL\'s improvements, OpenSSL 3.x rewrites) continue replacing C-based stacks where the language gives crypto code more guarantees against the Heartbleed-class bugs.` + title: "What's Next", + text: `Active work in 2025:\n\n- **Post-quantum TLS** is rolling out. Chrome, Cloudflare, Apple have already deployed hybrid X25519+ML-KEM (Kyber) by default. NIST PQC standards finalized in 2024; the migration phase is now.\n- **Encrypted Client Hello (ECH)** hides the SNI (which hostname the client is asking for) from passive observers. Default-on in Chrome and Firefox in 2024. The last unencrypted metadata in a TLS connection is gone.\n- **WireGuard in everything** β€” every major commercial VPN now offers WireGuard. Cloudflare WARP, Tailscale, Mullvad, NordVPN, Surfshark. The transition from OpenVPN/IPsec is essentially complete for consumer VPNs.\n- **SSH certificates** are slowly displacing \`authorized_keys\` files in enterprise environments. Short-lived certificates issued by a CA (HashiCorp Vault, smallstep CA, Teleport) provide centralized control and automatic expiry.\n- **MASQUE** (proxy traffic inside QUIC) is the next generation of "VPN" β€” used by iCloud Private Relay and Cloudflare's Privacy Gateway. Not a replacement for site-to-site IPsec, but a replacement for the "encrypted DNS + proxy" pattern that consumer VPNs deliver.\n- **Memory-safe TLS implementations** (rustls, BoringSSL's improvements, OpenSSL 3.x rewrites) continue replacing C-based stacks where the language gives crypto code more guarantees against the Heartbleed-class bugs.` } ] }; diff --git a/src/lib/data/subcategory-stories/streaming-delivery.ts b/src/lib/data/subcategory-stories/streaming-delivery.ts index 4f3e17c..627458e 100644 --- a/src/lib/data/subcategory-stories/streaming-delivery.ts +++ b/src/lib/data/subcategory-stories/streaming-delivery.ts @@ -3,12 +3,12 @@ import type { SubcategoryStory } from './types'; export const streamingDeliveryStory: SubcategoryStory = { subcategoryId: 'streaming-delivery', tagline: - "Delivering video at Internet scale β€” from Flash push to adaptive HTTP, and the protocol that refused to die", + 'Delivering video at Internet scale β€” from Flash push to adaptive HTTP, and the protocol that refused to die', sections: [ { type: 'narrative', title: 'How the Web Learned to Stream', - text: `In 2005, YouTube put up its first videos. They were Flash. By 2007 every video on the open web was Flash β€” \`<object\` tags pointing to .flv files served over **[[rtmp|RTMP]]**, Adobe\'s proprietary real-time streaming protocol. RTMP was *push-based*: the server streamed frames to the player over a long-lived TCP connection, and the player buffered and rendered them. For a decade, this was how video worked.\n\nThen mobile happened. Apple shipped the iPhone in 2007, refused to support Flash, and within five years had killed RTMP playback on the open web. The replacements β€” **[[hls|HLS]]** from Apple and **[[dash|DASH]]** from the ISO/IEC MPEG group β€” share an audacious idea: *use plain HTTP, like everything else on the web*. Instead of one long stream, the video is chopped into many small segments (typically 2–10 seconds each), each fetched as a separate [[http1|HTTP]] GET. A manifest file (\`.m3u8\` for HLS, \`.mpd\` for DASH) lists the segments and the available bitrates.\n\nThis is **adaptive bitrate streaming**. The player constantly measures its bandwidth and switches to the appropriate quality between segments. Network drops to 1 Mbps? Next segment fetched at 720p instead of 1080p. Recovered? Back to 1080p. The whole apparatus runs over the same HTTP infrastructure that serves images and JavaScript β€” caches at the CDN, served from disk, no special protocol stack.\n\n[[rtmp|RTMP]] didn\'t die. Player-facing RTMP is gone, but RTMP is still the dominant *ingest* protocol: when a streamer pushes video to Twitch, YouTube Live, or Facebook Live, they\'re almost certainly using RTMP from OBS or a hardware encoder. The "broadcast in" leg uses RTMP; the "broadcast out" leg uses HLS or DASH. Fifteen years after Adobe stopped pushing it, RTMP is still the default for live video ingest because nobody has bothered to replace it.` + text: `In 2005, YouTube put up its first videos. They were Flash. By 2007 every video on the open web was Flash β€” \`<object\` tags pointing to .flv files served over **[[rtmp|RTMP]]**, Adobe's proprietary real-time streaming protocol. RTMP was *push-based*: the server streamed frames to the player over a long-lived TCP connection, and the player buffered and rendered them. For a decade, this was how video worked.\n\nThen mobile happened. Apple shipped the iPhone in 2007, refused to support Flash, and within five years had killed RTMP playback on the open web. The replacements β€” **[[hls|HLS]]** from Apple and **[[dash|DASH]]** from the ISO/IEC MPEG group β€” share an audacious idea: *use plain HTTP, like everything else on the web*. Instead of one long stream, the video is chopped into many small segments (typically 2–10 seconds each), each fetched as a separate [[http1|HTTP]] GET. A manifest file (\`.m3u8\` for HLS, \`.mpd\` for DASH) lists the segments and the available bitrates.\n\nThis is **adaptive bitrate streaming**. The player constantly measures its bandwidth and switches to the appropriate quality between segments. Network drops to 1 Mbps? Next segment fetched at 720p instead of 1080p. Recovered? Back to 1080p. The whole apparatus runs over the same HTTP infrastructure that serves images and JavaScript β€” caches at the CDN, served from disk, no special protocol stack.\n\n[[rtmp|RTMP]] didn't die. Player-facing RTMP is gone, but RTMP is still the dominant *ingest* protocol: when a streamer pushes video to Twitch, YouTube Live, or Facebook Live, they're almost certainly using RTMP from OBS or a hardware encoder. The "broadcast in" leg uses RTMP; the "broadcast out" leg uses HLS or DASH. Fifteen years after Adobe stopped pushing it, RTMP is still the default for live video ingest because nobody has bothered to replace it.` }, { type: 'pioneers', @@ -28,7 +28,7 @@ export const streamingDeliveryStory: SubcategoryStory = { title: 'DASH Chair', org: 'MPEG / Microsoft', contribution: - "Chaired the MPEG working group that standardized [[dash|MPEG-DASH]] (ISO/IEC 23009-1) in 2012. Where [[hls|HLS]] was a single-vendor spec, DASH was the standards-body answer β€” designed to be codec-agnostic, container-agnostic, and royalty-free. Sodagar and the DASH-IF (DASH Industry Forum) drove interop testing across hundreds of player and encoder implementations." + 'Chaired the MPEG working group that standardized [[dash|MPEG-DASH]] (ISO/IEC 23009-1) in 2012. Where [[hls|HLS]] was a single-vendor spec, DASH was the standards-body answer β€” designed to be codec-agnostic, container-agnostic, and royalty-free. Sodagar and the DASH-IF (DASH Industry Forum) drove interop testing across hundreds of player and encoder implementations.' }, { name: 'Will Law', @@ -36,7 +36,7 @@ export const streamingDeliveryStory: SubcategoryStory = { title: 'CMAF / Low-Latency Streaming Architect', org: 'Akamai', contribution: - "Co-led the Common Media Application Format (CMAF, 2016) effort to unify the segment formats used by HLS and DASH β€” for years both used MPEG-2 Transport Streams for HLS and fragmented MP4 for DASH, requiring CDNs to cache two copies of the same content. Law also helped shape Low-Latency HLS (LL-HLS) and the Akamai Low-Latency CMAF pattern, which together pushed end-to-end live streaming latency from 30+ seconds down to 2–4 seconds." + 'Co-led the Common Media Application Format (CMAF, 2016) effort to unify the segment formats used by HLS and DASH β€” for years both used MPEG-2 Transport Streams for HLS and fragmented MP4 for DASH, requiring CDNs to cache two copies of the same content. Law also helped shape Low-Latency HLS (LL-HLS) and the Akamai Low-Latency CMAF pattern, which together pushed end-to-end live streaming latency from 30+ seconds down to 2–4 seconds.' } ] }, @@ -47,49 +47,49 @@ export const streamingDeliveryStory: SubcategoryStory = { year: 1995, title: 'RealAudio Ships', description: - "RealNetworks ships RealAudio with the first widely-deployed Internet streaming protocol. Proprietary, complex, hugely successful for music streaming in the late 1990s." + 'RealNetworks ships RealAudio with the first widely-deployed Internet streaming protocol. Proprietary, complex, hugely successful for music streaming in the late 1990s.' }, { year: 2002, - title: 'Adobe Buys Macromedia\'s Flash', + title: "Adobe Buys Macromedia's Flash", description: - "Adobe inherits Flash Media Server and the RTMP protocol. Flash becomes the default video stack on the web for the next decade." + 'Adobe inherits Flash Media Server and the RTMP protocol. Flash becomes the default video stack on the web for the next decade.' }, { year: 2005, title: 'YouTube Launches on Flash', description: - "YouTube ships using Adobe Flash + [[rtmp|RTMP]]/HTTP progressive download. Becomes the largest video site on the Internet." + 'YouTube ships using Adobe Flash + [[rtmp|RTMP]]/HTTP progressive download. Becomes the largest video site on the Internet.' }, { year: 2007, title: 'iPhone Ships Without Flash', description: - "Apple\'s iPhone launches without Flash. The clock starts on web video\'s migration away from Flash." + "Apple's iPhone launches without Flash. The clock starts on web video's migration away from Flash." }, { year: 2009, title: 'HLS Spec Drafts at IETF', description: - "Apple publishes the first [[hls|HLS]] internet-drafts. The original spec is short: an .m3u8 manifest pointing to .ts segment files served from any HTTP origin." + 'Apple publishes the first [[hls|HLS]] internet-drafts. The original spec is short: an .m3u8 manifest pointing to .ts segment files served from any HTTP origin.' }, { year: 2010, - title: 'Steve Jobs Publishes \"Thoughts on Flash\"', + title: 'Steve Jobs Publishes "Thoughts on Flash"', description: - "Jobs\' April 2010 open letter explicitly states the iPad will never support Flash. Within 18 months, every major video site is shipping an HTML5 + HLS or DASH path alongside Flash." + "Jobs' April 2010 open letter explicitly states the iPad will never support Flash. Within 18 months, every major video site is shipping an HTML5 + HLS or DASH path alongside Flash." }, { year: 2012, title: 'MPEG-DASH Standardized', description: - 'ISO/IEC 23009-1 publishes [[dash|MPEG-DASH]]. Codec-agnostic, royalty-free, designed by committee β€” the standards-body answer to Apple\'s vendor-controlled HLS.' + "ISO/IEC 23009-1 publishes [[dash|MPEG-DASH]]. Codec-agnostic, royalty-free, designed by committee β€” the standards-body answer to Apple's vendor-controlled HLS." }, { year: 2015, title: 'YouTube Defaults to DASH', description: - "YouTube migrates its primary player from Flash + RTMP to HTML5 + DASH. Netflix, Hulu, BBC iPlayer follow with DASH (or HLS) shortly after." + 'YouTube migrates its primary player from Flash + RTMP to HTML5 + DASH. Netflix, Hulu, BBC iPlayer follow with DASH (or HLS) shortly after.' }, { year: 2016, @@ -101,19 +101,19 @@ export const streamingDeliveryStory: SubcategoryStory = { year: 2017, title: 'Flash Officially Discontinued', description: - "Adobe announces Flash end-of-life by 2020. The last consumer browser version is removed from Chrome in late 2020." + 'Adobe announces Flash end-of-life by 2020. The last consumer browser version is removed from Chrome in late 2020.' }, { year: 2019, title: 'Low-Latency HLS (LL-HLS) and CMAF-LL', description: - "Apple publishes Low-Latency HLS; CMAF Low-Latency follows. Achieve 2–4 second end-to-end live latency, competitive with the WebRTC alternatives β€” without giving up the CDN cacheability that makes streaming economical." + 'Apple publishes Low-Latency HLS; CMAF Low-Latency follows. Achieve 2–4 second end-to-end live latency, competitive with the WebRTC alternatives β€” without giving up the CDN cacheability that makes streaming economical.' }, { year: 2023, title: 'Media over QUIC (MoQ) Working Group', description: - "IETF charters the MoQ WG to define the post-HLS/DASH future: streaming directly over [[quic|QUIC]] without segment files. Twitch and Meta are the largest sponsors." + 'IETF charters the MoQ WG to define the post-HLS/DASH future: streaming directly over [[quic|QUIC]] without segment files. Twitch and Meta are the largest sponsors.' } ] }, @@ -127,9 +127,9 @@ export const streamingDeliveryStory: SubcategoryStory = { values: [ 'Push (server pushes to player); also push (ingest)', 'TCP (long-lived)', - "FLV container, AAC/H.264", + 'FLV container, AAC/H.264', '1–5 seconds (low for the era)', - "Live ingest from streamer β†’ service (Twitch, YouTube Live, Facebook Live)" + 'Live ingest from streamer β†’ service (Twitch, YouTube Live, Facebook Live)' ] }, { @@ -137,9 +137,9 @@ export const streamingDeliveryStory: SubcategoryStory = { values: [ 'Pull (client fetches segments)', 'HTTP β€” fits behind any CDN', - ".m3u8 manifest + .ts or fMP4 segments", + '.m3u8 manifest + .ts or fMP4 segments', 'Standard: 15–30s; LL-HLS: 2–4s', - "All Apple platforms; default for mobile and Smart TVs; CDN-cached delivery" + 'All Apple platforms; default for mobile and Smart TVs; CDN-cached delivery' ] }, { @@ -147,13 +147,13 @@ export const streamingDeliveryStory: SubcategoryStory = { values: [ 'Pull (client fetches segments)', 'HTTP β€” fits behind any CDN', - ".mpd manifest + fMP4 (or webm) segments", + '.mpd manifest + fMP4 (or webm) segments', 'Standard: 6–30s; CMAF-LL: 2–4s', - "YouTube, Netflix, most non-Apple platforms; codec-agnostic so it survives codec churn" + 'YouTube, Netflix, most non-Apple platforms; codec-agnostic so it survives codec churn' ] } ], - note: "Modern live streams typically use [[rtmp|RTMP]] for ingest and [[hls|HLS]] or [[dash|DASH]] for delivery. The CMAF unification means a single set of fMP4 segments can serve both HLS and DASH players." + note: 'Modern live streams typically use [[rtmp|RTMP]] for ingest and [[hls|HLS]] or [[dash|DASH]] for delivery. The CMAF unification means a single set of fMP4 segments can serve both HLS and DASH players.' }, { type: 'animated-sequence', @@ -182,11 +182,11 @@ export const streamingDeliveryStory: SubcategoryStory = { CDN-->>P: segment, back to high quality Note over CDN: All segments cached at CDN edge β€” most requests never hit origin`, caption: - "The adaptive bitrate ladder is the magic of HTTP-based streaming. Each segment is a separate HTTP request, the player picks the bitrate per segment, and the CDN caches every variant. A 4K stream with 5 bitrates costs 5Γ— the storage but ~1Γ— the origin bandwidth β€” almost all traffic is served from cache.", + 'The adaptive bitrate ladder is the magic of HTTP-based streaming. Each segment is a separate HTTP request, the player picks the bitrate per segment, and the CDN caches every variant. A 4K stream with 5 bitrates costs 5Γ— the storage but ~1Γ— the origin bandwidth β€” almost all traffic is served from cache.', steps: { 0: '**The setup.** The player will fetch many small segments (typically 2–10 seconds each) over HTTP from a CDN. Before it can do anything, it needs the *manifest* β€” the list of available bitrates and segment URLs.', 1: 'Player requests the **manifest** (.m3u8 for HLS, .mpd for DASH).', - 2: '**CDN cache miss** β€” it doesn\'t have the manifest yet, so it fetches from origin.', + 2: "**CDN cache miss** β€” it doesn't have the manifest yet, so it fetches from origin.", 3: 'Origin returns the manifest listing five bitrates: **240p, 480p, 720p, 1080p, 4K**.', 4: 'CDN forwards the manifest to the player and caches it. Future viewers get the manifest from cache.', 5: '**The player chooses a starting bitrate** β€” typically conservative (low) β€” and starts measuring how fast segments are arriving to inform its quality decisions.', @@ -207,17 +207,17 @@ export const streamingDeliveryStory: SubcategoryStory = { { type: 'callout', title: 'Why RTMP Refused to Die', - text: `[[rtmp|RTMP]] should have been dead by 2015. Browsers stopped supporting Flash. Mobile never supported it. Adobe stopped investing. Every major streaming platform migrated *playback* to HLS or DASH. And yet, in 2025, if you open OBS Studio and start a stream to Twitch, YouTube Live, Facebook Live, Kick, or essentially any live streaming platform, the protocol going from your encoder to the service is **RTMP**.\n\nWhy?\n\n- **Encoder support is universal.** Every camera, every hardware encoder (TriCaster, AJA, Blackmagic), every streaming software (OBS, vMix, Wirecast, Streamlabs) supports RTMP. No replacement has matched that.\n- **It just works.** RTMP\'s push-over-TCP model is simple. A streamer types in a server URL and a stream key; the encoder connects and starts sending. No handshake complexity, no segmentation logic, no manifest publishing.\n- **The replacements are worse for this leg.** WebRTC requires complex signaling. SRT (Secure Reliable Transport) is gaining adoption but isn\'t in every encoder. Newer protocols (RIST, Zixi, WHIP) exist but the ecosystem is fragmented.\n- **It\'s ingest, not delivery.** The economic pressure to replace it is low β€” only the streamer-to-service hop uses RTMP. Everything past the ingest server is HLS/DASH/CMAF.\n\nThe migration *will* happen β€” WHIP (WebRTC-HTTP Ingestion Protocol) is the leading candidate, with YouTube and others adding support β€” but it has been "next year" for several years. RTMP is the cockroach of streaming protocols, and it\'s genuinely fine.` + text: `[[rtmp|RTMP]] should have been dead by 2015. Browsers stopped supporting Flash. Mobile never supported it. Adobe stopped investing. Every major streaming platform migrated *playback* to HLS or DASH. And yet, in 2025, if you open OBS Studio and start a stream to Twitch, YouTube Live, Facebook Live, Kick, or essentially any live streaming platform, the protocol going from your encoder to the service is **RTMP**.\n\nWhy?\n\n- **Encoder support is universal.** Every camera, every hardware encoder (TriCaster, AJA, Blackmagic), every streaming software (OBS, vMix, Wirecast, Streamlabs) supports RTMP. No replacement has matched that.\n- **It just works.** RTMP's push-over-TCP model is simple. A streamer types in a server URL and a stream key; the encoder connects and starts sending. No handshake complexity, no segmentation logic, no manifest publishing.\n- **The replacements are worse for this leg.** WebRTC requires complex signaling. SRT (Secure Reliable Transport) is gaining adoption but isn't in every encoder. Newer protocols (RIST, Zixi, WHIP) exist but the ecosystem is fragmented.\n- **It's ingest, not delivery.** The economic pressure to replace it is low β€” only the streamer-to-service hop uses RTMP. Everything past the ingest server is HLS/DASH/CMAF.\n\nThe migration *will* happen β€” WHIP (WebRTC-HTTP Ingestion Protocol) is the leading candidate, with YouTube and others adding support β€” but it has been "next year" for several years. RTMP is the cockroach of streaming protocols, and it's genuinely fine.` }, { type: 'narrative', title: 'The Failure Modes', - text: `[[hls|HLS]] and [[dash|DASH]]\'s failure mode is **latency**. Standard HLS/DASH live streaming has 15–30 seconds of end-to-end delay β€” segments must be encoded, written, fetched, buffered before playback. For VOD and most casual live streaming, this is fine. For interactive use cases (live auctions, sports betting, sports broadcasts where social media spoils the result), it\'s a dealbreaker. LL-HLS and CMAF-LL cut this to 2–4 seconds, but require CDN support, careful tuning, and HTTP/2 chunked transfer encoding. Many CDNs handle low-latency poorly.\n\n[[rtmp|RTMP]]\'s failure mode is **firewall traversal**. RTMP runs on TCP port 1935 by default; many corporate firewalls block it. RTMPS (TLS-wrapped on port 443) helps but isn\'t universally supported by streaming services. Streamers in restrictive networks often have to manually configure RTMPT (tunneled over HTTP), which adds latency and isn\'t supported everywhere.\n\nAll three share a deeper failure mode: **codec churn**. The container formats (TS, fMP4) are stable, but codecs (H.264 β†’ H.265 β†’ AV1 β†’ VVC) keep evolving. Each generation cuts bandwidth ~30%, which is huge at YouTube\'s scale. But device support lags by years β€” H.265 still isn\'t supported in Chrome on Android, AV1 hardware decode is still spotty, VVC isn\'t deployed yet. Streamers must transcode to multiple codecs and serve the right one to each device.` + text: `[[hls|HLS]] and [[dash|DASH]]'s failure mode is **latency**. Standard HLS/DASH live streaming has 15–30 seconds of end-to-end delay β€” segments must be encoded, written, fetched, buffered before playback. For VOD and most casual live streaming, this is fine. For interactive use cases (live auctions, sports betting, sports broadcasts where social media spoils the result), it's a dealbreaker. LL-HLS and CMAF-LL cut this to 2–4 seconds, but require CDN support, careful tuning, and HTTP/2 chunked transfer encoding. Many CDNs handle low-latency poorly.\n\n[[rtmp|RTMP]]'s failure mode is **firewall traversal**. RTMP runs on TCP port 1935 by default; many corporate firewalls block it. RTMPS (TLS-wrapped on port 443) helps but isn't universally supported by streaming services. Streamers in restrictive networks often have to manually configure RTMPT (tunneled over HTTP), which adds latency and isn't supported everywhere.\n\nAll three share a deeper failure mode: **codec churn**. The container formats (TS, fMP4) are stable, but codecs (H.264 β†’ H.265 β†’ AV1 β†’ VVC) keep evolving. Each generation cuts bandwidth ~30%, which is huge at YouTube's scale. But device support lags by years β€” H.265 still isn't supported in Chrome on Android, AV1 hardware decode is still spotty, VVC isn't deployed yet. Streamers must transcode to multiple codecs and serve the right one to each device.` }, { type: 'narrative', - title: 'What\'s Next', - text: `Active work in 2025:\n\n- **Media over QUIC (MoQ)** β€” IETF working group developing the post-HLS/DASH future. Direct streaming over QUIC streams instead of segment files. Sub-second latency potential, but the segment-based + CDN-cacheable model is hard to beat economically.\n- **WHIP / WHEP for WebRTC ingest** β€” WebRTC HTTP Ingestion Protocol (WHIP, RFC 9725) and Egress Protocol (WHEP) are the WebRTC-based path to replace RTMP ingest. Twitch, OBS, YouTube all have partial support.\n- **AV1 rollout** β€” YouTube and Netflix are pushing AV1 hard. ~30% bandwidth savings vs H.264 at equivalent quality. Hardware decode support is catching up (Apple A17, Snapdragon 8 Gen 3, Intel Arc).\n- **Low-latency CMAF and LL-HLS** are converging in practice β€” Apple\'s LL-HLS uses CMAF segments, the format wars are over.\n- **Live commerce and live auctions** are the new "must be <2 seconds" use cases driving low-latency investment. WebRTC is winning the under-1-second tier; LL-HLS/CMAF-LL the 2–4 second tier; standard HLS/DASH the 15–30 second tier (which is fine for most actual viewing).\n- **The boring truth**: 95% of streaming in 2025 is still standard HLS or DASH segments served from a CDN. The architectural breakthroughs (RTMP, segment-based adaptive, CMAF) are mostly already in production. The frontier is the long tail β€” latency, codec efficiency, ingest modernization.` + title: "What's Next", + text: `Active work in 2025:\n\n- **Media over QUIC (MoQ)** β€” IETF working group developing the post-HLS/DASH future. Direct streaming over QUIC streams instead of segment files. Sub-second latency potential, but the segment-based + CDN-cacheable model is hard to beat economically.\n- **WHIP / WHEP for WebRTC ingest** β€” WebRTC HTTP Ingestion Protocol (WHIP, RFC 9725) and Egress Protocol (WHEP) are the WebRTC-based path to replace RTMP ingest. Twitch, OBS, YouTube all have partial support.\n- **AV1 rollout** β€” YouTube and Netflix are pushing AV1 hard. ~30% bandwidth savings vs H.264 at equivalent quality. Hardware decode support is catching up (Apple A17, Snapdragon 8 Gen 3, Intel Arc).\n- **Low-latency CMAF and LL-HLS** are converging in practice β€” Apple's LL-HLS uses CMAF segments, the format wars are over.\n- **Live commerce and live auctions** are the new "must be <2 seconds" use cases driving low-latency investment. WebRTC is winning the under-1-second tier; LL-HLS/CMAF-LL the 2–4 second tier; standard HLS/DASH the 15–30 second tier (which is fine for most actual viewing).\n- **The boring truth**: 95% of streaming in 2025 is still standard HLS or DASH segments served from a CDN. The architectural breakthroughs (RTMP, segment-based adaptive, CMAF) are mostly already in production. The frontier is the long tail β€” latency, codec efficiency, ingest modernization.` } ] }; diff --git a/src/lib/data/subcategory-stories/types.ts b/src/lib/data/subcategory-stories/types.ts index 9634e6a..cb57f01 100644 --- a/src/lib/data/subcategory-stories/types.ts +++ b/src/lib/data/subcategory-stories/types.ts @@ -3,16 +3,10 @@ * structure is identical (narrative, timeline, pioneers, callout, diagram, * image). Only the parent id differs. */ -export type { - Pioneer, - TimelineEntry, - StorySection -} from '../category-stories/types'; +export type { Pioneer, TimelineEntry, StorySection } from '../category-stories/types'; -import type { StorySection } from '../category-stories/types'; +import type { StoryContent } from '../category-stories/types'; -export interface SubcategoryStory { +export interface SubcategoryStory extends StoryContent { subcategoryId: string; - tagline: string; - sections: StorySection[]; } diff --git a/src/lib/data/subcategory-stories/wlan-wan.ts b/src/lib/data/subcategory-stories/wlan-wan.ts index eff8ed4..c800853 100644 --- a/src/lib/data/subcategory-stories/wlan-wan.ts +++ b/src/lib/data/subcategory-stories/wlan-wan.ts @@ -3,12 +3,12 @@ import type { SubcategoryStory } from './types'; export const wlanWanStory: SubcategoryStory = { subcategoryId: 'wlan-wan', tagline: - "General-purpose wireless at two scales β€” unlicensed Wi-Fi for hundreds of meters, licensed cellular for hundreds of kilometers", + 'General-purpose wireless at two scales β€” unlicensed Wi-Fi for hundreds of meters, licensed cellular for hundreds of kilometers', sections: [ { type: 'narrative', title: 'Two Approaches, Two Spectrum Models', - text: `Most wireless networking on the planet runs on one of two technology families. Both push bits through the air. They differ on almost everything else.\n\n**[[wifi|Wi-Fi]]** (the IEEE 802.11 family, 1997–) runs in **unlicensed spectrum** β€” frequency bands (2.4 GHz, 5 GHz, 6 GHz) that anyone can use without buying the rights. The deal: keep your power below a regulated limit, share the medium with your neighbors, accept interference. Hundreds of meters of range, gigabits per second on the latest standards, no per-device cost, no carrier in the loop. Wi-Fi is *your network*.\n\n**[[cellular|Cellular]]** (GSM through 5G NR) runs in **licensed spectrum** β€” bands that carriers paid governments billions for at auction. The carrier controls the spectrum, the towers, the subscriber identity (SIM), and the billing. Kilometers of range, gigabits per second on the latest standards, expensive per-device, carrier in the loop. Cellular is *the carrier\'s network*.\n\nThe two have converged technically. Both use OFDM(A) modulation. Both have MIMO. Both have started using millimeter-wave spectrum for short-range high-bandwidth. Wi-Fi 6E and 5G NR have similar peak speeds. They\'ve diverged operationally. Wi-Fi is essentially free and best-effort; cellular is paid and policy-managed. Your phone uses both, switching seamlessly via {{ttls|EAP-TTLS}} / Passpoint or simple SSID joins; the only thing that differs is who you owe money to.\n\nThis is the broadcast-range family β€” protocols that move bits *as the primary radio link*, as opposed to short-range PAN protocols (Bluetooth, NFC, Zigbee) that exist for specific device-to-device interaction. WLAN and WAN, side by side, are how almost every Internet-connected device gets its bits today.` + text: `Most wireless networking on the planet runs on one of two technology families. Both push bits through the air. They differ on almost everything else.\n\n**[[wifi|Wi-Fi]]** (the IEEE 802.11 family, 1997–) runs in **unlicensed spectrum** β€” frequency bands (2.4 GHz, 5 GHz, 6 GHz) that anyone can use without buying the rights. The deal: keep your power below a regulated limit, share the medium with your neighbors, accept interference. Hundreds of meters of range, gigabits per second on the latest standards, no per-device cost, no carrier in the loop. Wi-Fi is *your network*.\n\n**[[cellular|Cellular]]** (GSM through 5G NR) runs in **licensed spectrum** β€” bands that carriers paid governments billions for at auction. The carrier controls the spectrum, the towers, the subscriber identity (SIM), and the billing. Kilometers of range, gigabits per second on the latest standards, expensive per-device, carrier in the loop. Cellular is *the carrier's network*.\n\nThe two have converged technically. Both use OFDM(A) modulation. Both have MIMO. Both have started using millimeter-wave spectrum for short-range high-bandwidth. Wi-Fi 6E and 5G NR have similar peak speeds. They've diverged operationally. Wi-Fi is essentially free and best-effort; cellular is paid and policy-managed. Your phone uses both, switching seamlessly via {{ttls|EAP-TTLS}} / Passpoint or simple SSID joins; the only thing that differs is who you owe money to.\n\nThis is the broadcast-range family β€” protocols that move bits *as the primary radio link*, as opposed to short-range PAN protocols (Bluetooth, NFC, Zigbee) that exist for specific device-to-device interaction. WLAN and WAN, side by side, are how almost every Internet-connected device gets its bits today.` }, { type: 'pioneers', @@ -18,7 +18,7 @@ export const wlanWanStory: SubcategoryStory = { id: 'marty-cooper', name: 'Marty Cooper', years: '1928–', - title: '\"Father of the Cell Phone\"', + title: '"Father of the Cell Phone"', org: 'Motorola', contribution: "Led the team at Motorola that built the first handheld cellular phone in 1973 β€” the DynaTAC prototype, the 2.5-pound brick Cooper used to make the first cellular phone call in April 1973. The call was to Cooper\\'s rival Joel Engel at Bell Labs, just to say \"I\\'m calling you from a real handheld cellular phone.\" It would be ten more years before commercial cellular service launched (1G AMPS in Chicago, 1983), but the architecture β€” cells, frequency reuse, handover β€” was Cooper\\'s vision." @@ -30,15 +30,15 @@ export const wlanWanStory: SubcategoryStory = { title: 'Inventor of the Viterbi Algorithm / Co-founder of Qualcomm', org: 'UCSD / Qualcomm', contribution: - "Invented the Viterbi algorithm (1967) β€” the optimal decoder for convolutional codes that underpins essentially every wireless modem since. Co-founded Qualcomm (1985), which bet on CDMA for cellular against the entrenched TDMA standard (GSM). CDMA won the US 2G/3G battle; the underlying spread-spectrum mathematics also drove modern OFDMA and 5G NR. The Viterbi School of Engineering at USC is named for him." + 'Invented the Viterbi algorithm (1967) β€” the optimal decoder for convolutional codes that underpins essentially every wireless modem since. Co-founded Qualcomm (1985), which bet on CDMA for cellular against the entrenched TDMA standard (GSM). CDMA won the US 2G/3G battle; the underlying spread-spectrum mathematics also drove modern OFDMA and 5G NR. The Viterbi School of Engineering at USC is named for him.' }, { name: 'Vic Hayes', years: '–', - title: '\"Father of Wi-Fi\"', + title: '"Father of Wi-Fi"', org: 'NCR / Lucent / IEEE 802.11', contribution: - 'Chaired the IEEE 802.11 working group from its founding in 1990 through 2000 β€” the decade when Wi-Fi went from a proposal to a global standard. Hayes\' particular contribution was shepherding the consensus between vendors with incompatible early designs (NCR\'s WaveLAN, others\') into a single standard that everyone could implement. Without that coordination, Wi-Fi would have fragmented like the early cellular world did.' + "Chaired the IEEE 802.11 working group from its founding in 1990 through 2000 β€” the decade when Wi-Fi went from a proposal to a global standard. Hayes' particular contribution was shepherding the consensus between vendors with incompatible early designs (NCR's WaveLAN, others') into a single standard that everyone could implement. Without that coordination, Wi-Fi would have fragmented like the early cellular world did." }, { id: 'erik-dahlman', @@ -58,85 +58,85 @@ export const wlanWanStory: SubcategoryStory = { year: 1973, title: 'First Cellular Phone Call', description: - "[[pioneer:marty-cooper|Cooper]] at Motorola makes the first handheld cellular phone call from a Manhattan street to Bell Labs\' Joel Engel." + "[[pioneer:marty-cooper|Cooper]] at Motorola makes the first handheld cellular phone call from a Manhattan street to Bell Labs' Joel Engel." }, { year: 1983, title: 'First Commercial Cellular (1G AMPS)', description: - "Ameritech launches Advanced Mobile Phone System in Chicago. Analog voice; FM modulation; massive cell towers." + 'Ameritech launches Advanced Mobile Phone System in Chicago. Analog voice; FM modulation; massive cell towers.' }, { year: 1991, title: '2G GSM Launches', description: - "Digital cellular ships in Finland. GSM standardized in Europe; CDMA-based IS-95 in the US. The split between TDMA-based GSM and CDMA-based US carriers defines a decade of incompatibility." + 'Digital cellular ships in Finland. GSM standardized in Europe; CDMA-based IS-95 in the US. The split between TDMA-based GSM and CDMA-based US carriers defines a decade of incompatibility.' }, { year: 1997, title: 'IEEE 802.11 Published', description: - "The original [[wifi|Wi-Fi]] standard β€” 1 Mbps and 2 Mbps in 2.4 GHz. Initially marketed as \"WaveLAN.\" The Wi-Fi Alliance forms a couple years later to brand the certified-interop version." + 'The original [[wifi|Wi-Fi]] standard β€” 1 Mbps and 2 Mbps in 2.4 GHz. Initially marketed as "WaveLAN." The Wi-Fi Alliance forms a couple years later to brand the certified-interop version.' }, { year: 1999, title: '802.11b β€” Wi-Fi Takes Off', description: - "11 Mbps in 2.4 GHz. Apple ships AirPort base stations and AirPort cards (rebadged Lucent WaveLAN). [[wifi|Wi-Fi]] starts appearing in laptops by default. CafΓ©s and airports become the first public Wi-Fi locations." + '11 Mbps in 2.4 GHz. Apple ships AirPort base stations and AirPort cards (rebadged Lucent WaveLAN). [[wifi|Wi-Fi]] starts appearing in laptops by default. CafΓ©s and airports become the first public Wi-Fi locations.' }, { year: 2001, title: '3G Launches in Japan (NTT DoCoMo)', description: - "DoCoMo\'s FOMA network launches the first commercial 3G. Data rates of hundreds of Kbps make mobile internet plausible for the first time." + "DoCoMo's FOMA network launches the first commercial 3G. Data rates of hundreds of Kbps make mobile internet plausible for the first time." }, { year: 2003, title: '802.11g β€” 54 Mbps', description: - "54 Mbps in 2.4 GHz. The version that mainstreams Wi-Fi in homes and offices. WPA replaces the badly-broken WEP for encryption." + '54 Mbps in 2.4 GHz. The version that mainstreams Wi-Fi in homes and offices. WPA replaces the badly-broken WEP for encryption.' }, { year: 2009, title: '802.11n / Wi-Fi 4 β€” MIMO', description: - "Multiple antennas; up to 600 Mbps theoretical. The first Wi-Fi version that\'s plausibly competitive with wired Ethernet." + "Multiple antennas; up to 600 Mbps theoretical. The first Wi-Fi version that's plausibly competitive with wired Ethernet." }, { year: 2009, title: '4G LTE Launches', description: - "TeliaSonera deploys the first commercial LTE network in Stockholm and Oslo. Verizon launches LTE in the US in 2010. Smartphones and high-bandwidth mobile internet take off." + 'TeliaSonera deploys the first commercial LTE network in Stockholm and Oslo. Verizon launches LTE in the US in 2010. Smartphones and high-bandwidth mobile internet take off.' }, { year: 2013, title: '802.11ac / Wi-Fi 5 β€” Gigabit', description: - "Gigabit speeds in 5 GHz. The version that finally made \"wireless = fast\" universal in consumer perception." + 'Gigabit speeds in 5 GHz. The version that finally made "wireless = fast" universal in consumer perception.' }, { year: 2019, title: '5G NR Launches', description: - "Commercial 5G launches in South Korea, the US, and China. Two flavors: sub-6 GHz (longer range, similar to LTE+) and mmWave (very fast, very short range)." + 'Commercial 5G launches in South Korea, the US, and China. Two flavors: sub-6 GHz (longer range, similar to LTE+) and mmWave (very fast, very short range).' }, { year: 2019, title: '802.11ax / Wi-Fi 6 β€” OFDMA', description: - "OFDMA borrowed from LTE arrives in Wi-Fi. Better performance with many simultaneous devices, which matters far more in real-world deployments than peak speed." + 'OFDMA borrowed from LTE arrives in Wi-Fi. Better performance with many simultaneous devices, which matters far more in real-world deployments than peak speed.' }, { year: 2020, title: 'Wi-Fi 6E β€” 6 GHz Spectrum', description: - "Regulators (FCC, Ofcom, EU) open the 6 GHz band for unlicensed use. 1200 MHz of new spectrum; effectively triples Wi-Fi capacity. Wi-Fi 6E devices ship in 2021." + 'Regulators (FCC, Ofcom, EU) open the 6 GHz band for unlicensed use. 1200 MHz of new spectrum; effectively triples Wi-Fi capacity. Wi-Fi 6E devices ship in 2021.' }, { year: 2024, title: '802.11be / Wi-Fi 7', description: - "320 MHz channel width in 6 GHz, 4096-QAM, multi-link operation (use 2.4 and 5 and 6 GHz simultaneously). Theoretical peak ~46 Gbps." + '320 MHz channel width in 6 GHz, 4096-QAM, multi-link operation (use 2.4 and 5 and 6 GHz simultaneously). Theoretical peak ~46 Gbps.' } ] }, @@ -151,8 +151,8 @@ export const wlanWanStory: SubcategoryStory = { 'Unlicensed (2.4 / 5 / 6 GHz)', 'Tens to hundreds of meters per AP', 'CapEx only (buy the AP); no per-user fees', - "Stationary or walking β€” handover between APs is OS-handled and lossy", - "Indoor β€” homes, offices, public hotspots, IoT inside buildings" + 'Stationary or walking β€” handover between APs is OS-handled and lossy', + 'Indoor β€” homes, offices, public hotspots, IoT inside buildings' ] }, { @@ -160,13 +160,13 @@ export const wlanWanStory: SubcategoryStory = { values: [ 'Licensed (various bands per region, billions paid at auction)', 'Kilometers per tower; mmWave only meters', - 'OpEx (per-month SIM); CapEx is the carrier\'s problem', - "Designed for fast handover at vehicle speeds β€” works on bullet trains", - "Outdoor and mobile β€” phones, vehicles, fixed-wireless backhaul" + "OpEx (per-month SIM); CapEx is the carrier's problem", + 'Designed for fast handover at vehicle speeds β€” works on bullet trains', + 'Outdoor and mobile β€” phones, vehicles, fixed-wireless backhaul' ] } ], - note: "These aren\'t competitors so much as complements. A modern smartphone uses both β€” Wi-Fi at home (cheaper, faster indoor), cellular outside (covers everywhere). Most phone OSes (iOS, Android) hand off transparently between them via Apple\'s Wi-Fi Calling and similar." + note: "These aren't competitors so much as complements. A modern smartphone uses both β€” Wi-Fi at home (cheaper, faster indoor), cellular outside (covers everywhere). Most phone OSes (iOS, Android) hand off transparently between them via Apple's Wi-Fi Calling and similar." }, { type: 'animated-sequence', @@ -207,7 +207,7 @@ export const wlanWanStory: SubcategoryStory = { 8: '**Association Response: Success.** The AP allocates state for this client and tells it the association ID it will use.', 9: '**Phase 3 β€” The 4-Way Handshake.** Both sides already know the **Pairwise Master Key** (derived from the Wi-Fi password for WPA2-PSK, from the RADIUS exchange for WPA2-Enterprise). What they need now are *fresh* session keys.', 10: '**Message 1.** The AP picks a random {{nonce|nonce}} (ANonce) and sends it. No encryption yet β€” but the nonce alone is harmless.', - 11: '**The client derives the Pairwise Transient Key** by combining the PMK, its own SNonce, the AP\'s ANonce, and both MAC addresses. The PTK is the actual encryption + integrity key for this session.', + 11: "**The client derives the Pairwise Transient Key** by combining the PMK, its own SNonce, the AP's ANonce, and both MAC addresses. The PTK is the actual encryption + integrity key for this session.", 12: '**Message 2.** The client sends its SNonce so the AP can derive the same PTK, plus a Message Integrity Code computed with the new key β€” proving the client really has the right password.', 13: '**The AP derives the PTK** with the now-known SNonce and verifies the MIC. A wrong password fails here; this is what makes the password "leak-free" β€” it never travels over the air.', 14: '**Message 3.** The AP confirms key installation and ships the **Group Temporal Key** (used for broadcast/multicast frames), encrypted with the new PTK.', @@ -219,18 +219,18 @@ export const wlanWanStory: SubcategoryStory = { }, { type: 'callout', - title: 'Why Cellular and Wi-Fi Don\'t Merge', - text: `For thirty years, people have predicted that Wi-Fi and cellular would converge into a single wireless standard. They haven\'t. The reasons are economic, not technical.\n\n**Spectrum economics are completely different.** Carriers spent ~\$700 billion globally on spectrum licenses over 20 years. They built tower networks on top of that investment. They have to charge for access to recoup it. Wi-Fi spectrum is free. The two pricing models are incompatible: there is no good way to monetize spectrum that is *also* free for anyone to use.\n\n**Coverage area economics differ.** Wi-Fi makes sense indoors (where signals don\'t travel far and adding APs is cheap). Cellular makes sense outdoors and at vehicle speeds (where tower-scale infrastructure is the only way). Trying to use Wi-Fi outdoors hits propagation limits; trying to use cellular indoors hits coverage gaps and signal absorption.\n\n**Regulatory frameworks differ.** Cellular spectrum is per-operator; Wi-Fi spectrum is shared. The "carrier" model assumes a single accountable operator per spectrum band; the "unlicensed" model assumes everyone competes politely. Bringing them together would either monopolize the unlicensed spectrum or fragment the licensed.\n\n**Practical convergence happens at the application layer.** Your iPhone seamlessly switches between Wi-Fi and 5G based on signal quality; Wi-Fi Calling uses Wi-Fi for cellular calls; Passpoint lets your SIM identity authenticate you to Wi-Fi networks. The user experience is unified; the underlying spectrum and economics are not.\n\nThe most interesting recent convergence is **private 5G** β€” companies (factories, ports, stadiums) buy small slices of cellular-style spectrum (CBRS in the US) and run their own 5G networks. Same air interface as commercial cellular; same convenience as Wi-Fi; sits in between. It\'s growing fast but is still a small fraction of either market.` + title: "Why Cellular and Wi-Fi Don't Merge", + text: `For thirty years, people have predicted that Wi-Fi and cellular would converge into a single wireless standard. They haven't. The reasons are economic, not technical.\n\n**Spectrum economics are completely different.** Carriers spent ~$700 billion globally on spectrum licenses over 20 years. They built tower networks on top of that investment. They have to charge for access to recoup it. Wi-Fi spectrum is free. The two pricing models are incompatible: there is no good way to monetize spectrum that is *also* free for anyone to use.\n\n**Coverage area economics differ.** Wi-Fi makes sense indoors (where signals don't travel far and adding APs is cheap). Cellular makes sense outdoors and at vehicle speeds (where tower-scale infrastructure is the only way). Trying to use Wi-Fi outdoors hits propagation limits; trying to use cellular indoors hits coverage gaps and signal absorption.\n\n**Regulatory frameworks differ.** Cellular spectrum is per-operator; Wi-Fi spectrum is shared. The "carrier" model assumes a single accountable operator per spectrum band; the "unlicensed" model assumes everyone competes politely. Bringing them together would either monopolize the unlicensed spectrum or fragment the licensed.\n\n**Practical convergence happens at the application layer.** Your iPhone seamlessly switches between Wi-Fi and 5G based on signal quality; Wi-Fi Calling uses Wi-Fi for cellular calls; Passpoint lets your SIM identity authenticate you to Wi-Fi networks. The user experience is unified; the underlying spectrum and economics are not.\n\nThe most interesting recent convergence is **private 5G** β€” companies (factories, ports, stadiums) buy small slices of cellular-style spectrum (CBRS in the US) and run their own 5G networks. Same air interface as commercial cellular; same convenience as Wi-Fi; sits in between. It's growing fast but is still a small fraction of either market.` }, { type: 'narrative', title: 'The Failure Modes', - text: `[[wifi|Wi-Fi]]\'s failure mode is **the crowded channel**. Wi-Fi spectrum is shared. A coffee shop with 50 users on Wi-Fi has 50 devices competing for the same radio channel; throughput per user collapses. Hardware mitigations (band steering, multi-AP roaming, OFDMA in Wi-Fi 6) help but don\'t eliminate the contention. The other failure mode is **deauth attacks** β€” anyone can send a deauthentication frame to anyone on the network (the management frames were unencrypted in pre-802.11w spec) and force them off. WPA3 fixes this; deployment is uneven.\n\n[[cellular|Cellular]]\'s failure mode is **the dead zone**. Coverage isn\'t universal; mmWave 5G works for a few hundred meters before falling back to sub-6 GHz. Indoor cellular is often poor β€” building materials block the signal. The carrier-side fix (femtocells, micro/pico cells, distributed antenna systems) requires significant infrastructure investment. The user-side fix (Wi-Fi calling) hands the problem back to Wi-Fi.\n\nBoth share a third failure mode: **the upgrade cycle**. Wi-Fi has had ~7 major standards in 25 years (b/g/n/ac/ax/6E/be). Cellular has had 5 generations (1G–5G). Each generation requires new hardware on both ends β€” new APs *and* new client cards. The "router lifespan" in 2025 is effectively the Wi-Fi standard lifespan, ~5–8 years. Cellular operators amortize this over their tower infrastructure; consumers feel it every time they buy a new phone or router.` + text: `[[wifi|Wi-Fi]]'s failure mode is **the crowded channel**. Wi-Fi spectrum is shared. A coffee shop with 50 users on Wi-Fi has 50 devices competing for the same radio channel; throughput per user collapses. Hardware mitigations (band steering, multi-AP roaming, OFDMA in Wi-Fi 6) help but don't eliminate the contention. The other failure mode is **deauth attacks** β€” anyone can send a deauthentication frame to anyone on the network (the management frames were unencrypted in pre-802.11w spec) and force them off. WPA3 fixes this; deployment is uneven.\n\n[[cellular|Cellular]]'s failure mode is **the dead zone**. Coverage isn't universal; mmWave 5G works for a few hundred meters before falling back to sub-6 GHz. Indoor cellular is often poor β€” building materials block the signal. The carrier-side fix (femtocells, micro/pico cells, distributed antenna systems) requires significant infrastructure investment. The user-side fix (Wi-Fi calling) hands the problem back to Wi-Fi.\n\nBoth share a third failure mode: **the upgrade cycle**. Wi-Fi has had ~7 major standards in 25 years (b/g/n/ac/ax/6E/be). Cellular has had 5 generations (1G–5G). Each generation requires new hardware on both ends β€” new APs *and* new client cards. The "router lifespan" in 2025 is effectively the Wi-Fi standard lifespan, ~5–8 years. Cellular operators amortize this over their tower infrastructure; consumers feel it every time they buy a new phone or router.` }, { type: 'narrative', - title: 'What\'s Next', - text: `Active work in 2025:\n\n- **Wi-Fi 7** (802.11be) is shipping in flagship devices. Multi-Link Operation lets a device use 2.4 + 5 + 6 GHz simultaneously, dramatically improving roaming and throughput. Reality lags the spec; few APs and clients support all features yet.\n- **6G research** has begun. ITU-R is targeting 2030 for commercial launch. Frequencies will include sub-terahertz; expect 100+ Gbps peak speeds but very short range.\n- **CBRS / private 5G** continues growing for industrial use cases. Factories, ports, mines, stadiums deploying their own 5G is now mainstream rather than experimental.\n- **OpenRAN** β€” disaggregating cellular base-station hardware from software β€” slowly moving from political will to commercial deployment. Dish Network in the US is the largest OpenRAN deployment; Rakuten in Japan was first.\n- **Satellite + cellular convergence** β€” Apple\'s Emergency SOS, Starlink Direct-to-Cell, AST SpaceMobile all let standard cell phones talk to satellites for SMS and (soon) data in areas with no tower coverage. The boundary between WAN cellular and LEO satellite is dissolving.\n- **Spectrum management automation** β€” Wi-Fi 6E and 7 in 6 GHz require AFC (Automated Frequency Coordination) to avoid interfering with existing fixed-service users. AFC databases shipped in 2024; standard-power 6 GHz Wi-Fi is finally deployable.\n- **The boring truth**: Wi-Fi and cellular will keep getting faster, eat each other\'s lunch at the edges, and never merge into one technology. The dual-stack will persist.` + title: "What's Next", + text: `Active work in 2025:\n\n- **Wi-Fi 7** (802.11be) is shipping in flagship devices. Multi-Link Operation lets a device use 2.4 + 5 + 6 GHz simultaneously, dramatically improving roaming and throughput. Reality lags the spec; few APs and clients support all features yet.\n- **6G research** has begun. ITU-R is targeting 2030 for commercial launch. Frequencies will include sub-terahertz; expect 100+ Gbps peak speeds but very short range.\n- **CBRS / private 5G** continues growing for industrial use cases. Factories, ports, mines, stadiums deploying their own 5G is now mainstream rather than experimental.\n- **OpenRAN** β€” disaggregating cellular base-station hardware from software β€” slowly moving from political will to commercial deployment. Dish Network in the US is the largest OpenRAN deployment; Rakuten in Japan was first.\n- **Satellite + cellular convergence** β€” Apple's Emergency SOS, Starlink Direct-to-Cell, AST SpaceMobile all let standard cell phones talk to satellites for SMS and (soon) data in areas with no tower coverage. The boundary between WAN cellular and LEO satellite is dissolving.\n- **Spectrum management automation** β€” Wi-Fi 6E and 7 in 6 GHz require AFC (Automated Frequency Coordination) to avoid interfering with existing fixed-service users. AFC databases shipped in 2024; standard-power 6 GHz Wi-Fi is finally deployable.\n- **The boring truth**: Wi-Fi and cellular will keep getting faster, eat each other's lunch at the edges, and never merge into one technology. The dual-stack will persist.` } ] }; diff --git a/src/lib/engine/canvas-renderer.ts b/src/lib/engine/canvas-renderer.ts index 9837875..4d2f77f 100644 --- a/src/lib/engine/canvas-renderer.ts +++ b/src/lib/engine/canvas-renderer.ts @@ -1,5 +1,11 @@ import type { GraphNode, GraphEdge, Viewport } from '$lib/data/types'; -import { hexToRgba, themedColor, themedDomColor, shiftHsl, type ThemeColors } from '$lib/utils/colors'; +import { + hexToRgba, + themedColor, + themedDomColor, + shiftHsl, + type ThemeColors +} from '$lib/utils/colors'; import { getProtocolById } from '$lib/data/index'; import { categoryMap, categories } from '$lib/data/categories'; import { subcategoryMap } from '$lib/data/subcategories'; @@ -71,7 +77,14 @@ function updateJourneyIds(journey: Journey | null | undefined): void { } } -function isNodeDimmed(node: GraphNode, selectedNode: GraphNode | null, compareTargetId?: string | null, activeJourney?: Journey | null, searchHighlightIds?: Set<string> | null, hoveredNode?: GraphNode | null): boolean { +function isNodeDimmed( + node: GraphNode, + selectedNode: GraphNode | null, + compareTargetId?: string | null, + activeJourney?: Journey | null, + searchHighlightIds?: Set<string> | null, + hoveredNode?: GraphNode | null +): boolean { // Hover overrides every dimming mode β€” when the user hovers an inline // protocol link in prose, the target node must light up regardless of // the current selection / journey / comparison context. @@ -135,8 +148,24 @@ function isNodeDimmed(node: GraphNode, selectedNode: GraphNode | null, compareTa let currentTheme: ThemeColors; export function render(ctx: CanvasRenderingContext2D, options: RenderOptions): void { - const { width, height, viewport, nodes, edges, hoveredNode, selectedNode, compareTargetId, activeJourney, activeJourneyStepIndex, searchHighlightIds, time, dpr, layoutMode, theme, birthScales } = - options; + const { + width, + height, + viewport, + nodes, + edges, + hoveredNode, + selectedNode, + compareTargetId, + activeJourney, + activeJourneyStepIndex, + searchHighlightIds, + time, + dpr, + layoutMode, + theme, + birthScales + } = options; const getBirth = (id: string): number => birthScales?.get(id) ?? 1; @@ -213,7 +242,16 @@ export function render(ctx: CanvasRenderingContext2D, options: RenderOptions): v // Update dim animations (smooth fade in/out) for (const node of nodes) { - const targetDim = isNodeDimmed(node, selectedNode, compareTargetId, activeJourney, searchHighlightIds, hoveredNode) ? 1 : 0; + const targetDim = isNodeDimmed( + node, + selectedNode, + compareTargetId, + activeJourney, + searchHighlightIds, + hoveredNode + ) + ? 1 + : 0; const current = dimAnim.get(node.id) ?? 0; const speed = targetDim > current ? DIM_EASE_IN : DIM_EASE_OUT; const next = current + (targetDim - current) * speed; @@ -244,7 +282,19 @@ export function render(ctx: CanvasRenderingContext2D, options: RenderOptions): v const isConnected = connectedIds.has(node.id); const birthT = getBirth(node.id); if (birthT <= 0.001) continue; - drawNode(ctx, node, hoverT, isSelected, dimT, isConnected, time, viewport.scale, theme, layoutMode, birthT); + drawNode( + ctx, + node, + hoverT, + isSelected, + dimT, + isConnected, + time, + viewport.scale, + theme, + layoutMode, + birthT + ); } ctx.restore(); @@ -292,8 +342,11 @@ function drawRelatedEdges( ctx.moveTo(liveNode.x, liveNode.y); ctx.quadraticCurveTo(cpx, cpy, targetNode.x, targetNode.y); const isLight = !tc.showStars; - ctx.strokeStyle = hexToRgba(nodeColor, compareTargetId ? (isLight ? 0.6 : 0.4) : (isLight ? 0.5 : 0.25)); - ctx.lineWidth = compareTargetId ? 1.5 : (isLight ? 1.4 : 1.0); + ctx.strokeStyle = hexToRgba( + nodeColor, + compareTargetId ? (isLight ? 0.6 : 0.4) : isLight ? 0.5 : 0.25 + ); + ctx.lineWidth = compareTargetId ? 1.5 : isLight ? 1.4 : 1.0; ctx.stroke(); } @@ -382,9 +435,8 @@ function drawJourneyPath( ctx.font = `600 ${9 * pulseScale}px Inter, system-ui, sans-serif`; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; - ctx.fillStyle = isCurrent || isVisited - ? (tc.showStars ? '#000000' : '#FFFFFF') - : hexToRgba(jColor, 0.8); + ctx.fillStyle = + isCurrent || isVisited ? (tc.showStars ? '#000000' : '#FFFFFF') : hexToRgba(jColor, 0.8); ctx.fillText(String(i + 1), badgeX, badgeY + 0.5); } @@ -495,7 +547,6 @@ function drawTimelineUnderlay(ctx: CanvasRenderingContext2D, theme: ThemeColors) ctx.restore(); } - // Seeded star field β€” generated once, reused every frame let starCache: { x: number; y: number; r: number; a: number }[] | null = null; let starCacheKey = ''; @@ -754,8 +805,7 @@ function drawNode( const glowScale = 1 + 0.3 * eased; // glow grows out with hover const glowRadius = r * 2.2 * glowScale; const glow = ctx.createRadialGradient(x, y, r * 0.5, x, y, glowRadius); - const baseGlowAlpha = - isSelected ? 0.35 : isConnected ? 0.2 : type === 'hub' ? 0.08 : 0.1; + const baseGlowAlpha = isSelected ? 0.35 : isConnected ? 0.2 : type === 'hub' ? 0.08 : 0.1; const glowAlpha = (baseGlowAlpha + 0.25 * eased) * glowVisibility; glow.addColorStop(0, hexToRgba(color, glowAlpha)); glow.addColorStop(1, hexToRgba(color, 0)); @@ -782,7 +832,7 @@ function drawNode( // Extract the rgb and replace alpha with (1 - dimT) const match = baseBg.match(/rgba?\(([^)]+)\)/); if (match) { - const parts = match[1].split(',').map(s => s.trim()); + const parts = match[1].split(',').map((s) => s.trim()); ctx.fillStyle = `rgba(${parts[0]}, ${parts[1]}, ${parts[2]}, ${1 - dimT})`; } else { ctx.fillStyle = baseBg; @@ -798,7 +848,7 @@ function drawNode( gradient.addColorStop(0, hexToRgba(theme.hub, alpha)); const endMatch = theme.hubGradientEnd.match(/rgba?\(([^)]+)\)/); if (endMatch) { - const parts = endMatch[1].split(',').map(s => s.trim()); + const parts = endMatch[1].split(',').map((s) => s.trim()); gradient.addColorStop(1, `rgba(${parts[0]}, ${parts[1]}, ${parts[2]}, ${alpha * 0.8})`); } else { gradient.addColorStop(1, hexToRgba(theme.hub, alpha * 0.8)); @@ -825,7 +875,10 @@ function drawNode( const highlight = ctx.createRadialGradient(x - r * 0.25, y - r * 0.3, 0, x, y, r); const hlAlpha = 1 - dimT; const hubHighlight = theme.showStars ? 0.4 : 0.15; // subtler in light mode - highlight.addColorStop(0, `rgba(255, 255, 255, ${(type === 'hub' ? hubHighlight : theme.innerHighlightAlpha) * hlAlpha})`); + highlight.addColorStop( + 0, + `rgba(255, 255, 255, ${(type === 'hub' ? hubHighlight : theme.innerHighlightAlpha) * hlAlpha})` + ); highlight.addColorStop(0.5, 'rgba(255, 255, 255, 0)'); highlight.addColorStop(1, 'rgba(255, 255, 255, 0)'); ctx.beginPath(); @@ -860,8 +913,10 @@ function drawNode( // Label β€” show for non-dimmed nodes and connected nodes if (dimT < 0.95 || isConnected) { - const fontSize = type === 'hub' ? 11 : type === 'category' ? 10 : type === 'subcategory' ? 9.5 : 9; - const showLabel = scale > 0.5 || type === 'hub' || type === 'category' || type === 'subcategory'; + const fontSize = + type === 'hub' ? 11 : type === 'category' ? 10 : type === 'subcategory' ? 9.5 : 9; + const showLabel = + scale > 0.5 || type === 'hub' || type === 'category' || type === 'subcategory'; const showAbbrev = scale <= 0.5 && scale > 0.3 && type === 'protocol'; if (showLabel || showAbbrev || isConnected) { @@ -880,12 +935,9 @@ function drawNode( ctx.font = `${type === 'hub' ? '600' : '500'} ${fontSize}px Inter, system-ui, sans-serif`; // In light mode, use muted DOM colors for labels so they're readable on the light bg - const labelColor = type === 'hub' - ? theme.hub - : theme.showStars - ? color - : themedDomColor(node.color, 'light'); - ctx.fillStyle = hexToRgba(labelColor, type === 'hub' ? labelAlpha : labelAlpha * 0.9); + const labelColor = + type === 'hub' ? theme.hub : theme.showStars ? color : themedDomColor(node.color, 'light'); + ctx.fillStyle = hexToRgba(labelColor, type === 'hub' ? labelAlpha : labelAlpha * 0.9); // Text shadow ctx.shadowColor = theme.labelShadowColor; @@ -978,11 +1030,17 @@ function drawAsyncIotIcon(ctx: CanvasRenderingContext2D): void { } function drawRealtimeAvIcon(ctx: CanvasRenderingContext2D): void { - ctx.stroke(new Path2D('M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z')); + ctx.stroke( + new Path2D('M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z') + ); } function drawUtilitiesIcon(ctx: CanvasRenderingContext2D): void { - ctx.stroke(new Path2D('M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z')); + ctx.stroke( + new Path2D( + 'M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z' + ) + ); ctx.stroke(new Path2D('M9 12l2 2 4-4')); } diff --git a/src/lib/engine/layouts.ts b/src/lib/engine/layouts.ts index 248ce6a..f99a095 100644 --- a/src/lib/engine/layouts.ts +++ b/src/lib/engine/layouts.ts @@ -10,14 +10,12 @@ import { type SimulationLinkDatum } from 'd3-force'; import type { GraphNode } from '$lib/data/types'; -import { allProtocols, categories, subcategories } from '$lib/data/index'; +import { allProtocols, categories } from '$lib/data/index'; export type LayoutMode = 'force' | 'radial' | 'timeline' | 'mesh'; // ─── Radial ──────────────────────────────────────────────────────────────── -export function computeRadialPositions( - nodes: GraphNode[] -): Map<string, { x: number; y: number }> { +export function computeRadialPositions(nodes: GraphNode[]): Map<string, { x: number; y: number }> { const pos = new Map<string, { x: number; y: number }>(); const hub = nodes.find((n) => n.type === 'hub'); @@ -85,9 +83,7 @@ export function computeRadialPositions( // Fallback for protocols without a subcategory: spread them across // the category sector at the protocol radius (preserves old behavior). - const orphans = protoNodes.filter( - (p) => p.categoryId === cat.id && !p.subcategoryId - ); + const orphans = protoNodes.filter((p) => p.categoryId === cat.id && !p.subcategoryId); orphans.forEach((proto, j) => { const t = (j + 0.5) / orphans.length; const protoAngle = catAngle - catSectorSpan / 2 + t * catSectorSpan; @@ -192,11 +188,9 @@ interface MeshNode extends SimulationNodeDatum { type: 'protocol' | 'subcategory'; categoryId: string; } -interface MeshLink extends SimulationLinkDatum<MeshNode> {} +type MeshLink = SimulationLinkDatum<MeshNode>; -export function computeMeshPositions( - nodes: GraphNode[] -): Map<string, { x: number; y: number }> { +export function computeMeshPositions(nodes: GraphNode[]): Map<string, { x: number; y: number }> { const pos = new Map<string, { x: number; y: number }>(); const protoNodes = nodes.filter((n) => n.type === 'protocol'); const subNodes = nodes.filter((n) => n.type === 'subcategory'); diff --git a/src/lib/engine/simulation.test.ts b/src/lib/engine/simulation.test.ts new file mode 100644 index 0000000..6ddac0e --- /dev/null +++ b/src/lib/engine/simulation.test.ts @@ -0,0 +1,44 @@ +import { describe, it, expect } from 'vitest'; +import type { Simulation } from 'd3-force'; +import { syncPositions, type SimNode } from './simulation'; +import type { GraphNode } from '$lib/data/types'; + +/** Minimal GraphNode for position-sync tests (only id/x/y/vx/vy are touched). */ +function gnode(id: string): GraphNode { + return { id, x: 0, y: 0, vx: 0, vy: 0 } as GraphNode; +} + +function snode(id: string, x: number, y: number): SimNode { + return { id, type: 'protocol', radius: 10, x, y, vx: 1, vy: 2 }; +} + +/** Stub d3 simulation exposing only the .nodes() syncPositions reads. */ +function fakeSim(simNodes: SimNode[]): Simulation<SimNode, never> { + return { nodes: () => simNodes } as unknown as Simulation<SimNode, never>; +} + +describe('syncPositions', () => { + it('copies positions onto the matching graph node by id, regardless of order', () => { + const simNodes = [snode('a', 10, 11), snode('b', 20, 21), snode('c', 30, 31)]; + // Graph nodes in a DIFFERENT order than the sim's internal array. + const graphNodes = [gnode('c'), gnode('a'), gnode('b')]; + + syncPositions(fakeSim(simNodes), graphNodes); + + const byId = new Map(graphNodes.map((n) => [n.id, n])); + expect(byId.get('a')).toMatchObject({ x: 10, y: 11 }); + expect(byId.get('b')).toMatchObject({ x: 20, y: 21 }); + expect(byId.get('c')).toMatchObject({ x: 30, y: 31 }); + }); + + it('leaves a graph node untouched when the sim has no node with its id', () => { + const simNodes = [snode('a', 5, 6)]; + const graphNodes = [gnode('a'), gnode('orphan')]; + + syncPositions(fakeSim(simNodes), graphNodes); + + expect(graphNodes[0]).toMatchObject({ x: 5, y: 6 }); + // orphan keeps its defaults β€” no stray sim node bleeds into it. + expect(graphNodes[1]).toMatchObject({ x: 0, y: 0 }); + }); +}); diff --git a/src/lib/engine/simulation.ts b/src/lib/engine/simulation.ts index 79ce280..a6c8d2f 100644 --- a/src/lib/engine/simulation.ts +++ b/src/lib/engine/simulation.ts @@ -224,15 +224,19 @@ export function warmUpSimulation(simulation: Simulation<SimNode, SimLink>, ticks } export function syncPositions(simulation: Simulation<SimNode, SimLink>, nodes: GraphNode[]): void { - const simNodes = simulation.nodes(); - for (let i = 0; i < simNodes.length; i++) { - const sn = simNodes[i]; - const gn = nodes[i]; - if (gn && sn) { - gn.x = sn.x ?? 0; - gn.y = sn.y ?? 0; - gn.vx = sn.vx ?? 0; - gn.vy = sn.vy ?? 0; - } + // Match by id, not array index. d3-force keeps its node array in creation + // order so index alignment usually holds, but it breaks silently the moment + // a caller passes a reordered or resized `nodes` array β€” desyncing every + // position. Keying on id is robust and barely more expensive. + const byId = new Map<string, SimNode>(); + for (const sn of simulation.nodes()) byId.set(sn.id, sn); + + for (const gn of nodes) { + const sn = byId.get(gn.id); + if (!sn) continue; + gn.x = sn.x ?? 0; + gn.y = sn.y ?? 0; + gn.vx = sn.vx ?? 0; + gn.vy = sn.vy ?? 0; } } diff --git a/src/lib/search/SearchBar.svelte b/src/lib/search/SearchBar.svelte index 6e1bf9e..e5bfb8f 100644 --- a/src/lib/search/SearchBar.svelte +++ b/src/lib/search/SearchBar.svelte @@ -19,8 +19,6 @@ type SearchResultType } from './search-index'; import { getAppState } from '$lib/state/context'; - import { buildGraphNodes } from '$lib/data/index'; - import { journeys } from '$lib/data/journeys'; import { themedDomColor } from '$lib/utils/colors'; import { navigateToProtocol, @@ -35,7 +33,6 @@ } from '$lib/utils/navigation'; const appState = getAppState(); - const allNodes = buildGraphNodes(); /** Theme-aware color for search result items */ function dc(c: string | undefined): string { diff --git a/src/lib/search/search-index.ts b/src/lib/search/search-index.ts index 822cdd0..d618205 100644 --- a/src/lib/search/search-index.ts +++ b/src/lib/search/search-index.ts @@ -222,7 +222,8 @@ for (const p of pioneers) { type: 'pioneer', label: p.name, description: p.title ?? p.org ?? '', - searchText: `${p.name} ${p.title ?? ''} ${p.org ?? ''} ${stripAtoms(p.contribution)} ${protoNames}`.toLowerCase(), + searchText: + `${p.name} ${p.title ?? ''} ${p.org ?? ''} ${stripAtoms(p.contribution)} ${protoNames}`.toLowerCase(), protocolIds: p.protocols ?? [], nav: { kind: 'pioneer', pioneerId: p.id } }); @@ -253,7 +254,8 @@ for (const o of outages) { type: 'outage', label: o.title, description: cleanOneLiner, - searchText: `outage incident ${o.title} ${cleanOneLiner} ${o.date} ${stripAtoms(o.setup)} ${stripAtoms(o.mistake)} ${stripAtoms(o.lesson)}`.toLowerCase(), + searchText: + `outage incident ${o.title} ${cleanOneLiner} ${o.date} ${stripAtoms(o.setup)} ${stripAtoms(o.mistake)} ${stripAtoms(o.lesson)}`.toLowerCase(), protocolIds: o.affectedProtocols, nav: { kind: 'outage', outageId: o.id } }); @@ -266,7 +268,8 @@ for (const f of frontierEntries) { type: 'frontier', label: f.title, description: cleanOneLiner, - searchText: `frontier ${f.title} ${cleanOneLiner} ${stripAtoms(f.description)} ${f.topic} ${f.status}`.toLowerCase(), + searchText: + `frontier ${f.title} ${cleanOneLiner} ${stripAtoms(f.description)} ${f.topic} ${f.status}`.toLowerCase(), protocolIds: f.protocols, nav: { kind: 'frontier', frontierId: f.id } }); diff --git a/src/lib/simulator/components/ActorStage.svelte b/src/lib/simulator/components/ActorStage.svelte index 2eb31b4..22a188c 100644 --- a/src/lib/simulator/components/ActorStage.svelte +++ b/src/lib/simulator/components/ActorStage.svelte @@ -7,7 +7,6 @@ interface Props { actors: SimulationActor[]; currentStep: SimulationStep | null; - stepIndex: number; color: string; compact?: boolean; } @@ -20,9 +19,7 @@ const fromIdx = $derived( currentStep ? actors.findIndex((a) => a.id === currentStep.fromActor) : -1 ); - const toIdx = $derived( - currentStep ? actors.findIndex((a) => a.id === currentStep.toActor) : -1 - ); + const toIdx = $derived(currentStep ? actors.findIndex((a) => a.id === currentStep.toActor) : -1); function isActiveActor(idx: number): boolean { return idx === fromIdx || idx === toIdx; @@ -74,11 +71,7 @@ {#each actors as actor, idx (actor.id)} {@const active = isActiveActor(idx)} <div class="actor" class:active> - <span - class="actor-label" - class:text-t-primary={active} - class:text-t-muted={!active} - > + <span class="actor-label" class:text-t-primary={active} class:text-t-muted={!active}> {actor.label} </span> <div @@ -223,7 +216,9 @@ border-radius: 50%; border: 1px solid var(--theme-glass-border); background: var(--theme-tooltip-bg); - transition: border-color 0.25s ease, box-shadow 0.25s ease; + transition: + border-color 0.25s ease, + box-shadow 0.25s ease; flex-shrink: 0; } .actor-stage.compact .actor-icon-wrap { diff --git a/src/lib/simulator/components/PacketInspector.svelte b/src/lib/simulator/components/PacketInspector.svelte index 910f6f6..1524e1a 100644 --- a/src/lib/simulator/components/PacketInspector.svelte +++ b/src/lib/simulator/components/PacketInspector.svelte @@ -11,7 +11,13 @@ compact?: boolean; } - let { layers, activeLayerIndex = -1, direction = 'encapsulate', highlightFields = [], compact = false }: Props = $props(); + let { + layers, + activeLayerIndex = -1, + direction = 'encapsulate', + highlightFields = [], + compact = false + }: Props = $props(); const appState = getAppState(); /** Theme-aware layer color */ @@ -19,7 +25,15 @@ return themedDomColor(rawColor, appState.theme); } - let hoveredField: { layerIdx: number; fieldIdx: number; layerColor: string; name: string; value: string; bits: number; description: string } | null = $state(null); + let hoveredField: { + layerIdx: number; + fieldIdx: number; + layerColor: string; + name: string; + value: string; + bits: number; + description: string; + } | null = $state(null); let mouseX = $state(0); let mouseY = $state(0); let tooltipEl: HTMLDivElement | undefined = $state(); @@ -55,7 +69,13 @@ return String(value); } - function onFieldEnter(e: MouseEvent, li: number, fi: number, layer: ProtocolLayer, field: ProtocolLayer['headerFields'][0]) { + function onFieldEnter( + e: MouseEvent, + li: number, + fi: number, + layer: ProtocolLayer, + field: ProtocolLayer['headerFields'][0] + ) { mouseX = e.clientX; mouseY = e.clientY; hoveredField = { @@ -97,109 +117,141 @@ {#each layers as layer (layer.abbreviation)} <span class="inline-flex items-center gap-1 rounded-md px-1.5 py-0.5 text-[9px] font-bold tracking-wider uppercase" - style="background-color: {lc(layer.color)}15; color: {lc(layer.color)}; border: 1px solid {lc(layer.color)}30;" + style="background-color: {lc(layer.color)}15; color: {lc( + layer.color + )}; border: 1px solid {lc(layer.color)}30;" > - <span - class="h-1.5 w-1.5 rounded-full" - style="background-color: {lc(layer.color)};" - ></span> + <span class="h-1.5 w-1.5 rounded-full" style="background-color: {lc(layer.color)};"></span> {layer.abbreviation} </span> {/each} </div> {:else} -<div class="flex flex-col gap-1"> - <h4 class="text-xs font-semibold tracking-wider text-t-muted uppercase"> - Encapsulation - </h4> - - <div class="relative rounded-lg border border-s-border bg-s-glass p-3"> - {#each displayLayers as layer, li (layer.abbreviation)} - <!-- Encapsulation connector between layers --> - {#if li > 0} - <div class="flex items-center gap-2 py-2.5"> - <div class="h-px flex-1" style="background: linear-gradient(to right, transparent, {lc(layer.color)}30);"></div> - <div - class="flex items-center gap-1.5 rounded-full border px-2.5 py-0.5 text-[10px]" - style="border-color: {lc(layer.color)}30; background-color: {lc(layer.color)}0a; color: var(--theme-text-secondary);" - > - <!-- Nested-layers icon (encapsulation) --> - <svg class="h-3 w-3 shrink-0" viewBox="0 0 16 16" fill="none"> - <rect x="3" y="3" width="6.5" height="4" rx="0.8" stroke={lc(layer.color)} stroke-width="1.2" opacity="0.7" /> - <rect x="1.5" y="7" width="13" height="6" rx="0.8" stroke={lc(layer.color)} stroke-width="1.2" /> - </svg> - <span>wrapped in <span style="color: {lc(layer.color)}" class="font-semibold">{layer.abbreviation}</span></span> + <div class="flex flex-col gap-1"> + <h4 class="text-xs font-semibold tracking-wider text-t-muted uppercase">Encapsulation</h4> + + <div class="relative rounded-lg border border-s-border bg-s-glass p-3"> + {#each displayLayers as layer, li (layer.abbreviation)} + <!-- Encapsulation connector between layers --> + {#if li > 0} + <div class="flex items-center gap-2 py-2.5"> + <div + class="h-px flex-1" + style="background: linear-gradient(to right, transparent, {lc(layer.color)}30);" + ></div> + <div + class="flex items-center gap-1.5 rounded-full border px-2.5 py-0.5 text-[10px]" + style="border-color: {lc(layer.color)}30; background-color: {lc( + layer.color + )}0a; color: var(--theme-text-secondary);" + > + <!-- Nested-layers icon (encapsulation) --> + <svg class="h-3 w-3 shrink-0" viewBox="0 0 16 16" fill="none"> + <rect + x="3" + y="3" + width="6.5" + height="4" + rx="0.8" + stroke={lc(layer.color)} + stroke-width="1.2" + opacity="0.7" + /> + <rect + x="1.5" + y="7" + width="13" + height="6" + rx="0.8" + stroke={lc(layer.color)} + stroke-width="1.2" + /> + </svg> + <span + >wrapped in <span style="color: {lc(layer.color)}" class="font-semibold" + >{layer.abbreviation}</span + ></span + > + </div> + <div + class="h-px flex-1" + style="background: linear-gradient(to left, transparent, {lc(layer.color)}30);" + ></div> </div> - <div class="h-px flex-1" style="background: linear-gradient(to left, transparent, {lc(layer.color)}30);"></div> - </div> - {/if} + {/if} - <!-- Layer card --> - <div - class="overflow-hidden rounded-lg transition-all duration-300" - style=" + <!-- Layer card --> + <div + class="overflow-hidden rounded-lg transition-all duration-300" + style=" border: 1px solid {lc(layer.color)}25; background-color: {lc(layer.color)}05; " - > - <!-- Layer header --> - <div - class="flex items-center gap-2 px-3 py-1.5" - style="background-color: {lc(layer.color)}0a; border-bottom: 1px solid {lc(layer.color)}15;" > + <!-- Layer header --> <div - class="h-2 w-2 rounded-full shrink-0" - style="background-color: {lc(layer.color)}; box-shadow: 0 0 6px {lc(layer.color)}60;" - ></div> - <span class="text-[11px] font-bold tracking-wider uppercase" style="color: {lc(layer.color)}"> - {layer.abbreviation} - </span> - <span class="text-[10px] text-t-muted"> - Layer {layer.osiLayer} β€” {layer.name} - </span> - </div> - - <!-- Header fields --> - <div class="grid gap-1 p-2" style="grid-template-columns: repeat(auto-fill, minmax(68px, 1fr));"> - {#each layer.headerFields as field, fi (field.name)} - {@const highlighted = isHighlighted(field.name)} - {@const isFullRow = field.bits === 0} + class="flex items-center gap-2 px-3 py-1.5" + style="background-color: {lc(layer.color)}0a; border-bottom: 1px solid {lc( + layer.color + )}15;" + > <div - class="flex min-w-0 flex-col overflow-hidden rounded-md px-2 py-1 transition-all cursor-help" - style=" + class="h-2 w-2 shrink-0 rounded-full" + style="background-color: {lc(layer.color)}; box-shadow: 0 0 6px {lc(layer.color)}60;" + ></div> + <span + class="text-[11px] font-bold tracking-wider uppercase" + style="color: {lc(layer.color)}" + > + {layer.abbreviation} + </span> + <span class="text-[10px] text-t-muted"> + Layer {layer.osiLayer} β€” {layer.name} + </span> + </div> + + <!-- Header fields --> + <div + class="grid gap-1 p-2" + style="grid-template-columns: repeat(auto-fill, minmax(68px, 1fr));" + > + {#each layer.headerFields as field, fi (field.name)} + {@const highlighted = isHighlighted(field.name)} + {@const isFullRow = field.bits === 0} + <div + class="flex min-w-0 cursor-help flex-col overflow-hidden rounded-md px-2 py-1 transition-all" + style=" background-color: {highlighted ? lc(layer.color) + '18' : 'var(--theme-glass-bg)'}; border: 1px solid {highlighted ? lc(layer.color) + '40' : 'var(--theme-glass-border)'}; grid-column: {isFullRow ? '1 / -1' : 'span 1'}; " - onmouseenter={(e) => onFieldEnter(e, li, fi, layer, field)} - onmousemove={onFieldMove} - onmouseleave={onFieldLeave} - role="presentation" - > - <span class="text-[8px] leading-tight text-t-muted">{field.name}</span> - <span - class="truncate text-[11px] font-mono font-medium" - style="color: {highlighted ? lc(layer.color) : 'var(--theme-text-primary)'}" - title={formatValue(field.value)} + onmouseenter={(e) => onFieldEnter(e, li, fi, layer, field)} + onmousemove={onFieldMove} + onmouseleave={onFieldLeave} + role="presentation" > - {formatValue(field.value)} - </span> - {#if field.bits > 0} - <span class="text-[7px] text-t-muted">{field.bits}b</span> - {/if} - </div> - {/each} + <span class="text-[8px] leading-tight text-t-muted">{field.name}</span> + <span + class="truncate font-mono text-[11px] font-medium" + style="color: {highlighted ? lc(layer.color) : 'var(--theme-text-primary)'}" + title={formatValue(field.value)} + > + {formatValue(field.value)} + </span> + {#if field.bits > 0} + <span class="text-[7px] text-t-muted">{field.bits}b</span> + {/if} + </div> + {/each} + </div> </div> - </div> - {/each} + {/each} - {#if displayLayers.length === 0} - <div class="py-6 text-center text-xs text-t-muted"> - Press Play to begin encapsulation - </div> - {/if} + {#if displayLayers.length === 0} + <div class="py-6 text-center text-xs text-t-muted">Press Play to begin encapsulation</div> + {/if} + </div> </div> -</div> {/if} <!-- Tooltip portaled to document.body via $effect --> @@ -218,14 +270,20 @@ > {#if hoveredField} <div class="flex items-center gap-2"> - <span class="text-xs font-semibold" style="color: {hoveredField.layerColor}">{hoveredField.name}</span> + <span class="text-xs font-semibold" style="color: {hoveredField.layerColor}" + >{hoveredField.name}</span + > {#if hoveredField.bits > 0} - <span class="rounded bg-s-glass px-1.5 py-0.5 text-[10px] text-t-secondary">{hoveredField.bits} bits</span> + <span class="rounded bg-s-glass px-1.5 py-0.5 text-[10px] text-t-secondary" + >{hoveredField.bits} bits</span + > {/if} </div> <p class="mt-1 text-xs leading-relaxed text-t-primary">{hoveredField.description}</p> <p class="mt-1 text-[10px] text-t-muted"> - Value: <span class="font-mono" style="color: {hoveredField.layerColor}">{hoveredField.value}</span> + Value: <span class="font-mono" style="color: {hoveredField.layerColor}" + >{hoveredField.value}</span + > </p> {/if} </div> diff --git a/src/lib/simulator/components/PlaybackControls.svelte b/src/lib/simulator/components/PlaybackControls.svelte index 0e75c68..1c25443 100644 --- a/src/lib/simulator/components/PlaybackControls.svelte +++ b/src/lib/simulator/components/PlaybackControls.svelte @@ -82,7 +82,7 @@ {/if} <!-- Step indicator --> - <span class="shrink-0 text-[10px] tabular-nums text-t-muted"> + <span class="shrink-0 text-[10px] text-t-muted tabular-nums"> {#if state.currentStep >= 0} {state.currentStep + 1}/{state.totalSteps} {:else if state.status === 'complete'} diff --git a/src/lib/simulator/components/SimulationInputs.svelte b/src/lib/simulator/components/SimulationInputs.svelte index db0ce4f..6df488a 100644 --- a/src/lib/simulator/components/SimulationInputs.svelte +++ b/src/lib/simulator/components/SimulationInputs.svelte @@ -13,16 +13,14 @@ {#if inputs.length > 0} <div class="flex flex-col gap-2"> - <h4 class="text-xs font-semibold tracking-wider text-t-muted uppercase"> - Configuration - </h4> + <h4 class="text-xs font-semibold tracking-wider text-t-muted uppercase">Configuration</h4> <div class="grid gap-2" style="grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));"> {#each inputs as input (input.id)} <label class="flex flex-col gap-1"> <span class="text-[10px] font-medium text-t-secondary">{input.label}</span> {#if input.type === 'select' && input.options} <select - class="rounded-md border border-s-border bg-s-glass px-2 py-1.5 text-xs text-t-primary outline-none transition-colors focus:border-opacity-50" + class="focus:border-opacity-50 rounded-md border border-s-border bg-s-glass px-2 py-1.5 text-xs text-t-primary transition-colors outline-none" style="focus:border-color: {color}" value={state.userValues[input.id] ?? input.defaultValue} onchange={(e) => state.setUserValue(input.id, (e.target as HTMLSelectElement).value)} @@ -34,7 +32,7 @@ {:else} <input type={input.type} - class="rounded-md border border-s-border bg-s-glass px-2 py-1.5 text-xs text-t-primary outline-none transition-colors focus:border-opacity-50" + class="focus:border-opacity-50 rounded-md border border-s-border bg-s-glass px-2 py-1.5 text-xs text-t-primary transition-colors outline-none" style="focus:border-color: {color}" placeholder={input.placeholder} value={state.userValues[input.id] ?? input.defaultValue} diff --git a/src/lib/simulator/components/SimulatorView.svelte b/src/lib/simulator/components/SimulatorView.svelte index 3a1288a..c10df47 100644 --- a/src/lib/simulator/components/SimulatorView.svelte +++ b/src/lib/simulator/components/SimulatorView.svelte @@ -1,4 +1,5 @@ <script lang="ts"> + import { untrack } from 'svelte'; import { SimulatorState } from '../state.svelte'; import { getSimulation } from '../simulations/index'; import StepTimeline from './StepTimeline.svelte'; @@ -15,9 +16,13 @@ let { protocolId, color }: Props = $props(); const simState = new SimulatorState(); - const config = getSimulation(protocolId); - // Load once at mount β€” parent uses {#key protocolId} to remount on change + // Resolve and load the simulation exactly once at mount. The parent wraps + // this component in {#key protocolId} so a protocol change fully remounts it + // β€” so reading protocolId once here is intentional. `untrack` documents that + // (and avoids loading sim state inside an effect, which Svelte flags as an + // unsafe mutation). + const config = untrack(() => getSimulation(protocolId)); if (config) simState.load(config); </script> @@ -49,15 +54,26 @@ class="flex h-16 w-16 items-center justify-center rounded-2xl" style="background-color: {color}10" > - <svg class="h-8 w-8" style="color: {color}" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.5"> - <path stroke-linecap="round" stroke-linejoin="round" d="M9.75 3.104v5.714a2.25 2.25 0 0 1-.659 1.591L5 14.5M9.75 3.104c-.251.023-.501.05-.75.082m.75-.082a24.301 24.301 0 0 1 4.5 0m0 0v5.714c0 .597.237 1.17.659 1.591L19.8 15.3M14.25 3.104c.251.023.501.05.75.082M19.8 15.3l-1.57.393A9.065 9.065 0 0 1 12 15a9.065 9.065 0 0 0-6.23.693L5 14.5m14.8.8 1.402 1.402c1.232 1.232.65 3.318-1.067 3.611A48.309 48.309 0 0 1 12 21c-2.773 0-5.491-.235-8.135-.687-1.718-.293-2.3-2.379-1.067-3.61L5 14.5" /> + <svg + class="h-8 w-8" + style="color: {color}" + fill="none" + stroke="currentColor" + viewBox="0 0 24 24" + stroke-width="1.5" + > + <path + stroke-linecap="round" + stroke-linejoin="round" + d="M9.75 3.104v5.714a2.25 2.25 0 0 1-.659 1.591L5 14.5M9.75 3.104c-.251.023-.501.05-.75.082m.75-.082a24.301 24.301 0 0 1 4.5 0m0 0v5.714c0 .597.237 1.17.659 1.591L19.8 15.3M14.25 3.104c.251.023.501.05.75.082M19.8 15.3l-1.57.393A9.065 9.065 0 0 1 12 15a9.065 9.065 0 0 0-6.23.693L5 14.5m14.8.8 1.402 1.402c1.232 1.232.65 3.318-1.067 3.611A48.309 48.309 0 0 1 12 21c-2.773 0-5.491-.235-8.135-.687-1.718-.293-2.3-2.379-1.067-3.61L5 14.5" + /> </svg> </div> <div> <p class="text-sm font-medium text-t-primary">Simulation Coming Soon</p> <p class="mt-1 text-xs text-t-muted"> - An interactive simulation for this protocol is being developed. - Switch to the Learn tab to explore its documentation. + An interactive simulation for this protocol is being developed. Switch to the Learn tab to + explore its documentation. </p> </div> </div> diff --git a/src/lib/simulator/components/StepTimeline.svelte b/src/lib/simulator/components/StepTimeline.svelte index 169ee0e..34c8ef9 100644 --- a/src/lib/simulator/components/StepTimeline.svelte +++ b/src/lib/simulator/components/StepTimeline.svelte @@ -39,9 +39,7 @@ </script> <section> - <h3 class="mb-3 text-xs font-semibold tracking-wider text-t-muted uppercase"> - Simulation Steps - </h3> + <h3 class="mb-3 text-xs font-semibold tracking-wider text-t-muted uppercase">Simulation Steps</h3> <div class="relative space-y-0"> {#each config.steps as step, i (step.id)} {@const stepState = stepStates[i]} @@ -73,7 +71,13 @@ aria-label="Go to step {i + 1}: {step.label}" > {#if isPast} - <svg class="h-3 w-3" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="3"> + <svg + class="h-3 w-3" + fill="none" + stroke="currentColor" + viewBox="0 0 24 24" + stroke-width="3" + > <path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" /> </svg> {:else} @@ -97,13 +101,7 @@ <div class="mt-3 space-y-3"> <div in:fly={{ y: 8, duration: 300, delay: 60 }}> - <ActorStage - actors={config.actors} - currentStep={step} - stepIndex={i} - {color} - compact={true} - /> + <ActorStage actors={config.actors} currentStep={step} {color} compact={true} /> </div> {#if step.layers && step.layers.length > 0} diff --git a/src/lib/simulator/components/actors/ActorIcon.svelte b/src/lib/simulator/components/actors/ActorIcon.svelte index 2b7e5e2..5d1abbb 100644 --- a/src/lib/simulator/components/actors/ActorIcon.svelte +++ b/src/lib/simulator/components/actors/ActorIcon.svelte @@ -10,7 +10,16 @@ let { icon, color = '#94a3b8', size = 32 }: Props = $props(); </script> -<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"> +<svg + width={size} + height={size} + viewBox="0 0 24 24" + fill="none" + stroke={color} + stroke-width="1.5" + stroke-linecap="round" + stroke-linejoin="round" +> {#if icon === 'client' || icon === 'browser'} <!-- Laptop --> <path d="M4 16V6a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v10" /> diff --git a/src/lib/simulator/components/actors/MessageArrow.svelte b/src/lib/simulator/components/actors/MessageArrow.svelte index 12dbf01..a899fd4 100644 --- a/src/lib/simulator/components/actors/MessageArrow.svelte +++ b/src/lib/simulator/components/actors/MessageArrow.svelte @@ -36,7 +36,8 @@ <!-- Arrowhead --> <polygon - points="{toX},{y} {toX - direction * arrowSize},{y - 3.5} {toX - direction * arrowSize},{y + 3.5}" + points="{toX},{y} {toX - direction * arrowSize},{y - 3.5} {toX - direction * arrowSize},{y + + 3.5}" fill={lineColor} /> diff --git a/src/lib/simulator/layers/amqp.ts b/src/lib/simulator/layers/amqp.ts index b4a7e4d..f36e2fa 100644 --- a/src/lib/simulator/layers/amqp.ts +++ b/src/lib/simulator/layers/amqp.ts @@ -14,40 +14,35 @@ export function createAMQPLayer( bits: 8, value: overrides?.frameType ?? 'Method (1)', editable: false, - description: - 'AMQP frame type β€” 1=Method, 2=Content Header, 3=Content Body, 8=Heartbeat' + description: 'AMQP frame type β€” 1=Method, 2=Content Header, 3=Content Body, 8=Heartbeat' }, { name: 'Channel', bits: 16, value: overrides?.channel ?? 0, editable: false, - description: - 'Channel number β€” 0 for connection-level, 1+ for application channels' + description: 'Channel number β€” 0 for connection-level, 1+ for application channels' }, { name: 'Class.Method', bits: 0, value: overrides?.method ?? 'Connection.Start', editable: false, - description: - 'AMQP class and method β€” Connection.Start, Channel.Open, Basic.Publish, etc.' + description: 'AMQP class and method β€” Connection.Start, Channel.Open, Basic.Publish, etc.' }, { name: 'Payload Size', bits: 32, value: overrides?.payloadSize ?? 128, editable: false, - description: - 'Size of the method arguments or content body in bytes' + description: 'Size of the method arguments or content body in bytes' }, { name: 'Properties', bits: 0, value: overrides?.properties ?? '', editable: false, - description: - 'Message properties β€” content-type, delivery-mode, correlation-id, headers' + description: 'Message properties β€” content-type, delivery-mode, correlation-id, headers' }, { name: 'Payload', diff --git a/src/lib/simulator/layers/arp.ts b/src/lib/simulator/layers/arp.ts index 127353a..9c9a362 100644 --- a/src/lib/simulator/layers/arp.ts +++ b/src/lib/simulator/layers/arp.ts @@ -64,8 +64,7 @@ export function createARPLayer( bits: 48, value: overrides?.targetMac ?? '00:00:00:00:00:00', editable: false, - description: - 'MAC address of the target β€” all zeros in requests (unknown)' + description: 'MAC address of the target β€” all zeros in requests (unknown)' }, { name: 'Target IP', diff --git a/src/lib/simulator/layers/bgp.ts b/src/lib/simulator/layers/bgp.ts index e7cc6ae..f50bb77 100644 --- a/src/lib/simulator/layers/bgp.ts +++ b/src/lib/simulator/layers/bgp.ts @@ -14,24 +14,21 @@ export function createBGPLayer( bits: 128, value: overrides?.marker ?? '0xFF…FF (all ones)', editable: false, - description: - 'Sync marker β€” 16 bytes of all 1s for authentication and synchronization' + description: 'Sync marker β€” 16 bytes of all 1s for authentication and synchronization' }, { name: 'Length', bits: 16, value: overrides?.length ?? 29, editable: false, - description: - 'Total message length in bytes (19–4096). Minimum 19 = header only (KEEPALIVE)' + description: 'Total message length in bytes (19–4096). Minimum 19 = header only (KEEPALIVE)' }, { name: 'Type', bits: 8, value: overrides?.type ?? 'OPEN (1)', editable: false, - description: - 'Message type β€” OPEN (1), UPDATE (2), NOTIFICATION (3), KEEPALIVE (4)', + description: 'Message type β€” OPEN (1), UPDATE (2), NOTIFICATION (3), KEEPALIVE (4)', color: '#DC2626' }, { @@ -39,8 +36,7 @@ export function createBGPLayer( bits: 16, value: overrides?.asNumber ?? 'AS 65001', editable: false, - description: - 'Autonomous System number β€” identifies the routing domain' + description: 'Autonomous System number β€” identifies the routing domain' }, { name: 'Hold Time', @@ -55,8 +51,7 @@ export function createBGPLayer( bits: 0, value: overrides?.payload ?? '', editable: false, - description: - 'Type-specific data β€” NLRI prefixes, path attributes, error codes' + description: 'Type-specific data β€” NLRI prefixes, path attributes, error codes' } ] }; diff --git a/src/lib/simulator/layers/ble.ts b/src/lib/simulator/layers/ble.ts index b651372..aeb0fba 100644 --- a/src/lib/simulator/layers/ble.ts +++ b/src/lib/simulator/layers/ble.ts @@ -30,7 +30,8 @@ export function createBLELinkLayer( bits: 16, value: overrides?.llHeader ?? 'PDU=ADV_IND, len=22', editable: false, - description: 'PDU type + RFU + TxAdd + RxAdd + length on advertising; LLID/NESN/SN/MD on data' + description: + 'PDU type + RFU + TxAdd + RxAdd + length on advertising; LLID/NESN/SN/MD on data' }, { name: 'PDU Body', @@ -108,7 +109,8 @@ export function createATTLayer( bits: 16, value: overrides?.handle ?? '0x002A', editable: false, - description: 'Attribute handle β€” the address of a characteristic or descriptor in the GATT database' + description: + 'Attribute handle β€” the address of a characteristic or descriptor in the GATT database' }, { name: 'Value', diff --git a/src/lib/simulator/layers/cellular.ts b/src/lib/simulator/layers/cellular.ts index 5eeba1a..d6fd21d 100644 --- a/src/lib/simulator/layers/cellular.ts +++ b/src/lib/simulator/layers/cellular.ts @@ -102,7 +102,8 @@ export function createGTPULayer( bits: 8, value: '0x34 (v1, GTP, E=1)', editable: false, - description: 'Version=1, Protocol Type=GTP, E flag set when an Extension Header (PDU Session Container) follows' + description: + 'Version=1, Protocol Type=GTP, E flag set when an Extension Header (PDU Session Container) follows' }, { name: 'Message Type', @@ -116,28 +117,32 @@ export function createGTPULayer( bits: 16, value: overrides?.length ?? 1380, editable: false, - description: 'Length of the GTP-U payload + extension headers, excluding the 8-byte mandatory header' + description: + 'Length of the GTP-U payload + extension headers, excluding the 8-byte mandatory header' }, { name: 'TEID', bits: 32, value: overrides?.teid ?? '0xC0FFEE01', editable: false, - description: 'Tunnel Endpoint Identifier β€” identifies which PDU session this packet belongs to' + description: + 'Tunnel Endpoint Identifier β€” identifies which PDU session this packet belongs to' }, { name: 'PDU Session Container', bits: 0, value: overrides?.qfi ?? 'QFI=9 (QoS flow)', editable: false, - description: 'Extension header carrying the QoS Flow Identifier; maps to the DRB on the air interface' + description: + 'Extension header carrying the QoS Flow Identifier; maps to the DRB on the air interface' }, { name: 'Inner IP Packet', bits: 0, value: overrides?.inner ?? 'IPv6 src=UE dst=internet β€” TCP/UDP/QUIC payload', editable: false, - description: "The UE's actual IP packet β€” what an application sees as 'the internet connection'" + description: + "The UE's actual IP packet β€” what an application sees as 'the internet connection'" } ] }; diff --git a/src/lib/simulator/layers/coap.ts b/src/lib/simulator/layers/coap.ts index d55aa81..a42a387 100644 --- a/src/lib/simulator/layers/coap.ts +++ b/src/lib/simulator/layers/coap.ts @@ -21,8 +21,7 @@ export function createCoAPLayer( bits: 2, value: overrides?.type ?? 'CON (0)', editable: false, - description: - 'Message type β€” CON (confirmable), NON (non-confirmable), ACK, RST' + description: 'Message type β€” CON (confirmable), NON (non-confirmable), ACK, RST' }, { name: 'Token Len', @@ -37,8 +36,7 @@ export function createCoAPLayer( bits: 8, value: overrides?.code ?? '0.01 GET', editable: false, - description: - 'Method or response code β€” 0.01 GET, 0.02 POST, 2.05 Content, 2.04 Changed', + description: 'Method or response code β€” 0.01 GET, 0.02 POST, 2.05 Content, 2.04 Changed', color: '#78C257' }, { @@ -46,24 +44,21 @@ export function createCoAPLayer( bits: 16, value: overrides?.messageId ?? '0x7D34', editable: false, - description: - '16-bit ID for matching ACKs to CON messages and detecting duplicates' + description: '16-bit ID for matching ACKs to CON messages and detecting duplicates' }, { name: 'Options', bits: 0, value: overrides?.options ?? '', editable: false, - description: - 'CoAP options β€” Uri-Path, Content-Format, Observe, Max-Age, ETag' + description: 'CoAP options β€” Uri-Path, Content-Format, Observe, Max-Age, ETag' }, { name: 'Payload', bits: 0, value: overrides?.payload ?? '', editable: false, - description: - 'Message payload β€” typically CBOR or JSON, preceded by 0xFF marker' + description: 'Message payload β€” typically CBOR or JSON, preceded by 0xFF marker' } ] }; diff --git a/src/lib/simulator/layers/dhcp.ts b/src/lib/simulator/layers/dhcp.ts index e2ef260..8d27a79 100644 --- a/src/lib/simulator/layers/dhcp.ts +++ b/src/lib/simulator/layers/dhcp.ts @@ -22,8 +22,7 @@ export function createDHCPLayer( bits: 32, value: overrides?.xid ?? '0x3903F326', editable: false, - description: - 'Transaction ID β€” random value chosen by client to match requests with replies' + description: 'Transaction ID β€” random value chosen by client to match requests with replies' }, { name: 'Client MAC', @@ -44,8 +43,7 @@ export function createDHCPLayer( bits: 8, value: overrides?.messageType ?? 'DISCOVER', editable: false, - description: - 'DHCP option 53 β€” DISCOVER, OFFER, REQUEST, ACK, NAK, RELEASE', + description: 'DHCP option 53 β€” DISCOVER, OFFER, REQUEST, ACK, NAK, RELEASE', color: '#06B6D4' }, { @@ -53,8 +51,7 @@ export function createDHCPLayer( bits: 0, value: overrides?.options ?? '', editable: false, - description: - 'DHCP options β€” subnet mask, router, DNS servers, lease time' + description: 'DHCP options β€” subnet mask, router, DNS servers, lease time' } ] }; diff --git a/src/lib/simulator/layers/ethernet.ts b/src/lib/simulator/layers/ethernet.ts index 857443c..34812b9 100644 --- a/src/lib/simulator/layers/ethernet.ts +++ b/src/lib/simulator/layers/ethernet.ts @@ -1,6 +1,8 @@ import type { ProtocolLayer } from '../types'; -export function createEthernetLayer(overrides?: Partial<Record<string, string | number>>): ProtocolLayer { +export function createEthernetLayer( + overrides?: Partial<Record<string, string | number>> +): ProtocolLayer { return { name: 'Ethernet Frame', abbreviation: 'ETH', diff --git a/src/lib/simulator/layers/ftp.ts b/src/lib/simulator/layers/ftp.ts index 110111c..c774571 100644 --- a/src/lib/simulator/layers/ftp.ts +++ b/src/lib/simulator/layers/ftp.ts @@ -43,8 +43,7 @@ export function createFTPLayer( bits: 0, value: overrides?.channel ?? 'Control (21)', editable: false, - description: - 'Which connection carries this data β€” Control (port 21) or Data (port 20)' + description: 'Which connection carries this data β€” Control (port 21) or Data (port 20)' } ] }; diff --git a/src/lib/simulator/layers/grpc.ts b/src/lib/simulator/layers/grpc.ts index 3c7abac..7cc809c 100644 --- a/src/lib/simulator/layers/grpc.ts +++ b/src/lib/simulator/layers/grpc.ts @@ -1,6 +1,8 @@ import type { ProtocolLayer } from '../types'; -export function createGRPCLayer(overrides?: Partial<Record<string, string | number>>): ProtocolLayer { +export function createGRPCLayer( + overrides?: Partial<Record<string, string | number>> +): ProtocolLayer { return { name: 'gRPC Message', abbreviation: 'gRPC', diff --git a/src/lib/simulator/layers/http2.ts b/src/lib/simulator/layers/http2.ts index cbe89ae..04fde69 100644 --- a/src/lib/simulator/layers/http2.ts +++ b/src/lib/simulator/layers/http2.ts @@ -1,6 +1,8 @@ import type { ProtocolLayer } from '../types'; -export function createHTTP2FrameLayer(overrides?: Partial<Record<string, string | number>>): ProtocolLayer { +export function createHTTP2FrameLayer( + overrides?: Partial<Record<string, string | number>> +): ProtocolLayer { return { name: 'HTTP/2 Frame', abbreviation: 'H2', @@ -33,7 +35,8 @@ export function createHTTP2FrameLayer(overrides?: Partial<Record<string, string bits: 31, value: overrides?.streamId ?? 1, editable: false, - description: 'Stream identifier β€” odd for client-initiated, even for server push, 0 for connection' + description: + 'Stream identifier β€” odd for client-initiated, even for server push, 0 for connection' }, { name: 'Payload', diff --git a/src/lib/simulator/layers/icmp.ts b/src/lib/simulator/layers/icmp.ts index f3fe485..3c878dd 100644 --- a/src/lib/simulator/layers/icmp.ts +++ b/src/lib/simulator/layers/icmp.ts @@ -23,32 +23,28 @@ export function createICMPLayer( bits: 8, value: overrides?.code ?? 0, editable: false, - description: - 'Subtype code β€” for Type 3: 0=Net, 1=Host, 3=Port unreachable' + description: 'Subtype code β€” for Type 3: 0=Net, 1=Host, 3=Port unreachable' }, { name: 'Checksum', bits: 16, value: overrides?.checksum ?? '0x4D2A', editable: false, - description: - 'Error-checking value covering the entire ICMP message' + description: 'Error-checking value covering the entire ICMP message' }, { name: 'Identifier', bits: 16, value: overrides?.identifier ?? '0x1234', editable: false, - description: - 'Identifies the ping session β€” matches requests to replies' + description: 'Identifies the ping session β€” matches requests to replies' }, { name: 'Sequence', bits: 16, value: overrides?.sequence ?? 1, editable: false, - description: - 'Sequence number β€” increments with each ping in a session' + description: 'Sequence number β€” increments with each ping in a session' }, { name: 'Data', diff --git a/src/lib/simulator/layers/imap.ts b/src/lib/simulator/layers/imap.ts index f6e0705..7ffb8d4 100644 --- a/src/lib/simulator/layers/imap.ts +++ b/src/lib/simulator/layers/imap.ts @@ -22,32 +22,28 @@ export function createIMAPLayer( bits: 0, value: overrides?.command ?? 'SELECT', editable: false, - description: - 'IMAP command β€” LOGIN, SELECT, FETCH, SEARCH, STORE, IDLE, LOGOUT' + description: 'IMAP command β€” LOGIN, SELECT, FETCH, SEARCH, STORE, IDLE, LOGOUT' }, { name: 'Arguments', bits: 0, value: overrides?.arguments ?? 'INBOX', editable: false, - description: - 'Command arguments β€” mailbox name, message sequence, fetch items' + description: 'Command arguments β€” mailbox name, message sequence, fetch items' }, { name: 'Response Status', bits: 0, value: overrides?.responseStatus ?? '', editable: false, - description: - 'Tagged response status β€” OK, NO, BAD, or untagged * responses' + description: 'Tagged response status β€” OK, NO, BAD, or untagged * responses' }, { name: 'Response Data', bits: 0, value: overrides?.responseData ?? '', editable: false, - description: - 'Response payload β€” message data, mailbox info, search results' + description: 'Response payload β€” message data, mailbox info, search results' } ] }; diff --git a/src/lib/simulator/layers/ipsec.ts b/src/lib/simulator/layers/ipsec.ts index 887ab5f..8c95024 100644 --- a/src/lib/simulator/layers/ipsec.ts +++ b/src/lib/simulator/layers/ipsec.ts @@ -14,14 +14,16 @@ export function createIKEv2Layer( bits: 64, value: overrides?.initSpi ?? '0x1122334455667788', editable: false, - description: '64-bit Initiator Security Parameters Index β€” identifies the IKE SA on the initiator' + description: + '64-bit Initiator Security Parameters Index β€” identifies the IKE SA on the initiator' }, { name: 'Responder SPI', bits: 64, value: overrides?.respSpi ?? '0x0000000000000000', editable: false, - description: '64-bit Responder SPI β€” zero until the responder picks one in the first IKE_SA_INIT response' + description: + '64-bit Responder SPI β€” zero until the responder picks one in the first IKE_SA_INIT response' }, { name: 'Next Payload', @@ -57,7 +59,8 @@ export function createIKEv2Layer( bits: 32, value: overrides?.messageId ?? 0, editable: false, - description: 'Counter that prevents replay; starts at 0 for IKE_SA_INIT and increments per request' + description: + 'Counter that prevents replay; starts at 0 for IKE_SA_INIT and increments per request' }, { name: 'Payloads', @@ -84,14 +87,16 @@ export function createESPLayer( bits: 32, value: overrides?.spi ?? '0xC0FFEE01', editable: false, - description: 'Security Parameters Index β€” receiver looks up the SA (key, cipher) by this value' + description: + 'Security Parameters Index β€” receiver looks up the SA (key, cipher) by this value' }, { name: 'Sequence Number', bits: 32, value: overrides?.seq ?? 1, editable: false, - description: 'Anti-replay counter β€” receiver maintains a sliding window (default 32, prod tune β‰₯1024)' + description: + 'Anti-replay counter β€” receiver maintains a sliding window (default 32, prod tune β‰₯1024)' }, { name: 'IV / Nonce', @@ -105,7 +110,8 @@ export function createESPLayer( bits: 0, value: overrides?.payload ?? '<encrypted inner IP packet + ESP trailer>', editable: false, - description: 'In tunnel mode: the entire inner IP packet plus an ESP trailer (padding + next-header byte)' + description: + 'In tunnel mode: the entire inner IP packet plus an ESP trailer (padding + next-header byte)' }, { name: 'ICV (Auth Tag)', diff --git a/src/lib/simulator/layers/ipv4.ts b/src/lib/simulator/layers/ipv4.ts index 70d4ea7..c44f493 100644 --- a/src/lib/simulator/layers/ipv4.ts +++ b/src/lib/simulator/layers/ipv4.ts @@ -1,6 +1,8 @@ import type { ProtocolLayer } from '../types'; -export function createIPv4Layer(overrides?: Partial<Record<string, string | number>>): ProtocolLayer { +export function createIPv4Layer( + overrides?: Partial<Record<string, string | number>> +): ProtocolLayer { return { name: 'IPv4 Packet', abbreviation: 'IP', @@ -38,7 +40,7 @@ export function createIPv4Layer(overrides?: Partial<Record<string, string | numb { name: 'ID', bits: 16, - value: overrides?.id ?? 0x1A2B, + value: overrides?.id ?? 0x1a2b, editable: false, description: 'Identification β€” used for reassembling fragmented packets' }, @@ -47,7 +49,7 @@ export function createIPv4Layer(overrides?: Partial<Record<string, string | numb bits: 3, value: '010', editable: false, - description: 'Control flags β€” bit 1 (DF: Don\'t Fragment) is set' + description: "Control flags β€” bit 1 (DF: Don't Fragment) is set" }, { name: 'TTL', diff --git a/src/lib/simulator/layers/ipv6.ts b/src/lib/simulator/layers/ipv6.ts index 979bda9..71405fa 100644 --- a/src/lib/simulator/layers/ipv6.ts +++ b/src/lib/simulator/layers/ipv6.ts @@ -1,6 +1,8 @@ import type { ProtocolLayer } from '../types'; -export function createIPv6Layer(overrides?: Partial<Record<string, string | number>>): ProtocolLayer { +export function createIPv6Layer( + overrides?: Partial<Record<string, string | number>> +): ProtocolLayer { return { name: 'IPv6 Packet', abbreviation: 'IPv6', @@ -47,7 +49,8 @@ export function createIPv6Layer(overrides?: Partial<Record<string, string | numb bits: 8, value: overrides?.hopLimit ?? 64, editable: true, - description: 'Hop Limit β€” decremented at each router, packet discarded at 0 (replaces IPv4 TTL)' + description: + 'Hop Limit β€” decremented at each router, packet discarded at 0 (replaces IPv4 TTL)' }, { name: 'Src IP', diff --git a/src/lib/simulator/layers/kafka.ts b/src/lib/simulator/layers/kafka.ts index b0f0b13..80f4cfe 100644 --- a/src/lib/simulator/layers/kafka.ts +++ b/src/lib/simulator/layers/kafka.ts @@ -14,32 +14,28 @@ export function createKafkaLayer( bits: 16, value: overrides?.apiKey ?? 'Produce (0)', editable: false, - description: - 'Request type β€” ApiVersions (18), Metadata (3), Produce (0), Fetch (1), etc.' + description: 'Request type β€” ApiVersions (18), Metadata (3), Produce (0), Fetch (1), etc.' }, { name: 'API Version', bits: 16, value: overrides?.apiVersion ?? 9, editable: false, - description: - 'Protocol version for this API β€” allows backward-compatible evolution' + description: 'Protocol version for this API β€” allows backward-compatible evolution' }, { name: 'Correlation ID', bits: 32, value: overrides?.correlationId ?? 1, editable: false, - description: - 'Client-assigned ID to match responses to requests across async pipelining' + description: 'Client-assigned ID to match responses to requests across async pipelining' }, { name: 'Client ID', bits: 0, value: overrides?.clientId ?? 'producer-1', editable: false, - description: - 'Identifier for the client application β€” used in logging and quotas' + description: 'Identifier for the client application β€” used in logging and quotas' }, { name: 'Topic', @@ -54,16 +50,14 @@ export function createKafkaLayer( bits: 32, value: overrides?.partition ?? 0, editable: false, - description: - 'Partition index β€” topics are split into partitions for parallel processing' + description: 'Partition index β€” topics are split into partitions for parallel processing' }, { name: 'Payload', bits: 0, value: overrides?.payload ?? '', editable: false, - description: - 'Message key/value pairs β€” typically serialized as JSON, Avro, or Protobuf' + description: 'Message key/value pairs β€” typically serialized as JSON, Avro, or Protobuf' } ] }; diff --git a/src/lib/simulator/layers/kerberos.ts b/src/lib/simulator/layers/kerberos.ts index 56fb1ee..93bdef8 100644 --- a/src/lib/simulator/layers/kerberos.ts +++ b/src/lib/simulator/layers/kerberos.ts @@ -22,14 +22,16 @@ export function createKerberosLayer( bits: 8, value: 5, editable: false, - description: 'Kerberos protocol version β€” 5 is current; V4 was deprecated in MIT krb5 1.18 (2020)' + description: + 'Kerberos protocol version β€” 5 is current; V4 was deprecated in MIT krb5 1.18 (2020)' }, { name: 'Message Type', bits: 8, value: overrides?.msgType ?? 10, editable: false, - description: 'Matches the application tag β€” 10=AS-REQ, 11=AS-REP, 12=TGS-REQ, 13=TGS-REP, 14=AP-REQ, 15=AP-REP' + description: + 'Matches the application tag β€” 10=AS-REQ, 11=AS-REP, 12=TGS-REQ, 13=TGS-REP, 14=AP-REQ, 15=AP-REP' }, { name: 'Principal Name (cname / sname)', diff --git a/src/lib/simulator/layers/mdns.ts b/src/lib/simulator/layers/mdns.ts index 29a8e9a..b530d1a 100644 --- a/src/lib/simulator/layers/mdns.ts +++ b/src/lib/simulator/layers/mdns.ts @@ -14,7 +14,8 @@ export function createMDNSLayer( bits: 16, value: overrides?.txid ?? '0x0000', editable: false, - description: 'mDNS uses 0x0000 β€” multicast doesn\'t need transaction IDs (matching is by question)' + description: + "mDNS uses 0x0000 β€” multicast doesn't need transaction IDs (matching is by question)" }, { name: 'Flags', diff --git a/src/lib/simulator/layers/mptcp.ts b/src/lib/simulator/layers/mptcp.ts index 8db10fc..d0e8bbd 100644 --- a/src/lib/simulator/layers/mptcp.ts +++ b/src/lib/simulator/layers/mptcp.ts @@ -14,8 +14,7 @@ export function createMPTCPLayer( bits: 4, value: overrides?.subtype ?? 'MP_CAPABLE (0)', editable: false, - description: - 'MPTCP option subtype β€” MP_CAPABLE, MP_JOIN, DSS, ADD_ADDR, REMOVE_ADDR' + description: 'MPTCP option subtype β€” MP_CAPABLE, MP_JOIN, DSS, ADD_ADDR, REMOVE_ADDR' }, { name: 'Version', @@ -29,24 +28,21 @@ export function createMPTCPLayer( bits: 8, value: overrides?.flags ?? 'H=1', editable: false, - description: - 'Option flags β€” H (HMAC-SHA256), A (checksum), B (backup path), etc.' + description: 'Option flags β€” H (HMAC-SHA256), A (checksum), B (backup path), etc.' }, { name: 'Sender Key', bits: 0, value: overrides?.senderKey ?? '', editable: false, - description: - 'Sender\'s key β€” used to derive tokens and authenticate subflow joins' + description: "Sender's key β€” used to derive tokens and authenticate subflow joins" }, { name: 'Subflow', bits: 0, value: overrides?.subflow ?? 'Primary', editable: false, - description: - 'Which TCP subflow this belongs to β€” Primary (Wi-Fi) or Secondary (Cellular)' + description: 'Which TCP subflow this belongs to β€” Primary (Wi-Fi) or Secondary (Cellular)' }, { name: 'Payload', diff --git a/src/lib/simulator/layers/mqtt.ts b/src/lib/simulator/layers/mqtt.ts index 3fa5619..49af8d8 100644 --- a/src/lib/simulator/layers/mqtt.ts +++ b/src/lib/simulator/layers/mqtt.ts @@ -21,40 +21,35 @@ export function createMQTTLayer( bits: 4, value: overrides?.flags ?? '0000', editable: false, - description: - 'Type-specific flags β€” DUP, QoS level, RETAIN for PUBLISH packets' + description: 'Type-specific flags β€” DUP, QoS level, RETAIN for PUBLISH packets' }, { name: 'Remaining Len', bits: 8, value: overrides?.remainingLength ?? 42, editable: false, - description: - 'Remaining bytes after fixed header β€” variable-length encoding up to 256 MB' + description: 'Remaining bytes after fixed header β€” variable-length encoding up to 256 MB' }, { name: 'Packet ID', bits: 16, value: overrides?.packetId ?? 1, editable: false, - description: - 'Packet identifier β€” used by QoS 1/2 and SUBSCRIBE/UNSUBSCRIBE for matching' + description: 'Packet identifier β€” used by QoS 1/2 and SUBSCRIBE/UNSUBSCRIBE for matching' }, { name: 'Topic', bits: 0, value: overrides?.topic ?? 'sensors/temperature', editable: false, - description: - 'Topic name β€” hierarchical path using / separators, supports + and # wildcards' + description: 'Topic name β€” hierarchical path using / separators, supports + and # wildcards' }, { name: 'Payload', bits: 0, value: overrides?.payload ?? '', editable: false, - description: - 'Message payload β€” can be any binary data, commonly JSON or plain text' + description: 'Message payload β€” can be any binary data, commonly JSON or plain text' } ] }; diff --git a/src/lib/simulator/layers/nfc.ts b/src/lib/simulator/layers/nfc.ts index f83c635..0d8f092 100644 --- a/src/lib/simulator/layers/nfc.ts +++ b/src/lib/simulator/layers/nfc.ts @@ -13,7 +13,8 @@ export function createNFCALayer( { name: 'Carrier', bits: 0, - value: '13.56 MHz, 100% ASK modified-Miller (readerβ†’card) / OOK Manchester on 847.5 kHz subcarrier (cardβ†’reader)', + value: + '13.56 MHz, 100% ASK modified-Miller (readerβ†’card) / OOK Manchester on 847.5 kHz subcarrier (cardβ†’reader)', editable: false, description: 'NFC-A physical layer β€” the same since ISO 14443-3 was published in 2000' }, @@ -30,21 +31,24 @@ export function createNFCALayer( bits: 0, value: overrides?.direction ?? 'PCD β†’ PICC', editable: false, - description: 'PCD (Proximity Coupling Device, the reader) β†’ PICC (Proximity Integrated Circuit Card, the tag)' + description: + 'PCD (Proximity Coupling Device, the reader) β†’ PICC (Proximity Integrated Circuit Card, the tag)' }, { name: 'Payload', bits: 0, value: overrides?.payload ?? '0x26', editable: false, - description: 'Frame-specific payload β€” REQA=0x26, WUPA=0x52, SEL=0x93/0x95/0x97, HLTA=0x50 0x00, etc.' + description: + 'Frame-specific payload β€” REQA=0x26, WUPA=0x52, SEL=0x93/0x95/0x97, HLTA=0x50 0x00, etc.' }, { name: 'CRC_A', bits: 16, value: overrides?.crc ?? '(none β€” short frame)', editable: false, - description: 'CRC_A polynomial 0x8408, appended to standard and full frames; absent on short frames' + description: + 'CRC_A polynomial 0x8408, appended to standard and full frames; absent on short frames' } ] }; @@ -96,7 +100,7 @@ export function createNDEFLayer( value: overrides?.payload ?? '0x03 example.com/info', editable: false, description: - "For a URI record: first byte is the prefix code (0x01=http://www., 0x02=https://www., 0x03=http://, 0x04=https://, 0x05=tel:, 0x06=mailto:); remainder is the URI body" + 'For a URI record: first byte is the prefix code (0x01=http://www., 0x02=https://www., 0x03=http://, 0x04=https://, 0x05=tel:, 0x06=mailto:); remainder is the URI body' } ] }; @@ -130,9 +134,12 @@ export function createAPDULayer( { name: 'Data', bits: 0, - value: overrides?.data ?? "32 50 41 59 2E 53 59 53 2E 44 44 46 30 31 (PPSE AID '2PAY.SYS.DDF01')", + value: + overrides?.data ?? + "32 50 41 59 2E 53 59 53 2E 44 44 46 30 31 (PPSE AID '2PAY.SYS.DDF01')", editable: false, - description: 'Command body β€” for SELECT, the AID being selected; for GENERATE AC, the CDOL1 data' + description: + 'Command body β€” for SELECT, the AID being selected; for GENERATE AC, the CDOL1 data' }, { name: 'Le', diff --git a/src/lib/simulator/layers/ntp.ts b/src/lib/simulator/layers/ntp.ts index cae624d..c403fd3 100644 --- a/src/lib/simulator/layers/ntp.ts +++ b/src/lib/simulator/layers/ntp.ts @@ -30,32 +30,28 @@ export function createNTPLayer( bits: 8, value: overrides?.poll ?? 6, editable: false, - description: - 'Poll interval as log2 seconds β€” 6 means poll every 64 seconds' + description: 'Poll interval as log2 seconds β€” 6 means poll every 64 seconds' }, { name: 'Precision', bits: 8, value: overrides?.precision ?? '-20', editable: false, - description: - 'Clock precision as log2 seconds β€” -20 is approximately 1 microsecond' + description: 'Clock precision as log2 seconds β€” -20 is approximately 1 microsecond' }, { name: 'Reference ID', bits: 32, value: overrides?.refId ?? '', editable: false, - description: - 'Identifies the time source β€” "GPS", "ATOM", or IP address of upstream server' + description: 'Identifies the time source β€” "GPS", "ATOM", or IP address of upstream server' }, { name: 'Timestamps', bits: 0, value: overrides?.timestamps ?? '', editable: false, - description: - 'Four 64-bit timestamps: Reference, Origin (T1), Receive (T2), Transmit (T3)' + description: 'Four 64-bit timestamps: Reference, Origin (T1), Receive (T2), Transmit (T3)' } ] }; diff --git a/src/lib/simulator/layers/oauth2.ts b/src/lib/simulator/layers/oauth2.ts index a80f47e..602dc3d 100644 --- a/src/lib/simulator/layers/oauth2.ts +++ b/src/lib/simulator/layers/oauth2.ts @@ -14,24 +14,21 @@ export function createOAuth2Layer( bits: 0, value: overrides?.grantType ?? 'authorization_code', editable: false, - description: - 'OAuth flow type β€” authorization_code, client_credentials, refresh_token' + description: 'OAuth flow type β€” authorization_code, client_credentials, refresh_token' }, { name: 'Client ID', bits: 0, value: overrides?.clientId ?? 'my-app-id', editable: false, - description: - 'Identifies the application requesting access' + description: 'Identifies the application requesting access' }, { name: 'Scope', bits: 0, value: overrides?.scope ?? 'read:user email', editable: false, - description: - 'Requested permissions β€” limits what the token can access', + description: 'Requested permissions β€” limits what the token can access', color: '#2DD4BF' }, { @@ -39,24 +36,21 @@ export function createOAuth2Layer( bits: 0, value: overrides?.state ?? 'xYz123_csrf', editable: false, - description: - 'CSRF protection β€” random value verified on callback' + description: 'CSRF protection β€” random value verified on callback' }, { name: 'Code Challenge', bits: 0, value: overrides?.codeChallenge ?? 'SHA256(verifier)', editable: false, - description: - 'PKCE β€” proves the token requester is the same as the auth initiator' + description: 'PKCE β€” proves the token requester is the same as the auth initiator' }, { name: 'Token', bits: 0, value: overrides?.token ?? '', editable: false, - description: - 'Access token (JWT or opaque) β€” presented in Authorization: Bearer header' + description: 'Access token (JWT or opaque) β€” presented in Authorization: Bearer header' } ] }; diff --git a/src/lib/simulator/layers/ospf.ts b/src/lib/simulator/layers/ospf.ts index 91223e2..026f1b8 100644 --- a/src/lib/simulator/layers/ospf.ts +++ b/src/lib/simulator/layers/ospf.ts @@ -1,6 +1,8 @@ import type { ProtocolLayer } from '../types'; -export function createOSPFLayer(overrides?: Partial<Record<string, string | number>>): ProtocolLayer { +export function createOSPFLayer( + overrides?: Partial<Record<string, string | number>> +): ProtocolLayer { return { name: 'OSPFv2 Packet', abbreviation: 'OSPF', diff --git a/src/lib/simulator/layers/quic.ts b/src/lib/simulator/layers/quic.ts index b2f303c..7ac02fb 100644 --- a/src/lib/simulator/layers/quic.ts +++ b/src/lib/simulator/layers/quic.ts @@ -1,6 +1,8 @@ import type { ProtocolLayer } from '../types'; -export function createQUICLayer(overrides?: Partial<Record<string, string | number>>): ProtocolLayer { +export function createQUICLayer( + overrides?: Partial<Record<string, string | number>> +): ProtocolLayer { return { name: 'QUIC Packet', abbreviation: 'QUIC', diff --git a/src/lib/simulator/layers/rtmp.ts b/src/lib/simulator/layers/rtmp.ts index c5ea1c0..6edb20e 100644 --- a/src/lib/simulator/layers/rtmp.ts +++ b/src/lib/simulator/layers/rtmp.ts @@ -14,16 +14,14 @@ export function createRTMPLayer( bits: 2, value: overrides?.chunkType ?? 'Type 0 (full)', editable: false, - description: - 'Chunk header format β€” Type 0 (12 bytes, full), Type 1-3 (compressed headers)' + description: 'Chunk header format β€” Type 0 (12 bytes, full), Type 1-3 (compressed headers)' }, { name: 'Chunk Stream ID', bits: 6, value: overrides?.chunkStreamId ?? 3, editable: false, - description: - 'Multiplexing channel β€” 2=protocol control, 3+=application messages' + description: 'Multiplexing channel β€” 2=protocol control, 3+=application messages' }, { name: 'Message Type', @@ -38,8 +36,7 @@ export function createRTMPLayer( bits: 32, value: overrides?.streamId ?? 0, editable: false, - description: - 'Message stream ID β€” 0 for control, 1+ for published streams' + description: 'Message stream ID β€” 0 for control, 1+ for published streams' }, { name: 'Timestamp', @@ -54,8 +51,7 @@ export function createRTMPLayer( bits: 0, value: overrides?.payload ?? '', editable: false, - description: - 'AMF-encoded command, audio/video data, or metadata' + description: 'AMF-encoded command, audio/video data, or metadata' } ] }; diff --git a/src/lib/simulator/layers/rtp.ts b/src/lib/simulator/layers/rtp.ts index a730582..af17337 100644 --- a/src/lib/simulator/layers/rtp.ts +++ b/src/lib/simulator/layers/rtp.ts @@ -14,8 +14,7 @@ export function createRTPLayer( bits: 8, value: overrides?.flags ?? '0x80', editable: false, - description: - 'Version (2), Padding (1), Extension (1), CSRC Count (4) β€” V=2 is current' + description: 'Version (2), Padding (1), Extension (1), CSRC Count (4) β€” V=2 is current' }, { name: 'M/PT', @@ -30,8 +29,7 @@ export function createRTPLayer( bits: 16, value: overrides?.seq ?? 1, editable: false, - description: - 'Sequence number β€” increments per packet, used to detect loss and reorder' + description: 'Sequence number β€” increments per packet, used to detect loss and reorder' }, { name: 'Timestamp', @@ -54,8 +52,7 @@ export function createRTPLayer( bits: 0, value: overrides?.payload ?? '', editable: false, - description: - 'Encoded media data β€” audio samples (Opus, G.711) or video frames (H.264, VP8)' + description: 'Encoded media data β€” audio samples (Opus, G.711) or video frames (H.264, VP8)' } ] }; diff --git a/src/lib/simulator/layers/sctp.ts b/src/lib/simulator/layers/sctp.ts index acb340d..e4d8b03 100644 --- a/src/lib/simulator/layers/sctp.ts +++ b/src/lib/simulator/layers/sctp.ts @@ -28,16 +28,14 @@ export function createSCTPLayer( bits: 32, value: overrides?.vTag ?? '0x00000000', editable: false, - description: - 'Verification Tag β€” prevents blind attacks, must match the association\'s tag' + description: "Verification Tag β€” prevents blind attacks, must match the association's tag" }, { name: 'Chunk Type', bits: 8, value: overrides?.chunkType ?? 'INIT (1)', editable: false, - description: - 'Chunk type β€” INIT, INIT-ACK, COOKIE-ECHO, COOKIE-ACK, DATA, SACK, HEARTBEAT', + description: 'Chunk type β€” INIT, INIT-ACK, COOKIE-ECHO, COOKIE-ACK, DATA, SACK, HEARTBEAT', color: '#7C3AED' }, { @@ -52,8 +50,7 @@ export function createSCTPLayer( bits: 0, value: overrides?.payload ?? '', editable: false, - description: - 'Chunk data β€” initiation parameters, cookie, or application data' + description: 'Chunk data β€” initiation parameters, cookie, or application data' } ] }; diff --git a/src/lib/simulator/layers/sip.ts b/src/lib/simulator/layers/sip.ts index f3d70ca..757df78 100644 --- a/src/lib/simulator/layers/sip.ts +++ b/src/lib/simulator/layers/sip.ts @@ -14,8 +14,7 @@ export function createSIPLayer( bits: 0, value: overrides?.method ?? 'INVITE', editable: false, - description: - 'SIP method β€” INVITE, ACK, BYE, CANCEL, REGISTER, OPTIONS' + description: 'SIP method β€” INVITE, ACK, BYE, CANCEL, REGISTER, OPTIONS' }, { name: 'Status', @@ -30,32 +29,28 @@ export function createSIPLayer( bits: 0, value: overrides?.from ?? '', editable: false, - description: - 'Caller SIP URI β€” identifies the initiator of the request (sip:user@domain)' + description: 'Caller SIP URI β€” identifies the initiator of the request (sip:user@domain)' }, { name: 'To', bits: 0, value: overrides?.to ?? '', editable: false, - description: - 'Callee SIP URI β€” identifies the intended recipient of the request' + description: 'Callee SIP URI β€” identifies the intended recipient of the request' }, { name: 'Call-ID', bits: 0, value: overrides?.callId ?? '', editable: false, - description: - 'Unique call identifier β€” groups all messages belonging to the same dialog' + description: 'Unique call identifier β€” groups all messages belonging to the same dialog' }, { name: 'Body', bits: 0, value: overrides?.body ?? '', editable: false, - description: - 'Message body β€” typically SDP for media negotiation in INVITE/200 OK' + description: 'Message body β€” typically SDP for media negotiation in INVITE/200 OK' } ] }; diff --git a/src/lib/simulator/layers/smtp.ts b/src/lib/simulator/layers/smtp.ts index 9e4bb54..6827876 100644 --- a/src/lib/simulator/layers/smtp.ts +++ b/src/lib/simulator/layers/smtp.ts @@ -21,8 +21,7 @@ export function createSMTPLayer( bits: 0, value: overrides?.parameter ?? 'client.example.com', editable: false, - description: - 'Command parameter β€” hostname for EHLO, address for MAIL FROM/RCPT TO' + description: 'Command parameter β€” hostname for EHLO, address for MAIL FROM/RCPT TO' }, { name: 'Response Code', diff --git a/src/lib/simulator/layers/soap.ts b/src/lib/simulator/layers/soap.ts index 627152c..25990bb 100644 --- a/src/lib/simulator/layers/soap.ts +++ b/src/lib/simulator/layers/soap.ts @@ -14,24 +14,21 @@ export function createSOAPLayer( bits: 0, value: overrides?.envelope ?? 'soap:Envelope xmlns:soap="..."', editable: false, - description: - 'Root XML element wrapping the entire SOAP message' + description: 'Root XML element wrapping the entire SOAP message' }, { name: 'Header', bits: 0, value: overrides?.header ?? '', editable: false, - description: - 'Optional SOAP Header β€” authentication, routing, transaction context' + description: 'Optional SOAP Header β€” authentication, routing, transaction context' }, { name: 'Body', bits: 0, value: overrides?.body ?? 'GetUser(id: 42)', editable: false, - description: - 'Required SOAP Body β€” contains the operation and parameters', + description: 'Required SOAP Body β€” contains the operation and parameters', color: '#00D4FF' }, { @@ -39,16 +36,14 @@ export function createSOAPLayer( bits: 0, value: overrides?.namespace ?? 'http://example.com/users', editable: false, - description: - 'XML namespace identifying the service schema and operations' + description: 'XML namespace identifying the service schema and operations' }, { name: 'SOAPAction', bits: 0, value: overrides?.soapAction ?? 'http://example.com/GetUser', editable: false, - description: - 'HTTP header identifying the intended SOAP operation' + description: 'HTTP header identifying the intended SOAP operation' } ] }; diff --git a/src/lib/simulator/layers/ssh.ts b/src/lib/simulator/layers/ssh.ts index 16f4435..ef675fe 100644 --- a/src/lib/simulator/layers/ssh.ts +++ b/src/lib/simulator/layers/ssh.ts @@ -1,6 +1,8 @@ import type { ProtocolLayer } from '../types'; -export function createSSHLayer(overrides?: Partial<Record<string, string | number>>): ProtocolLayer { +export function createSSHLayer( + overrides?: Partial<Record<string, string | number>> +): ProtocolLayer { return { name: 'SSH Packet', abbreviation: 'SSH', @@ -26,7 +28,8 @@ export function createSSHLayer(overrides?: Partial<Record<string, string | numbe bits: 8, value: overrides?.messageType ?? 'KEXINIT (20)', editable: false, - description: 'SSH message type β€” KEXINIT, KEXDH_INIT, NEWKEYS, SERVICE_REQUEST, USERAUTH_REQUEST, etc.' + description: + 'SSH message type β€” KEXINIT, KEXDH_INIT, NEWKEYS, SERVICE_REQUEST, USERAUTH_REQUEST, etc.' }, { name: 'Algorithm', @@ -40,7 +43,8 @@ export function createSSHLayer(overrides?: Partial<Record<string, string | numbe bits: 0, value: overrides?.payload ?? 'Key exchange data', editable: false, - description: 'Message-specific payload β€” key exchange parameters, auth credentials, or encrypted data' + description: + 'Message-specific payload β€” key exchange parameters, auth credentials, or encrypted data' } ] }; diff --git a/src/lib/simulator/layers/stomp.ts b/src/lib/simulator/layers/stomp.ts index babea32..3724cea 100644 --- a/src/lib/simulator/layers/stomp.ts +++ b/src/lib/simulator/layers/stomp.ts @@ -14,24 +14,21 @@ export function createSTOMPLayer( bits: 0, value: overrides?.command ?? 'CONNECT', editable: false, - description: - 'STOMP command β€” CONNECT, CONNECTED, SEND, SUBSCRIBE, MESSAGE, ACK, DISCONNECT' + description: 'STOMP command β€” CONNECT, CONNECTED, SEND, SUBSCRIBE, MESSAGE, ACK, DISCONNECT' }, { name: 'Destination', bits: 0, value: overrides?.destination ?? '', editable: false, - description: - 'Message destination β€” queue or topic path (e.g. /queue/orders, /topic/prices)' + description: 'Message destination β€” queue or topic path (e.g. /queue/orders, /topic/prices)' }, { name: 'Content-Type', bits: 0, value: overrides?.contentType ?? '', editable: false, - description: - 'MIME type of the body β€” application/json, text/plain, etc.' + description: 'MIME type of the body β€” application/json, text/plain, etc.' }, { name: 'Receipt', @@ -54,8 +51,7 @@ export function createSTOMPLayer( bits: 0, value: overrides?.body ?? '', editable: false, - description: - 'Frame body β€” the message payload, terminated by a null character (\\0)' + description: 'Frame body β€” the message payload, terminated by a null character (\\0)' } ] }; diff --git a/src/lib/simulator/layers/stun.ts b/src/lib/simulator/layers/stun.ts index b2ef1f0..c732f40 100644 --- a/src/lib/simulator/layers/stun.ts +++ b/src/lib/simulator/layers/stun.ts @@ -1,6 +1,8 @@ import type { ProtocolLayer } from '../types'; -export function createSTUNLayer(overrides?: Partial<Record<string, string | number>>): ProtocolLayer { +export function createSTUNLayer( + overrides?: Partial<Record<string, string | number>> +): ProtocolLayer { return { name: 'STUN Message', abbreviation: 'STUN', @@ -40,7 +42,8 @@ export function createSTUNLayer(overrides?: Partial<Record<string, string | numb bits: 0, value: overrides?.attribute ?? 'XOR-MAPPED-ADDRESS', editable: false, - description: 'STUN attribute β€” XOR-MAPPED-ADDRESS reveals the public IP:port as seen by the STUN server' + description: + 'STUN attribute β€” XOR-MAPPED-ADDRESS reveals the public IP:port as seen by the STUN server' } ] }; diff --git a/src/lib/simulator/layers/tcp.ts b/src/lib/simulator/layers/tcp.ts index 13239b2..b584a63 100644 --- a/src/lib/simulator/layers/tcp.ts +++ b/src/lib/simulator/layers/tcp.ts @@ -1,6 +1,8 @@ import type { ProtocolLayer } from '../types'; -export function createTCPLayer(overrides?: Partial<Record<string, string | number>>): ProtocolLayer { +export function createTCPLayer( + overrides?: Partial<Record<string, string | number>> +): ProtocolLayer { return { name: 'TCP Segment', abbreviation: 'TCP', @@ -76,7 +78,8 @@ export function createTCPLayer(overrides?: Partial<Record<string, string | numbe bits: 16, value: 0, editable: false, - description: 'Urgent pointer β€” offset to the end of urgent data (only valid when URG flag is set)' + description: + 'Urgent pointer β€” offset to the end of urgent data (only valid when URG flag is set)' } ] }; diff --git a/src/lib/simulator/layers/tls.ts b/src/lib/simulator/layers/tls.ts index 497fa2c..f41c2a0 100644 --- a/src/lib/simulator/layers/tls.ts +++ b/src/lib/simulator/layers/tls.ts @@ -1,6 +1,8 @@ import type { ProtocolLayer } from '../types'; -export function createTLSRecordLayer(overrides?: Partial<Record<string, string | number>>): ProtocolLayer { +export function createTLSRecordLayer( + overrides?: Partial<Record<string, string | number>> +): ProtocolLayer { return { name: 'TLS Record', abbreviation: 'TLS', @@ -12,7 +14,8 @@ export function createTLSRecordLayer(overrides?: Partial<Record<string, string | bits: 8, value: overrides?.contentType ?? 'Handshake (22)', editable: false, - description: 'Record type β€” Handshake (22), Application Data (23), Alert (21), Change Cipher Spec (20)' + description: + 'Record type β€” Handshake (22), Application Data (23), Alert (21), Change Cipher Spec (20)' }, { name: 'Version', @@ -47,7 +50,8 @@ export function createTLSRecordLayer(overrides?: Partial<Record<string, string | bits: 0, value: overrides?.extensions ?? 'SNI, key_share, supported_versions', editable: false, - description: 'TLS extensions β€” Server Name Indication, key shares, supported protocol versions' + description: + 'TLS extensions β€” Server Name Indication, key shares, supported protocol versions' } ] }; diff --git a/src/lib/simulator/layers/udp.ts b/src/lib/simulator/layers/udp.ts index a41738e..b0f1cdf 100644 --- a/src/lib/simulator/layers/udp.ts +++ b/src/lib/simulator/layers/udp.ts @@ -1,6 +1,8 @@ import type { ProtocolLayer } from '../types'; -export function createUDPLayer(overrides?: Partial<Record<string, string | number>>): ProtocolLayer { +export function createUDPLayer( + overrides?: Partial<Record<string, string | number>> +): ProtocolLayer { return { name: 'UDP Datagram', abbreviation: 'UDP', @@ -12,7 +14,7 @@ export function createUDPLayer(overrides?: Partial<Record<string, string | numbe bits: 16, value: overrides?.srcPort ?? 49152, editable: true, - description: 'Source port β€” sender\'s port number' + description: "Source port β€” sender's port number" }, { name: 'Dst Port', diff --git a/src/lib/simulator/layers/uwb.ts b/src/lib/simulator/layers/uwb.ts index c27d985..e9324cd 100644 --- a/src/lib/simulator/layers/uwb.ts +++ b/src/lib/simulator/layers/uwb.ts @@ -15,28 +15,32 @@ export function createUWBPHYLayer( bits: 0, value: overrides?.channel ?? 'Ch 9 β€” 7987.2 MHz, 499.2 MHz BW', editable: false, - description: 'Channel 5 (6489.6 MHz) is universal; Channel 9 (7987.2 MHz) is preferred outside Japan' + description: + 'Channel 5 (6489.6 MHz) is universal; Channel 9 (7987.2 MHz) is preferred outside Japan' }, { name: 'Mode', bits: 0, value: overrides?.mode ?? 'BPRF mean PRF = 64 MHz, 6.81 Mbps data rate', editable: false, - description: 'BPRF (base ~64 MHz) for tag-side power; HPRF (124.8/249.6 MHz) for anchor-side processing gain' + description: + 'BPRF (base ~64 MHz) for tag-side power; HPRF (124.8/249.6 MHz) for anchor-side processing gain' }, { name: 'SHR (Preamble + SFD)', bits: 0, value: overrides?.shr ?? '64 sync symbols + 8-symbol SFD', editable: false, - description: 'Synchronisation Header: receiver acquires symbol timing and detects "frame here". First-path-arrival timestamp is taken on the SFD.' + description: + 'Synchronisation Header: receiver acquires symbol timing and detects "frame here". First-path-arrival timestamp is taken on the SFD.' }, { name: 'PHR', bits: 19, value: overrides?.phr ?? 'len=12, RFRAME=1, rate=01 (6.81 Mbps)', editable: false, - description: 'PHY Header: 7-bit frame length, 1-bit ranging-frame flag (RFRAME), 2-bit data rate, 6-bit SECDED parity' + description: + 'PHY Header: 7-bit frame length, 1-bit ranging-frame flag (RFRAME), 2-bit data rate, 6-bit SECDED parity' }, { name: 'PSDU (data field)', @@ -86,7 +90,8 @@ export function createFiRaLayer( bits: 16, value: overrides?.round ?? 0x002a, editable: false, - description: 'Index of the ranging round within the session β€” increments per Poll/Response/Final triplet' + description: + 'Index of the ranging round within the session β€” increments per Poll/Response/Final triplet' }, { name: 'Frame Type', @@ -108,7 +113,8 @@ export function createFiRaLayer( bits: 16, value: overrides?.peer ?? 'Init=0x4321 β†’ Resp=0x1234', editable: false, - description: '16-bit short addresses of the initiator and responder for this ranging exchange' + description: + '16-bit short addresses of the initiator and responder for this ranging exchange' } ] }; diff --git a/src/lib/simulator/layers/websocket.ts b/src/lib/simulator/layers/websocket.ts index 7fb8e14..f42034c 100644 --- a/src/lib/simulator/layers/websocket.ts +++ b/src/lib/simulator/layers/websocket.ts @@ -1,6 +1,8 @@ import type { ProtocolLayer } from '../types'; -export function createWebSocketFrameLayer(overrides?: Partial<Record<string, string | number>>): ProtocolLayer { +export function createWebSocketFrameLayer( + overrides?: Partial<Record<string, string | number>> +): ProtocolLayer { return { name: 'WebSocket Frame', abbreviation: 'WS', diff --git a/src/lib/simulator/layers/wifi.ts b/src/lib/simulator/layers/wifi.ts index b0caac6..fd1d8f6 100644 --- a/src/lib/simulator/layers/wifi.ts +++ b/src/lib/simulator/layers/wifi.ts @@ -14,8 +14,7 @@ export function createWiFiLayer( bits: 16, value: overrides?.frameControl ?? '0x0841', editable: false, - description: - 'Frame type and control bits β€” Data (0x08), To DS, Protected Frame', + description: 'Frame type and control bits β€” Data (0x08), To DS, Protected Frame', color: '#F472B6' }, { @@ -31,8 +30,7 @@ export function createWiFiLayer( bits: 48, value: overrides?.addr1 ?? 'AA:BB:CC:DD:EE:FF', editable: true, - description: - 'Receiver Address β€” the immediate next recipient (usually the access point)' + description: 'Receiver Address β€” the immediate next recipient (usually the access point)' }, { name: 'Addr 2 (TA)', @@ -46,24 +44,21 @@ export function createWiFiLayer( bits: 48, value: overrides?.addr3 ?? 'CC:DD:EE:FF:00:11', editable: true, - description: - 'Destination Address β€” the final destination on the network' + description: 'Destination Address β€” the final destination on the network' }, { name: 'Seq Control', bits: 16, value: overrides?.seqControl ?? '0x0010', editable: false, - description: - 'Fragment and sequence number for reassembly and duplicate detection' + description: 'Fragment and sequence number for reassembly and duplicate detection' }, { name: 'Payload', bits: 0, value: overrides?.payload ?? '...', editable: false, - description: - 'Encrypted data payload (up to 2304 bytes with WPA2/3 encryption)' + description: 'Encrypted data payload (up to 2304 bytes with WPA2/3 encryption)' }, { name: 'FCS', diff --git a/src/lib/simulator/layers/wireguard.ts b/src/lib/simulator/layers/wireguard.ts index 6153864..28890d3 100644 --- a/src/lib/simulator/layers/wireguard.ts +++ b/src/lib/simulator/layers/wireguard.ts @@ -30,14 +30,16 @@ export function createWireGuardLayer( bits: 32, value: overrides?.senderIndex ?? '0xABCD1234', editable: false, - description: 'Random 32-bit identifier the receiver echoes back; lets peers track parallel handshakes' + description: + 'Random 32-bit identifier the receiver echoes back; lets peers track parallel handshakes' }, { name: 'Receiver Index', bits: 32, value: overrides?.receiverIndex ?? '0x00000000', editable: false, - description: 'Echoed back in Handshake Response and Transport Data; zero in the initial handshake' + description: + 'Echoed back in Handshake Response and Transport Data; zero in the initial handshake' }, { name: 'Payload', diff --git a/src/lib/simulator/layers/xmpp.ts b/src/lib/simulator/layers/xmpp.ts index ea4f71f..c5d3a04 100644 --- a/src/lib/simulator/layers/xmpp.ts +++ b/src/lib/simulator/layers/xmpp.ts @@ -14,8 +14,7 @@ export function createXMPPLayer( bits: 0, value: overrides?.stanzaType ?? '<stream:stream>', editable: false, - description: - 'XML element type β€” <stream:stream>, <message>, <presence>, <iq>, <auth>' + description: 'XML element type β€” <stream:stream>, <message>, <presence>, <iq>, <auth>' }, { name: 'From', @@ -30,8 +29,7 @@ export function createXMPPLayer( bits: 0, value: overrides?.to ?? '', editable: false, - description: - 'Recipient JID β€” the destination user, room, or service' + description: 'Recipient JID β€” the destination user, room, or service' }, { name: 'ID', diff --git a/src/lib/simulator/layers/zigbee.ts b/src/lib/simulator/layers/zigbee.ts index efaf1b5..1dcf5a5 100644 --- a/src/lib/simulator/layers/zigbee.ts +++ b/src/lib/simulator/layers/zigbee.ts @@ -15,7 +15,8 @@ export function create802154Layer( bits: 16, value: overrides?.frameControl ?? '0x8841 (Data, AckReq=1, PAN-ID Compression)', editable: false, - description: 'Frame type (Data/Ack/Cmd), security on/off, AckReq, frame version, addressing modes' + description: + 'Frame type (Data/Ack/Cmd), security on/off, AckReq, frame version, addressing modes' }, { name: 'Seq Num', @@ -86,7 +87,8 @@ export function createZigbeeNWKLayer( bits: 16, value: overrides?.dstAddr ?? '0x1234', editable: false, - description: 'NWK 16-bit short address β€” every node has a locally unique 16-bit address assigned at join' + description: + 'NWK 16-bit short address β€” every node has a locally unique 16-bit address assigned at join' }, { name: 'Src Addr', @@ -114,7 +116,8 @@ export function createZigbeeNWKLayer( bits: 0, value: overrides?.security ?? 'AES-CCM* (frame counter 0x000ABCDE, MIC=4 bytes)', editable: false, - description: 'AES-128-CCM* encryption + integrity using the network key; 4/8/16-byte MIC appended' + description: + 'AES-128-CCM* encryption + integrity using the network key; 4/8/16-byte MIC appended' }, { name: 'Payload (APS frame)', @@ -142,14 +145,16 @@ export function createZigbeeAPSLayer( bits: 8, value: overrides?.frameControl ?? '0x40 (Data, Unicast, no Ack)', editable: false, - description: 'Type (Data / Cmd / Ack), Delivery Mode (Unicast / Indirect / Broadcast / Group), Security, AckReq, Extended Hdr' + description: + 'Type (Data / Cmd / Ack), Delivery Mode (Unicast / Indirect / Broadcast / Group), Security, AckReq, Extended Hdr' }, { name: 'Dst Endpoint', bits: 8, value: overrides?.dstEp ?? 11, editable: false, - description: 'Endpoint within the destination device (1–240). Endpoint 11 is the standard Hue bulb endpoint.' + description: + 'Endpoint within the destination device (1–240). Endpoint 11 is the standard Hue bulb endpoint.' }, { name: 'Cluster ID', diff --git a/src/lib/simulator/simulations/a2a-task.ts b/src/lib/simulator/simulations/a2a-task.ts index 22b5e6f..c8f8f08 100644 --- a/src/lib/simulator/simulations/a2a-task.ts +++ b/src/lib/simulator/simulations/a2a-task.ts @@ -10,9 +10,21 @@ function httpRequestLayer(method: string, path: string, contentType: string) { osiLayer: 7, color: '#4B5563', headerFields: [ - { name: 'Method', bits: 0, value: method, editable: false, description: `HTTP ${method} β€” A2A uses standard HTTP as its transport` }, + { + name: 'Method', + bits: 0, + value: method, + editable: false, + description: `HTTP ${method} β€” A2A uses standard HTTP as its transport` + }, { name: 'Path', bits: 0, value: path, editable: false, description: 'A2A endpoint path' }, - { name: 'Content-Type', bits: 0, value: contentType, editable: false, description: 'Request content type' } + { + name: 'Content-Type', + bits: 0, + value: contentType, + editable: false, + description: 'Request content type' + } ] }; } @@ -24,10 +36,34 @@ function a2aRequestLayer(method: string, params: string, id: string | number) { osiLayer: 7, color: '#00D4FF', headerFields: [ - { name: 'Version', bits: 0, value: '"2.0"', editable: false, description: 'JSON-RPC protocol version β€” A2A uses JSON-RPC 2.0 as its wire format' }, - { name: 'Method', bits: 0, value: method, editable: false, description: 'A2A method to invoke on the remote agent' }, - { name: 'Params', bits: 0, value: params, editable: false, description: 'Method parameters as a JSON object' }, - { name: 'ID', bits: 0, value: String(id), editable: false, description: 'Request identifier β€” remote agent echoes this back to correlate the response' } + { + name: 'Version', + bits: 0, + value: '"2.0"', + editable: false, + description: 'JSON-RPC protocol version β€” A2A uses JSON-RPC 2.0 as its wire format' + }, + { + name: 'Method', + bits: 0, + value: method, + editable: false, + description: 'A2A method to invoke on the remote agent' + }, + { + name: 'Params', + bits: 0, + value: params, + editable: false, + description: 'Method parameters as a JSON object' + }, + { + name: 'ID', + bits: 0, + value: String(id), + editable: false, + description: 'Request identifier β€” remote agent echoes this back to correlate the response' + } ] }; } @@ -39,9 +75,28 @@ function a2aResponseLayer(result: string, id: string | number, color: string) { osiLayer: 7, color: '#00D4FF', headerFields: [ - { name: 'Version', bits: 0, value: '"2.0"', editable: false, description: 'JSON-RPC protocol version' }, - { name: 'Result', bits: 0, value: result, editable: false, description: 'Response payload from the remote agent', color }, - { name: 'ID', bits: 0, value: String(id), editable: false, description: 'Matches the request ID β€” confirms which call this responds to' } + { + name: 'Version', + bits: 0, + value: '"2.0"', + editable: false, + description: 'JSON-RPC protocol version' + }, + { + name: 'Result', + bits: 0, + value: result, + editable: false, + description: 'Response payload from the remote agent', + color + }, + { + name: 'ID', + bits: 0, + value: String(id), + editable: false, + description: 'Matches the request ID β€” confirms which call this responds to' + } ] }; } @@ -50,7 +105,7 @@ export const a2aTask: SimulationConfig = { protocolId: 'a2a', title: 'A2A β€” Agent Discovery & Task Lifecycle', description: - 'Watch an agent discover another agent and delegate a task. The client fetches the remote agent\'s card, sends a message, and receives streaming task updates β€” all using the Agent-to-Agent protocol.', + "Watch an agent discover another agent and delegate a task. The client fetches the remote agent's card, sends a message, and receives streaming task updates β€” all using the Agent-to-Agent protocol.", tier: 'client', actors: [ { id: 'client', label: 'Client Agent', icon: 'browser', position: 'left' }, @@ -70,7 +125,7 @@ export const a2aTask: SimulationConfig = { id: 'agent-card-request', label: 'Agent Card Request', description: - 'Client agent sends an HTTP GET to the well-known agent card endpoint. This is how agents discover each other β€” the card describes the remote agent\'s identity, skills, and capabilities.', + "Client agent sends an HTTP GET to the well-known agent card endpoint. This is how agents discover each other β€” the card describes the remote agent's identity, skills, and capabilities.", fromActor: 'client', toActor: 'remote', duration: 800, @@ -85,9 +140,28 @@ export const a2aTask: SimulationConfig = { osiLayer: 7, color: '#4B5563', headerFields: [ - { name: 'Method', bits: 0, value: 'GET', editable: false, description: 'HTTP GET β€” retrieving the agent\'s public card' }, - { name: 'Path', bits: 0, value: '/.well-known/agent.json', editable: false, description: 'Well-known URI for agent discovery β€” standardized path so clients know where to look' }, - { name: 'Accept', bits: 0, value: 'application/json', editable: false, description: 'Client expects a JSON agent card' } + { + name: 'Method', + bits: 0, + value: 'GET', + editable: false, + description: "HTTP GET β€” retrieving the agent's public card" + }, + { + name: 'Path', + bits: 0, + value: '/.well-known/agent.json', + editable: false, + description: + 'Well-known URI for agent discovery β€” standardized path so clients know where to look' + }, + { + name: 'Accept', + bits: 0, + value: 'application/json', + editable: false, + description: 'Client expects a JSON agent card' + } ] } ] @@ -111,8 +185,21 @@ export const a2aTask: SimulationConfig = { osiLayer: 7, color: '#4B5563', headerFields: [ - { name: 'Status', bits: 0, value: '200 OK', editable: false, description: 'Agent card found and returned', color: '#22c55e' }, - { name: 'Content-Type', bits: 0, value: 'application/json', editable: false, description: 'Agent card is JSON' } + { + name: 'Status', + bits: 0, + value: '200 OK', + editable: false, + description: 'Agent card found and returned', + color: '#22c55e' + }, + { + name: 'Content-Type', + bits: 0, + value: 'application/json', + editable: false, + description: 'Agent card is JSON' + } ] }, { @@ -121,11 +208,41 @@ export const a2aTask: SimulationConfig = { osiLayer: 7, color: '#00D4FF', headerFields: [ - { name: 'Name', bits: 0, value: '"TravelAgent"', editable: false, description: 'Human-readable agent name' }, - { name: 'Description', bits: 0, value: '"Books flights, hotels, and travel plans"', editable: false, description: 'What this agent can do' }, - { name: 'URL', bits: 0, value: '"https://travel.example.com/a2a"', editable: false, description: 'Endpoint for sending messages to this agent' }, - { name: 'Skills', bits: 0, value: '[{"id":"flight-search","name":"Flight Search"}]', editable: false, description: 'List of skills β€” each with an ID, name, and description' }, - { name: 'Version', bits: 0, value: '"0.2.1"', editable: false, description: 'A2A protocol version supported by this agent' } + { + name: 'Name', + bits: 0, + value: '"TravelAgent"', + editable: false, + description: 'Human-readable agent name' + }, + { + name: 'Description', + bits: 0, + value: '"Books flights, hotels, and travel plans"', + editable: false, + description: 'What this agent can do' + }, + { + name: 'URL', + bits: 0, + value: '"https://travel.example.com/a2a"', + editable: false, + description: 'Endpoint for sending messages to this agent' + }, + { + name: 'Skills', + bits: 0, + value: '[{"id":"flight-search","name":"Flight Search"}]', + editable: false, + description: 'List of skills β€” each with an ID, name, and description' + }, + { + name: 'Version', + bits: 0, + value: '"0.2.1"', + editable: false, + description: 'A2A protocol version supported by this agent' + } ] } ] @@ -144,7 +261,11 @@ export const a2aTask: SimulationConfig = { createIPv4Layer({ protocol: 6 }), createTCPLayer({ srcPort: 55100, dstPort: 443, flags: 'PSH,ACK' }), httpRequestLayer('POST', '/a2a', 'application/json'), - a2aRequestLayer('message/send', '{"message":{"role":"user","parts":[{"kind":"text","text":"Find flights NYC to London"}]}}', 1) + a2aRequestLayer( + 'message/send', + '{"message":{"role":"user","parts":[{"kind":"text","text":"Find flights NYC to London"}]}}', + 1 + ) ] }, { @@ -160,7 +281,11 @@ export const a2aTask: SimulationConfig = { createEthernetLayer({ srcMac: 'AA:BB:CC:DD:EE:FF', dstMac: '00:1A:2B:3C:4D:5E' }), createIPv4Layer({ srcIp: '93.184.216.34', dstIp: '192.168.1.100', protocol: 6 }), createTCPLayer({ srcPort: 443, dstPort: 55100, flags: 'PSH,ACK' }), - a2aResponseLayer('{"id":"task-001","status":{"state":"working","message":{"role":"agent","parts":[{"kind":"text","text":"Searching flights..."}]}}}', 1, '#eab308') + a2aResponseLayer( + '{"id":"task-001","status":{"state":"working","message":{"role":"agent","parts":[{"kind":"text","text":"Searching flights..."}]}}}', + 1, + '#eab308' + ) ] }, { @@ -176,7 +301,11 @@ export const a2aTask: SimulationConfig = { createEthernetLayer({ srcMac: 'AA:BB:CC:DD:EE:FF', dstMac: '00:1A:2B:3C:4D:5E' }), createIPv4Layer({ srcIp: '93.184.216.34', dstIp: '192.168.1.100', protocol: 6 }), createTCPLayer({ srcPort: 443, dstPort: 55100, flags: 'PSH,ACK' }), - a2aResponseLayer('{"id":"task-001","status":{"state":"completed"},"artifacts":[{"name":"flights","parts":[{"kind":"text","text":"BA115 JFKβ†’LHR 7pm $450"}]}]}', 1, '#22c55e') + a2aResponseLayer( + '{"id":"task-001","status":{"state":"completed"},"artifacts":[{"name":"flights","parts":[{"kind":"text","text":"BA115 JFKβ†’LHR 7pm $450"}]}]}', + 1, + '#22c55e' + ) ] }, { @@ -193,7 +322,11 @@ export const a2aTask: SimulationConfig = { createIPv4Layer({ protocol: 6 }), createTCPLayer({ srcPort: 55100, dstPort: 443, flags: 'PSH,ACK' }), httpRequestLayer('POST', '/a2a', 'application/json'), - a2aRequestLayer('message/stream', '{"message":{"role":"user","parts":[{"kind":"text","text":"Find flights NYC to London"}]}}', 2) + a2aRequestLayer( + 'message/stream', + '{"message":{"role":"user","parts":[{"kind":"text","text":"Find flights NYC to London"}]}}', + 2 + ) ] }, { @@ -215,7 +348,14 @@ export const a2aTask: SimulationConfig = { osiLayer: 7, color: '#4B5563', headerFields: [ - { name: 'Content-Type', bits: 0, value: 'text/event-stream', editable: false, description: 'Server-sent events β€” the server pushes updates over a long-lived HTTP connection' } + { + name: 'Content-Type', + bits: 0, + value: 'text/event-stream', + editable: false, + description: + 'Server-sent events β€” the server pushes updates over a long-lived HTTP connection' + } ] }, { @@ -224,9 +364,28 @@ export const a2aTask: SimulationConfig = { osiLayer: 7, color: '#00D4FF', headerFields: [ - { name: 'Event 1', bits: 0, value: '{"status":{"state":"working","message":"Searching..."}}', editable: false, description: 'First SSE event β€” task is now working' }, - { name: 'Event 2', bits: 0, value: '{"artifact":{"name":"flights","parts":[...],"append":true}}', editable: false, description: 'Artifact event β€” partial results streamed incrementally' }, - { name: 'Event 3', bits: 0, value: '{"status":{"state":"completed"},"final":true}', editable: false, description: 'Final event β€” task complete, stream closes', color: '#22c55e' } + { + name: 'Event 1', + bits: 0, + value: '{"status":{"state":"working","message":"Searching..."}}', + editable: false, + description: 'First SSE event β€” task is now working' + }, + { + name: 'Event 2', + bits: 0, + value: '{"artifact":{"name":"flights","parts":[...],"append":true}}', + editable: false, + description: 'Artifact event β€” partial results streamed incrementally' + }, + { + name: 'Event 3', + bits: 0, + value: '{"status":{"state":"completed"},"final":true}', + editable: false, + description: 'Final event β€” task complete, stream closes', + color: '#22c55e' + } ] } ] diff --git a/src/lib/simulator/simulations/amqp-messaging.ts b/src/lib/simulator/simulations/amqp-messaging.ts index b7b8988..d5d4924 100644 --- a/src/lib/simulator/simulations/amqp-messaging.ts +++ b/src/lib/simulator/simulations/amqp-messaging.ts @@ -157,7 +157,8 @@ export const amqpMessaging: SimulationConfig = { channel: 1, method: 'Basic.Deliver', payloadSize: 86, - properties: 'Consumer-Tag: ctag-1, Delivery-Tag: 1, Exchange: orders, Routing-Key: order.created', + properties: + 'Consumer-Tag: ctag-1, Delivery-Tag: 1, Exchange: orders, Routing-Key: order.created', payload: '{"event": "order.created", "orderId": "ORD-1234", "total": 59.99}' }) ] diff --git a/src/lib/simulator/simulations/arp-resolution.ts b/src/lib/simulator/simulations/arp-resolution.ts index aacc369..980bed8 100644 --- a/src/lib/simulator/simulations/arp-resolution.ts +++ b/src/lib/simulator/simulations/arp-resolution.ts @@ -58,7 +58,7 @@ export const arpResolution: SimulationConfig = { id: 'arp-reply', label: 'ARP Reply (unicast)', description: - 'Host B recognizes its own IP in the Target IP field and responds with a unicast ARP Reply. The reply fills in the missing piece: Sender MAC AA:BB:CC:DD:EE:FF. Notice this is unicast (directly to Host A\'s MAC), not broadcast β€” only Host A receives the reply. Host B also caches Host A\'s IP-to-MAC mapping from the request, since it will likely need it soon.', + "Host B recognizes its own IP in the Target IP field and responds with a unicast ARP Reply. The reply fills in the missing piece: Sender MAC AA:BB:CC:DD:EE:FF. Notice this is unicast (directly to Host A's MAC), not broadcast β€” only Host A receives the reply. Host B also caches Host A's IP-to-MAC mapping from the request, since it will likely need it soon.", fromActor: 'host-b', toActor: 'host-a', duration: 800, @@ -126,7 +126,7 @@ export const arpResolution: SimulationConfig = { id: 'response', label: 'Response (cache hit)', description: - 'Host B sends a response back to Host A. This time, no ARP is needed β€” Host B already cached Host A\'s MAC address when it processed the original ARP Request. This is a cache hit: the Ethernet frame is constructed immediately with the known destination MAC. Bidirectional communication now flows without any ARP overhead.', + "Host B sends a response back to Host A. This time, no ARP is needed β€” Host B already cached Host A's MAC address when it processed the original ARP Request. This is a cache hit: the Ethernet frame is constructed immediately with the known destination MAC. Bidirectional communication now flows without any ARP overhead.", fromActor: 'host-b', toActor: 'host-a', duration: 600, diff --git a/src/lib/simulator/simulations/bgp-peering.ts b/src/lib/simulator/simulations/bgp-peering.ts index 780737c..bcf2cc1 100644 --- a/src/lib/simulator/simulations/bgp-peering.ts +++ b/src/lib/simulator/simulations/bgp-peering.ts @@ -63,7 +63,7 @@ export const bgpPeering: SimulationConfig = { id: 'keepalive-a', label: 'KEEPALIVE', description: - 'Router A confirms the session parameters by sending a KEEPALIVE. This is the smallest possible BGP message β€” just the 19-byte header with no payload. The KEEPALIVE serves double duty: it confirms the OPEN exchange and starts the hold timer. If either peer doesn\'t hear from the other within the hold time, the session is torn down.', + "Router A confirms the session parameters by sending a KEEPALIVE. This is the smallest possible BGP message β€” just the 19-byte header with no payload. The KEEPALIVE serves double duty: it confirms the OPEN exchange and starts the hold timer. If either peer doesn't hear from the other within the hold time, the session is torn down.", fromActor: 'routerA', toActor: 'routerB', duration: 800, @@ -129,7 +129,7 @@ export const bgpPeering: SimulationConfig = { id: 'update-announce-b', label: 'UPDATE (announce)', description: - 'Router B announces its own networks in return. The AS_PATH now shows AS 65002, and the NEXT_HOP points to Router B\'s address. When Router A receives this, it knows that to reach 172.16.0.0/12, it should send traffic to 10.0.0.2. This is how the internet\'s routing table is built β€” one UPDATE at a time.', + "Router B announces its own networks in return. The AS_PATH now shows AS 65002, and the NEXT_HOP points to Router B's address. When Router A receives this, it knows that to reach 172.16.0.0/12, it should send traffic to 10.0.0.2. This is how the internet's routing table is built β€” one UPDATE at a time.", fromActor: 'routerB', toActor: 'routerA', duration: 1000, @@ -173,7 +173,7 @@ export const bgpPeering: SimulationConfig = { id: 'keepalive-periodic', label: 'KEEPALIVE', description: - 'BGP peers send periodic KEEPALIVEs (typically every 30 seconds) to prove they\'re still alive. If no message is received within the hold time (90 seconds), the peer is declared dead and all its routes are withdrawn. This is why BGP misconfiguration can cause massive internet outages β€” if a major ISP\'s session drops, thousands of routes disappear.', + "BGP peers send periodic KEEPALIVEs (typically every 30 seconds) to prove they're still alive. If no message is received within the hold time (90 seconds), the peer is declared dead and all its routes are withdrawn. This is why BGP misconfiguration can cause massive internet outages β€” if a major ISP's session drops, thousands of routes disappear.", fromActor: 'routerA', toActor: 'routerB', duration: 800, diff --git a/src/lib/simulator/simulations/bluetooth-ble.ts b/src/lib/simulator/simulations/bluetooth-ble.ts index d42b793..749a7ac 100644 --- a/src/lib/simulator/simulations/bluetooth-ble.ts +++ b/src/lib/simulator/simulations/bluetooth-ble.ts @@ -5,7 +5,7 @@ export const bluetoothBleGatt: SimulationConfig = { protocolId: 'bluetooth', title: 'BLE Connect, Pair, and GATT Read', description: - "Watch a phone (Central) discover a heart-rate sensor (Peripheral) on a BLE advertising channel, establish a connection, exchange MTU, pair with LE Secure Connections, and subscribe to notifications. This is the flow under every fitness tracker, AirTag, hearing aid, and Matter device commissioning over Bluetooth.", + 'Watch a phone (Central) discover a heart-rate sensor (Peripheral) on a BLE advertising channel, establish a connection, exchange MTU, pair with LE Secure Connections, and subscribe to notifications. This is the flow under every fitness tracker, AirTag, hearing aid, and Matter device commissioning over Bluetooth.', tier: 'client', actors: [ { id: 'central', label: 'Central (Phone)', icon: 'device', position: 'left' }, diff --git a/src/lib/simulator/simulations/cellular-registration.ts b/src/lib/simulator/simulations/cellular-registration.ts index 844a856..ef3736b 100644 --- a/src/lib/simulator/simulations/cellular-registration.ts +++ b/src/lib/simulator/simulations/cellular-registration.ts @@ -9,7 +9,7 @@ export const cellularRegistration: SimulationConfig = { protocolId: 'cellular', title: '5G Initial Registration + First PDU Session', description: - "Watch a phone power on and walk the 8 beats every 5G-SA UE walks every time it leaves airplane mode: RRC Setup β†’ Registration Request β†’ 5G-AKA β†’ Security Mode β†’ Registration Accept β†’ PDU Session Establishment β†’ UPF programming β†’ user plane up. Every NGAP and GTP-U hop is wrapped in IPsec ESP per 3GPP TS 33.501.", + 'Watch a phone power on and walk the 8 beats every 5G-SA UE walks every time it leaves airplane mode: RRC Setup β†’ Registration Request β†’ 5G-AKA β†’ Security Mode β†’ Registration Accept β†’ PDU Session Establishment β†’ UPF programming β†’ user plane up. Every NGAP and GTP-U hop is wrapped in IPsec ESP per 3GPP TS 33.501.', tier: 'client', actors: [ { id: 'ue', label: 'UE (phone)', icon: 'device', position: 'left' }, @@ -44,7 +44,7 @@ export const cellularRegistration: SimulationConfig = { id: 'rrc-setup', label: 'RRC Setup (random access)', description: - "UE selects a cell from SSB measurements and runs random access: PRACH preamble (Msg1) β†’ Random Access Response with timing advance + temporary C-RNTI (Msg2) β†’ RRCSetupRequest (Msg3) β†’ RRCSetup (Msg4). At this point the UE has SRB1 (signalling radio bearer) but no security context.", + 'UE selects a cell from SSB measurements and runs random access: PRACH preamble (Msg1) β†’ Random Access Response with timing advance + temporary C-RNTI (Msg2) β†’ RRCSetupRequest (Msg3) β†’ RRCSetup (Msg4). At this point the UE has SRB1 (signalling radio bearer) but no security context.', fromActor: 'ue', toActor: 'gnb', duration: 1300, @@ -62,14 +62,16 @@ export const cellularRegistration: SimulationConfig = { bits: 0, value: 'mo-Signalling', editable: false, - description: 'Why the UE wants a connection β€” signalling, data, voice, emergency, etc.' + description: + 'Why the UE wants a connection β€” signalling, data, voice, emergency, etc.' }, { name: 'C-RNTI', bits: 16, value: '0x4A2F', editable: false, - description: 'Cell Radio Network Temporary Identifier β€” the UE\'s short-lived ID in this cell' + description: + "Cell Radio Network Temporary Identifier β€” the UE's short-lived ID in this cell" }, { name: 'SRB1', @@ -86,7 +88,7 @@ export const cellularRegistration: SimulationConfig = { id: 'reg-req', label: 'Registration Request (NAS)', description: - 'UE sends a Registration Request over SRB1. The gNB doesn\'t look at the NAS payload β€” it just forwards it to the AMF inside an NGAP Initial UE Message on SCTP/38412 (wrapped in IPsec ESP). The Request carries the **SUCI** (public-key-encrypted SUPI), requested NSSAI, and UE security capabilities.', + "UE sends a Registration Request over SRB1. The gNB doesn't look at the NAS payload β€” it just forwards it to the AMF inside an NGAP Initial UE Message on SCTP/38412 (wrapped in IPsec ESP). The Request carries the **SUCI** (public-key-encrypted SUPI), requested NSSAI, and UE security capabilities.", fromActor: 'gnb', toActor: 'core', duration: 1400, @@ -112,7 +114,7 @@ export const cellularRegistration: SimulationConfig = { id: 'aka', label: '5G-AKA Authentication', description: - 'AMF asks AUSF β†’ AUSF asks UDM β†’ UDM\'s SIDF decrypts SUCI to SUPI, generates an authentication vector. RAND/AUTN traverse all the way down to the UE. The USIM checks AUTN.MAC against f1(K, SQN, RAND), computes RES* via KDF(CK β€– IK). AUSF compares RES* to HRES*. Mutual authentication.', + "AMF asks AUSF β†’ AUSF asks UDM β†’ UDM's SIDF decrypts SUCI to SUPI, generates an authentication vector. RAND/AUTN traverse all the way down to the UE. The USIM checks AUTN.MAC against f1(K, SQN, RAND), computes RES* via KDF(CK β€– IK). AUSF compares RES* to HRES*. Mutual authentication.", fromActor: 'core', toActor: 'ue', duration: 1500, @@ -136,7 +138,7 @@ export const cellularRegistration: SimulationConfig = { id: 'security-mode', label: 'NAS Security Mode Command', description: - "AMF picks ciphering (128-NEA2 = AES-CTR) and integrity (128-NIA2 = AES-CMAC). Sends Security Mode Command integrity-protected with the freshly-derived K_NASint. UE responds with Security Mode Complete ciphered+integrity-protected. From this point every NAS message is wrapped in `(Security Header, MAC, sequence)`.", + 'AMF picks ciphering (128-NEA2 = AES-CTR) and integrity (128-NIA2 = AES-CMAC). Sends Security Mode Command integrity-protected with the freshly-derived K_NASint. UE responds with Security Mode Complete ciphered+integrity-protected. From this point every NAS message is wrapped in `(Security Header, MAC, sequence)`.', fromActor: 'core', toActor: 'ue', duration: 1300, @@ -208,7 +210,7 @@ export const cellularRegistration: SimulationConfig = { id: 'pdu-session-accept', label: 'PDU Session Establishment Accept', description: - "SMF allocated the UE\'s [[ipv6|IPv6]] prefix from the pool, programmed PDR/FAR/QER/URR on the UPF, set up the N3 GTP-U tunnel TEID, and returned the allocated address + DNS servers back to the UE through the AMF. The gNB issues an RRCReconfiguration to map the QoS flow β†’ DRB. The DRB is now up.", + "SMF allocated the UE's [[ipv6|IPv6]] prefix from the pool, programmed PDR/FAR/QER/URR on the UPF, set up the N3 GTP-U tunnel TEID, and returned the allocated address + DNS servers back to the UE through the AMF. The gNB issues an RRCReconfiguration to map the QoS flow β†’ DRB. The DRB is now up.", fromActor: 'core', toActor: 'ue', duration: 1300, @@ -232,7 +234,7 @@ export const cellularRegistration: SimulationConfig = { id: 'user-plane', label: 'First user-plane packet (GTP-U on N3)', description: - "The N3 tunnel is up. First user-plane packet flows. UE sends an HTTPS request to 2606:4700:4700::1111 (Cloudflare DNS). The packet travels: UE β†’ gNB (radio) β†’ gNB wraps in GTP-U + IPsec ESP β†’ N3 to UPF β†’ UPF unwraps β†’ public internet. The encapsulation is *the* lesson of cellular protocol design.", + 'The N3 tunnel is up. First user-plane packet flows. UE sends an HTTPS request to 2606:4700:4700::1111 (Cloudflare DNS). The packet travels: UE β†’ gNB (radio) β†’ gNB wraps in GTP-U + IPsec ESP β†’ N3 to UPF β†’ UPF unwraps β†’ public internet. The encapsulation is *the* lesson of cellular protocol design.', fromActor: 'gnb', toActor: 'core', duration: 1500, diff --git a/src/lib/simulator/simulations/coap-request.ts b/src/lib/simulator/simulations/coap-request.ts index 038e7c9..8adf22f 100644 --- a/src/lib/simulator/simulations/coap-request.ts +++ b/src/lib/simulator/simulations/coap-request.ts @@ -100,7 +100,7 @@ export const coapRequest: SimulationConfig = { id: 'ack-changed', label: 'ACK 2.04 Changed', description: - 'The server confirms the resource was updated successfully. Code 2.04 Changed is the CoAP equivalent of HTTP 204 No Content. The empty payload is typical for update confirmations β€” the client already knows what it sent. CoAP\'s simplicity makes it ideal for battery-powered sensors.', + "The server confirms the resource was updated successfully. Code 2.04 Changed is the CoAP equivalent of HTTP 204 No Content. The empty payload is typical for update confirmations β€” the client already knows what it sent. CoAP's simplicity makes it ideal for battery-powered sensors.", fromActor: 'server', toActor: 'sensor', duration: 600, diff --git a/src/lib/simulator/simulations/dash-streaming.ts b/src/lib/simulator/simulations/dash-streaming.ts index c3c05d6..80267fc 100644 --- a/src/lib/simulator/simulations/dash-streaming.ts +++ b/src/lib/simulator/simulations/dash-streaming.ts @@ -11,8 +11,20 @@ function dashRequestLayer(path: string): ProtocolLayer { osiLayer: 7, color: '#00D4FF', headerFields: [ - { name: 'Method', bits: 0, value: 'GET', editable: false, description: 'DASH uses standard HTTP GET β€” fully CDN-compatible' }, - { name: 'Path', bits: 0, value: path, editable: false, description: 'Resource path β€” MPD manifest or media segment' } + { + name: 'Method', + bits: 0, + value: 'GET', + editable: false, + description: 'DASH uses standard HTTP GET β€” fully CDN-compatible' + }, + { + name: 'Path', + bits: 0, + value: path, + editable: false, + description: 'Resource path β€” MPD manifest or media segment' + } ] }; } @@ -24,8 +36,20 @@ function dashPayloadLayer(contentType: string, content: string): ProtocolLayer { osiLayer: 7, color: '#F472B6', headerFields: [ - { name: 'Content-Type', bits: 0, value: contentType, editable: false, description: 'MIME type β€” application/dash+xml for MPD, video/mp4 for segments' }, - { name: 'Content', bits: 0, value: content, editable: false, description: 'MPD manifest or CMAF/fMP4 segment data' } + { + name: 'Content-Type', + bits: 0, + value: contentType, + editable: false, + description: 'MIME type β€” application/dash+xml for MPD, video/mp4 for segments' + }, + { + name: 'Content', + bits: 0, + value: content, + editable: false, + description: 'MPD manifest or CMAF/fMP4 segment data' + } ] }; } @@ -45,7 +69,7 @@ export const dashStreaming: SimulationConfig = { id: 'mpd', label: 'GET MPD', description: - 'The player fetches the Media Presentation Description (MPD), an XML document that describes the entire stream structure. It lists Periods (timeline), Adaptation Sets (media types), and Representations (quality levels). The MPD is DASH\'s equivalent of HLS\'s master playlist.', + "The player fetches the Media Presentation Description (MPD), an XML document that describes the entire stream structure. It lists Periods (timeline), Adaptation Sets (media types), and Representations (quality levels). The MPD is DASH's equivalent of HLS's master playlist.", fromActor: 'player', toActor: 'cdn', duration: 800, @@ -54,9 +78,15 @@ export const dashStreaming: SimulationConfig = { createEthernetLayer(), createIPv4Layer({ protocol: 6 }), createTCPLayer({ srcPort: 53400, dstPort: 443, flags: 'PSH,ACK' }), - createTLSRecordLayer({ contentType: 'Application Data (23)', handshakeType: 'N/A (encrypted)' }), + createTLSRecordLayer({ + contentType: 'Application Data (23)', + handshakeType: 'N/A (encrypted)' + }), dashRequestLayer('/content/manifest.mpd'), - dashPayloadLayer('application/dash+xml', '<MPD> Period β†’ AdaptationSet(video) β†’ Rep 1080p@5Mbps, 720p@2.5Mbps, 480p@1Mbps') + dashPayloadLayer( + 'application/dash+xml', + '<MPD> Period β†’ AdaptationSet(video) β†’ Rep 1080p@5Mbps, 720p@2.5Mbps, 480p@1Mbps' + ) ] }, { @@ -72,7 +102,10 @@ export const dashStreaming: SimulationConfig = { createEthernetLayer({ srcMac: 'AA:BB:CC:DD:EE:FF', dstMac: '00:1A:2B:3C:4D:5E' }), createIPv4Layer({ srcIp: '93.184.216.34', dstIp: '192.168.1.100', protocol: 6 }), createTCPLayer({ srcPort: 443, dstPort: 53400, flags: 'PSH,ACK' }), - createTLSRecordLayer({ contentType: 'Application Data (23)', handshakeType: 'N/A (encrypted)' }), + createTLSRecordLayer({ + contentType: 'Application Data (23)', + handshakeType: 'N/A (encrypted)' + }), dashPayloadLayer('video/mp4', 'fMP4 init β€” moov box, H.264 codec config, 1080p, 24fps') ] }, @@ -89,7 +122,10 @@ export const dashStreaming: SimulationConfig = { createEthernetLayer(), createIPv4Layer({ protocol: 6 }), createTCPLayer({ srcPort: 53400, dstPort: 443, flags: 'PSH,ACK' }), - createTLSRecordLayer({ contentType: 'Application Data (23)', handshakeType: 'N/A (encrypted)' }), + createTLSRecordLayer({ + contentType: 'Application Data (23)', + handshakeType: 'N/A (encrypted)' + }), dashRequestLayer('/content/video/1080p/seg-1.m4s'), dashPayloadLayer('video/mp4', 'fMP4 segment β€” 4.0s, 1080p, H.264, 2.5 MB') ] @@ -107,7 +143,10 @@ export const dashStreaming: SimulationConfig = { createEthernetLayer(), createIPv4Layer({ protocol: 6 }), createTCPLayer({ srcPort: 53400, dstPort: 443, flags: 'PSH,ACK' }), - createTLSRecordLayer({ contentType: 'Application Data (23)', handshakeType: 'N/A (encrypted)' }), + createTLSRecordLayer({ + contentType: 'Application Data (23)', + handshakeType: 'N/A (encrypted)' + }), dashRequestLayer('/content/video/720p/seg-2.m4s'), dashPayloadLayer('video/mp4', 'fMP4 segment β€” 4.0s, 720p, H.264, 1.2 MB (ABR switch)') ] diff --git a/src/lib/simulator/simulations/dhcp-dora.ts b/src/lib/simulator/simulations/dhcp-dora.ts index 80ff7f2..60a447d 100644 --- a/src/lib/simulator/simulations/dhcp-dora.ts +++ b/src/lib/simulator/simulations/dhcp-dora.ts @@ -65,7 +65,7 @@ export const dhcpDora: SimulationConfig = { id: 'request', label: 'REQUEST', description: - 'The device broadcasts its acceptance of a specific server\'s offer. This broadcast ensures that all DHCP servers on the network know which offer was chosen, so declined servers can return their proposed addresses to their pools.', + "The device broadcasts its acceptance of a specific server's offer. This broadcast ensures that all DHCP servers on the network know which offer was chosen, so declined servers can return their proposed addresses to their pools.", fromActor: 'client', toActor: 'server', duration: 1000, diff --git a/src/lib/simulator/simulations/dns-resolution.ts b/src/lib/simulator/simulations/dns-resolution.ts index 1fb508e..9b6c034 100644 --- a/src/lib/simulator/simulations/dns-resolution.ts +++ b/src/lib/simulator/simulations/dns-resolution.ts @@ -14,13 +14,43 @@ function dnsQueryLayers(srcIp: string, dstIp: string) { osiLayer: 7, color: '#2DD4BF', headerFields: [ - { name: 'ID', bits: 16, value: '0xA1B2', editable: false, description: 'Transaction ID β€” matches queries to responses' }, + { + name: 'ID', + bits: 16, + value: '0xA1B2', + editable: false, + description: 'Transaction ID β€” matches queries to responses' + }, { name: 'QR', bits: 1, value: 0, editable: false, description: '0 = Query, 1 = Response' }, { name: 'Opcode', bits: 4, value: 0, editable: false, description: '0 = Standard query' }, - { name: 'RD', bits: 1, value: 1, editable: false, description: 'Recursion Desired β€” ask the resolver to recurse on our behalf' }, - { name: 'QDCount', bits: 16, value: 1, editable: false, description: 'Number of questions β€” we are asking about one domain' }, - { name: 'QNAME', bits: 0, value: 'example.com', editable: false, description: 'The domain name we want to resolve' }, - { name: 'QTYPE', bits: 16, value: 'A', editable: false, description: 'Query type A β€” requesting an IPv4 address' } + { + name: 'RD', + bits: 1, + value: 1, + editable: false, + description: 'Recursion Desired β€” ask the resolver to recurse on our behalf' + }, + { + name: 'QDCount', + bits: 16, + value: 1, + editable: false, + description: 'Number of questions β€” we are asking about one domain' + }, + { + name: 'QNAME', + bits: 0, + value: 'example.com', + editable: false, + description: 'The domain name we want to resolve' + }, + { + name: 'QTYPE', + bits: 16, + value: 'A', + editable: false, + description: 'Query type A β€” requesting an IPv4 address' + } ] } ]; @@ -37,14 +67,57 @@ function dnsResponseLayers(srcIp: string, dstIp: string, answer: string) { osiLayer: 7, color: '#2DD4BF', headerFields: [ - { name: 'ID', bits: 16, value: '0xA1B2', editable: false, description: 'Same transaction ID β€” matches our query' }, + { + name: 'ID', + bits: 16, + value: '0xA1B2', + editable: false, + description: 'Same transaction ID β€” matches our query' + }, { name: 'QR', bits: 1, value: 1, editable: false, description: '1 = Response' }, - { name: 'AA', bits: 1, value: 1, editable: false, description: 'Authoritative Answer β€” this server owns the domain' }, - { name: 'ANCount', bits: 16, value: 1, editable: false, description: 'Number of answer records' }, - { name: 'NAME', bits: 0, value: 'example.com', editable: false, description: 'The domain name we asked about' }, - { name: 'TYPE', bits: 16, value: 'A', editable: false, description: 'Answer type β€” A record (IPv4 address)' }, - { name: 'TTL', bits: 32, value: 3600, editable: false, description: 'Time to live β€” cache this answer for 3600 seconds (1 hour)' }, - { name: 'RDATA', bits: 32, value: answer, editable: false, description: 'The resolved IPv4 address', color: '#2DD4BF' } + { + name: 'AA', + bits: 1, + value: 1, + editable: false, + description: 'Authoritative Answer β€” this server owns the domain' + }, + { + name: 'ANCount', + bits: 16, + value: 1, + editable: false, + description: 'Number of answer records' + }, + { + name: 'NAME', + bits: 0, + value: 'example.com', + editable: false, + description: 'The domain name we asked about' + }, + { + name: 'TYPE', + bits: 16, + value: 'A', + editable: false, + description: 'Answer type β€” A record (IPv4 address)' + }, + { + name: 'TTL', + bits: 32, + value: 3600, + editable: false, + description: 'Time to live β€” cache this answer for 3600 seconds (1 hour)' + }, + { + name: 'RDATA', + bits: 32, + value: answer, + editable: false, + description: 'The resolved IPv4 address', + color: '#2DD4BF' + } ] } ]; @@ -97,7 +170,7 @@ export const dnsResolution: SimulationConfig = { id: 'root-referral', label: 'Root Referral', description: - 'The root nameserver doesn\'t know example.com, but it knows who handles all .com domains. It responds with a referral to the .com TLD nameserver.', + "The root nameserver doesn't know example.com, but it knows who handles all .com domains. It responds with a referral to the .com TLD nameserver.", fromActor: 'nameserver', toActor: 'resolver', duration: 1000, diff --git a/src/lib/simulator/simulations/ethernet-frame.ts b/src/lib/simulator/simulations/ethernet-frame.ts index 5210862..55223f4 100644 --- a/src/lib/simulator/simulations/ethernet-frame.ts +++ b/src/lib/simulator/simulations/ethernet-frame.ts @@ -67,7 +67,7 @@ export const ethernetFrame: SimulationConfig = { id: 'arp-reply', label: 'ARP Reply (unicast)', description: - 'Host B recognizes its own IP (192.168.1.50) in the ARP Request and sends a unicast ARP Reply directly to Host A\'s MAC. The reply contains Host B\'s MAC address AA:BB:CC:DD:EE:FF, which is the information Host A was looking for. This is unicast β€” only the requesting host receives it.', + "Host B recognizes its own IP (192.168.1.50) in the ARP Request and sends a unicast ARP Reply directly to Host A's MAC. The reply contains Host B's MAC address AA:BB:CC:DD:EE:FF, which is the information Host A was looking for. This is unicast β€” only the requesting host receives it.", fromActor: 'host-b', toActor: 'host-a', duration: 800, @@ -91,7 +91,7 @@ export const ethernetFrame: SimulationConfig = { id: 'data-frame', label: 'Data Frame (Host A β†’ Switch)', description: - 'Now that Host A knows Host B\'s MAC, it constructs a proper Ethernet frame with the correct destination MAC AA:BB:CC:DD:EE:FF. The EtherType reverts to 0x0800 (IPv4) since this is a regular data packet. The IP payload is encapsulated inside the Ethernet frame β€” this is Layer 2 encapsulation of a Layer 3 packet.', + "Now that Host A knows Host B's MAC, it constructs a proper Ethernet frame with the correct destination MAC AA:BB:CC:DD:EE:FF. The EtherType reverts to 0x0800 (IPv4) since this is a regular data packet. The IP payload is encapsulated inside the Ethernet frame β€” this is Layer 2 encapsulation of a Layer 3 packet.", fromActor: 'host-a', toActor: 'switch', duration: 600, @@ -111,7 +111,7 @@ export const ethernetFrame: SimulationConfig = { id: 'switch-forward', label: 'Switch Forwards to Host B', description: - 'The switch looks up destination MAC AA:BB:CC:DD:EE:FF in its forwarding table and finds a match β€” it learned this MAC when Host B sent the ARP Reply. Instead of flooding, the switch forwards the frame only to Host B\'s port. This is the efficiency of a switch over a hub: unicast traffic stays on the relevant port.', + "The switch looks up destination MAC AA:BB:CC:DD:EE:FF in its forwarding table and finds a match β€” it learned this MAC when Host B sent the ARP Reply. Instead of flooding, the switch forwards the frame only to Host B's port. This is the efficiency of a switch over a hub: unicast traffic stays on the relevant port.", fromActor: 'switch', toActor: 'host-b', duration: 600, @@ -131,7 +131,7 @@ export const ethernetFrame: SimulationConfig = { id: 'response-frame', label: 'Response Frame (Host B β†’ Switch)', description: - 'Host B processes the received data and sends a response back. The Ethernet frame has swapped source and destination MACs β€” Host B\'s MAC is now the source, Host A\'s MAC is the destination. The switch already has both MACs in its forwarding table, so this frame will be switched efficiently.', + "Host B processes the received data and sends a response back. The Ethernet frame has swapped source and destination MACs β€” Host B's MAC is now the source, Host A's MAC is the destination. The switch already has both MACs in its forwarding table, so this frame will be switched efficiently.", fromActor: 'host-b', toActor: 'switch', duration: 600, @@ -151,7 +151,7 @@ export const ethernetFrame: SimulationConfig = { id: 'response-forward', label: 'Switch Forwards to Host A', description: - 'The switch forwards the response directly to Host A\'s port using its learned MAC table entry. Both directions are now fully learned β€” no more flooding is needed for traffic between these two hosts. The forwarding table entries will age out after a timeout (typically 300 seconds) if no traffic is seen.', + "The switch forwards the response directly to Host A's port using its learned MAC table entry. Both directions are now fully learned β€” no more flooding is needed for traffic between these two hosts. The forwarding table entries will age out after a timeout (typically 300 seconds) if no traffic is seen.", fromActor: 'switch', toActor: 'host-a', duration: 600, diff --git a/src/lib/simulator/simulations/ftp-transfer.ts b/src/lib/simulator/simulations/ftp-transfer.ts index 503cb5c..ba05381 100644 --- a/src/lib/simulator/simulations/ftp-transfer.ts +++ b/src/lib/simulator/simulations/ftp-transfer.ts @@ -94,7 +94,7 @@ export const ftpTransfer: SimulationConfig = { id: 'pass', label: 'PASS', description: - 'The client sends the password. On success, the server responds with 230 (User logged in). FTP\'s plain-text credentials are a well-known security weakness, which is why modern file transfer uses SFTP or FTPS with TLS encryption.', + "The client sends the password. On success, the server responds with 230 (User logged in). FTP's plain-text credentials are a well-known security weakness, which is why modern file transfer uses SFTP or FTPS with TLS encryption.", fromActor: 'client', toActor: 'server', duration: 800, diff --git a/src/lib/simulator/simulations/graphql-operation.ts b/src/lib/simulator/simulations/graphql-operation.ts index 59f6ec2..a8081c6 100644 --- a/src/lib/simulator/simulations/graphql-operation.ts +++ b/src/lib/simulator/simulations/graphql-operation.ts @@ -4,32 +4,100 @@ import { createIPv4Layer } from '../layers/ipv4'; import { createEthernetLayer } from '../layers/ethernet'; import { createTLSRecordLayer } from '../layers/tls'; -function gqlRequestLayer(operation: string, name: string, variables: string, selectionSet: string): ProtocolLayer { +function gqlRequestLayer(): ProtocolLayer { return { name: 'HTTP Request', abbreviation: 'HTTP', osiLayer: 7, color: '#00D4FF', headerFields: [ - { name: 'Method', bits: 0, value: 'POST', editable: false, description: 'GraphQL always uses POST β€” the query is in the request body, not the URL' }, - { name: 'Path', bits: 0, value: '/graphql', editable: false, description: 'Single endpoint β€” unlike REST, all operations go to the same URL' }, - { name: 'Content-Type', bits: 0, value: 'application/json', editable: false, description: 'GraphQL request bodies are JSON-encoded' } + { + name: 'Method', + bits: 0, + value: 'POST', + editable: false, + description: 'GraphQL always uses POST β€” the query is in the request body, not the URL' + }, + { + name: 'Path', + bits: 0, + value: '/graphql', + editable: false, + description: 'Single endpoint β€” unlike REST, all operations go to the same URL' + }, + { + name: 'Content-Type', + bits: 0, + value: 'application/json', + editable: false, + description: 'GraphQL request bodies are JSON-encoded' + } ] }; } -function gqlLayer(operation: string, name: string, variables: string, selectionSet: string, responseData: string): ProtocolLayer { +function gqlLayer( + operation: string, + name: string, + variables: string, + selectionSet: string, + responseData: string +): ProtocolLayer { return { name: 'GraphQL Operation', abbreviation: 'GQL', osiLayer: 7, color: '#E535AB', headerFields: [ - { name: 'Operation', bits: 0, value: operation, editable: false, description: 'GraphQL operation type β€” query (read), mutation (write), or subscription (stream)' }, - { name: 'Name', bits: 0, value: name, editable: false, description: 'Operation name β€” used for debugging and server-side logging' }, - ...(variables ? [{ name: 'Variables', bits: 0, value: variables, editable: false, description: 'Variables passed to the operation β€” typed inputs that parameterize the query' }] : []), - ...(selectionSet ? [{ name: 'Selection Set', bits: 0, value: selectionSet, editable: false, description: 'The fields requested β€” determines the exact shape of the response' }] : []), - ...(responseData ? [{ name: 'Response Data', bits: 0, value: responseData, editable: false, description: 'JSON response body β€” mirrors the selection set structure exactly' }] : []) + { + name: 'Operation', + bits: 0, + value: operation, + editable: false, + description: + 'GraphQL operation type β€” query (read), mutation (write), or subscription (stream)' + }, + { + name: 'Name', + bits: 0, + value: name, + editable: false, + description: 'Operation name β€” used for debugging and server-side logging' + }, + ...(variables + ? [ + { + name: 'Variables', + bits: 0, + value: variables, + editable: false, + description: + 'Variables passed to the operation β€” typed inputs that parameterize the query' + } + ] + : []), + ...(selectionSet + ? [ + { + name: 'Selection Set', + bits: 0, + value: selectionSet, + editable: false, + description: 'The fields requested β€” determines the exact shape of the response' + } + ] + : []), + ...(responseData + ? [ + { + name: 'Response Data', + bits: 0, + value: responseData, + editable: false, + description: 'JSON response body β€” mirrors the selection set structure exactly' + } + ] + : []) ] }; } @@ -41,8 +109,22 @@ function gqlResponseLayer(status: string): ProtocolLayer { osiLayer: 7, color: '#00D4FF', headerFields: [ - { name: 'Status', bits: 0, value: status, editable: false, description: 'GraphQL always returns 200 β€” errors are in the response body, not HTTP status codes', color: '#22c55e' }, - { name: 'Content-Type', bits: 0, value: 'application/json', editable: false, description: 'Response body is JSON with data and/or errors fields' } + { + name: 'Status', + bits: 0, + value: status, + editable: false, + description: + 'GraphQL always returns 200 β€” errors are in the response body, not HTTP status codes', + color: '#22c55e' + }, + { + name: 'Content-Type', + bits: 0, + value: 'application/json', + editable: false, + description: 'Response body is JSON with data and/or errors fields' + } ] }; } @@ -80,9 +162,18 @@ export const graphqlOperation: SimulationConfig = { createEthernetLayer(), createIPv4Layer({ protocol: 6 }), createTCPLayer({ srcPort: 52400, dstPort: 443, flags: 'PSH,ACK' }), - createTLSRecordLayer({ contentType: 'Application Data (23)', handshakeType: 'N/A (encrypted)' }), - gqlRequestLayer('query', 'GetUser', '{ "id": "42" }', '{ user { name email } }'), - gqlLayer('query', 'GetUser', '{ "id": "42" }', '{ user(id: $id) { name email posts { title } } }', '') + createTLSRecordLayer({ + contentType: 'Application Data (23)', + handshakeType: 'N/A (encrypted)' + }), + gqlRequestLayer(), + gqlLayer( + 'query', + 'GetUser', + '{ "id": "42" }', + '{ user(id: $id) { name email posts { title } } }', + '' + ) ] }, { @@ -98,9 +189,18 @@ export const graphqlOperation: SimulationConfig = { createEthernetLayer({ srcMac: 'AA:BB:CC:DD:EE:FF', dstMac: '00:1A:2B:3C:4D:5E' }), createIPv4Layer({ srcIp: '93.184.216.34', dstIp: '192.168.1.100', protocol: 6 }), createTCPLayer({ srcPort: 443, dstPort: 52400, flags: 'PSH,ACK' }), - createTLSRecordLayer({ contentType: 'Application Data (23)', handshakeType: 'N/A (encrypted)' }), + createTLSRecordLayer({ + contentType: 'Application Data (23)', + handshakeType: 'N/A (encrypted)' + }), gqlResponseLayer('200 OK'), - gqlLayer('query', 'GetUser', '', '', '{ user: { name: "Alice", email: "alice@...", posts: [{ title: "Getting Started" }] } }') + gqlLayer( + 'query', + 'GetUser', + '', + '', + '{ user: { name: "Alice", email: "alice@...", posts: [{ title: "Getting Started" }] } }' + ) ] }, { @@ -116,9 +216,18 @@ export const graphqlOperation: SimulationConfig = { createEthernetLayer(), createIPv4Layer({ protocol: 6 }), createTCPLayer({ srcPort: 52400, dstPort: 443, flags: 'PSH,ACK' }), - createTLSRecordLayer({ contentType: 'Application Data (23)', handshakeType: 'N/A (encrypted)' }), - gqlRequestLayer('mutation', 'CreatePost', '{ "title": "New Post" }', '{ createPost { id title } }'), - gqlLayer('mutation', 'CreatePost', '{ "title": "New Post", "authorId": "42" }', '{ createPost(input: $input) { id title author { name } } }', '') + createTLSRecordLayer({ + contentType: 'Application Data (23)', + handshakeType: 'N/A (encrypted)' + }), + gqlRequestLayer(), + gqlLayer( + 'mutation', + 'CreatePost', + '{ "title": "New Post", "authorId": "42" }', + '{ createPost(input: $input) { id title author { name } } }', + '' + ) ] }, { @@ -134,9 +243,18 @@ export const graphqlOperation: SimulationConfig = { createEthernetLayer({ srcMac: 'AA:BB:CC:DD:EE:FF', dstMac: '00:1A:2B:3C:4D:5E' }), createIPv4Layer({ srcIp: '93.184.216.34', dstIp: '192.168.1.100', protocol: 6 }), createTCPLayer({ srcPort: 443, dstPort: 52400, flags: 'PSH,ACK' }), - createTLSRecordLayer({ contentType: 'Application Data (23)', handshakeType: 'N/A (encrypted)' }), + createTLSRecordLayer({ + contentType: 'Application Data (23)', + handshakeType: 'N/A (encrypted)' + }), gqlResponseLayer('200 OK'), - gqlLayer('mutation', 'CreatePost', '', '', '{ createPost: { id: "99", title: "New Post", author: { name: "Alice" } } }') + gqlLayer( + 'mutation', + 'CreatePost', + '', + '', + '{ createPost: { id: "99", title: "New Post", author: { name: "Alice" } } }' + ) ] } ] diff --git a/src/lib/simulator/simulations/hls-streaming.ts b/src/lib/simulator/simulations/hls-streaming.ts index b73b511..693d58a 100644 --- a/src/lib/simulator/simulations/hls-streaming.ts +++ b/src/lib/simulator/simulations/hls-streaming.ts @@ -11,9 +11,27 @@ function hlsRequestLayer(path: string, accept: string): ProtocolLayer { osiLayer: 7, color: '#00D4FF', headerFields: [ - { name: 'Method', bits: 0, value: 'GET', editable: false, description: 'HLS uses standard HTTP GET β€” works through any CDN and proxy' }, - { name: 'Path', bits: 0, value: path, editable: false, description: 'Resource path β€” playlist manifest or media segment' }, - { name: 'Accept', bits: 0, value: accept, editable: false, description: 'Expected content type for the response' } + { + name: 'Method', + bits: 0, + value: 'GET', + editable: false, + description: 'HLS uses standard HTTP GET β€” works through any CDN and proxy' + }, + { + name: 'Path', + bits: 0, + value: path, + editable: false, + description: 'Resource path β€” playlist manifest or media segment' + }, + { + name: 'Accept', + bits: 0, + value: accept, + editable: false, + description: 'Expected content type for the response' + } ] }; } @@ -25,8 +43,21 @@ function hlsResponseLayer(contentType: string, body: string): ProtocolLayer { osiLayer: 7, color: '#3B82F6', headerFields: [ - { name: 'Content-Type', bits: 0, value: contentType, editable: false, description: 'MIME type β€” application/vnd.apple.mpegurl for playlists, video/MP2T for segments' }, - { name: 'Content', bits: 0, value: body, editable: false, description: 'Playlist directives or media segment data' } + { + name: 'Content-Type', + bits: 0, + value: contentType, + editable: false, + description: + 'MIME type β€” application/vnd.apple.mpegurl for playlists, video/MP2T for segments' + }, + { + name: 'Content', + bits: 0, + value: body, + editable: false, + description: 'Playlist directives or media segment data' + } ] }; } @@ -55,7 +86,10 @@ export const hlsStreaming: SimulationConfig = { createEthernetLayer(), createIPv4Layer({ protocol: 6 }), createTCPLayer({ srcPort: 53100, dstPort: 443, flags: 'PSH,ACK' }), - createTLSRecordLayer({ contentType: 'Application Data (23)', handshakeType: 'N/A (encrypted)' }), + createTLSRecordLayer({ + contentType: 'Application Data (23)', + handshakeType: 'N/A (encrypted)' + }), hlsRequestLayer('/live/stream.m3u8', 'application/vnd.apple.mpegurl') ] }, @@ -72,8 +106,14 @@ export const hlsStreaming: SimulationConfig = { createEthernetLayer({ srcMac: 'AA:BB:CC:DD:EE:FF', dstMac: '00:1A:2B:3C:4D:5E' }), createIPv4Layer({ srcIp: '93.184.216.34', dstIp: '192.168.1.100', protocol: 6 }), createTCPLayer({ srcPort: 443, dstPort: 53100, flags: 'PSH,ACK' }), - createTLSRecordLayer({ contentType: 'Application Data (23)', handshakeType: 'N/A (encrypted)' }), - hlsResponseLayer('application/vnd.apple.mpegurl', '#EXTM3U, #EXT-X-TARGETDURATION:6, #EXTINF:6.0, seg001.ts, seg002.ts, seg003.ts') + createTLSRecordLayer({ + contentType: 'Application Data (23)', + handshakeType: 'N/A (encrypted)' + }), + hlsResponseLayer( + 'application/vnd.apple.mpegurl', + '#EXTM3U, #EXT-X-TARGETDURATION:6, #EXTINF:6.0, seg001.ts, seg002.ts, seg003.ts' + ) ] }, { @@ -89,7 +129,10 @@ export const hlsStreaming: SimulationConfig = { createEthernetLayer(), createIPv4Layer({ protocol: 6 }), createTCPLayer({ srcPort: 53100, dstPort: 443, flags: 'PSH,ACK' }), - createTLSRecordLayer({ contentType: 'Application Data (23)', handshakeType: 'N/A (encrypted)' }), + createTLSRecordLayer({ + contentType: 'Application Data (23)', + handshakeType: 'N/A (encrypted)' + }), hlsRequestLayer('/live/720p/seg001.ts', 'video/MP2T'), hlsResponseLayer('video/MP2T', 'MPEG-TS segment β€” 6.0s, 720p, H.264+AAC, 1.2 MB') ] @@ -107,7 +150,10 @@ export const hlsStreaming: SimulationConfig = { createEthernetLayer(), createIPv4Layer({ protocol: 6 }), createTCPLayer({ srcPort: 53100, dstPort: 443, flags: 'PSH,ACK' }), - createTLSRecordLayer({ contentType: 'Application Data (23)', handshakeType: 'N/A (encrypted)' }), + createTLSRecordLayer({ + contentType: 'Application Data (23)', + handshakeType: 'N/A (encrypted)' + }), hlsRequestLayer('/live/720p/seg002.ts', 'video/MP2T'), hlsResponseLayer('video/MP2T', 'MPEG-TS segment β€” 6.0s, 720p, H.264+AAC, 1.1 MB') ] diff --git a/src/lib/simulator/simulations/http-request.ts b/src/lib/simulator/simulations/http-request.ts index f17861b..4c4ff43 100644 --- a/src/lib/simulator/simulations/http-request.ts +++ b/src/lib/simulator/simulations/http-request.ts @@ -48,8 +48,7 @@ export const httpRequest: SimulationConfig = { { id: 'tcp-synack', label: 'TCP SYN-ACK', - description: - 'Server responds with SYN-ACK, agreeing to establish the connection.', + description: 'Server responds with SYN-ACK, agreeing to establish the connection.', fromActor: 'server', toActor: 'browser', duration: 800, @@ -95,12 +94,48 @@ export const httpRequest: SimulationConfig = { osiLayer: 7, color: '#00D4FF', headerFields: [ - { name: 'Method', bits: 0, value: 'GET', editable: false, description: 'HTTP method β€” what action to perform' }, - { name: 'Path', bits: 0, value: '/index.html', editable: false, description: 'Resource path on the server' }, - { name: 'Version', bits: 0, value: 'HTTP/1.1', editable: false, description: 'Protocol version' }, - { name: 'Host', bits: 0, value: 'example.com', editable: false, description: 'Host header β€” which server to contact' }, - { name: 'Accept', bits: 0, value: 'text/html', editable: false, description: 'What content types the browser accepts' }, - { name: 'Connection', bits: 0, value: 'keep-alive', editable: false, description: 'Keep the TCP connection open for more requests' } + { + name: 'Method', + bits: 0, + value: 'GET', + editable: false, + description: 'HTTP method β€” what action to perform' + }, + { + name: 'Path', + bits: 0, + value: '/index.html', + editable: false, + description: 'Resource path on the server' + }, + { + name: 'Version', + bits: 0, + value: 'HTTP/1.1', + editable: false, + description: 'Protocol version' + }, + { + name: 'Host', + bits: 0, + value: 'example.com', + editable: false, + description: 'Host header β€” which server to contact' + }, + { + name: 'Accept', + bits: 0, + value: 'text/html', + editable: false, + description: 'What content types the browser accepts' + }, + { + name: 'Connection', + bits: 0, + value: 'keep-alive', + editable: false, + description: 'Keep the TCP connection open for more requests' + } ] } ] @@ -116,7 +151,12 @@ export const httpRequest: SimulationConfig = { highlight: ['Status', 'Content-Type'], layers: [ createEthernetLayer({ srcMac: 'AA:BB:CC:DD:EE:FF', dstMac: '00:1A:2B:3C:4D:5E' }), - createIPv4Layer({ srcIp: '93.184.216.34', dstIp: '192.168.1.100', protocol: 6, totalLength: 1420 }), + createIPv4Layer({ + srcIp: '93.184.216.34', + dstIp: '192.168.1.100', + protocol: 6, + totalLength: 1420 + }), createTCPLayer({ srcPort: 80, dstPort: 52000, seq: 301, ack: 321, flags: 'PSH,ACK' }), { name: 'HTTP Response', @@ -124,11 +164,42 @@ export const httpRequest: SimulationConfig = { osiLayer: 7, color: '#00D4FF', headerFields: [ - { name: 'Version', bits: 0, value: 'HTTP/1.1', editable: false, description: 'Protocol version' }, - { name: 'Status', bits: 0, value: '200 OK', editable: false, description: 'Success β€” the resource was found and returned', color: '#22c55e' }, - { name: 'Content-Type', bits: 0, value: 'text/html', editable: false, description: 'MIME type of the response body' }, - { name: 'Content-Length', bits: 0, value: '1256', editable: false, description: 'Size of the response body in bytes' }, - { name: 'Body', bits: 0, value: '<html>...</html>', editable: false, description: 'The HTML content of the page' } + { + name: 'Version', + bits: 0, + value: 'HTTP/1.1', + editable: false, + description: 'Protocol version' + }, + { + name: 'Status', + bits: 0, + value: '200 OK', + editable: false, + description: 'Success β€” the resource was found and returned', + color: '#22c55e' + }, + { + name: 'Content-Type', + bits: 0, + value: 'text/html', + editable: false, + description: 'MIME type of the response body' + }, + { + name: 'Content-Length', + bits: 0, + value: '1256', + editable: false, + description: 'Size of the response body in bytes' + }, + { + name: 'Body', + bits: 0, + value: '<html>...</html>', + editable: false, + description: 'The HTML content of the page' + } ] } ] diff --git a/src/lib/simulator/simulations/imap-session.ts b/src/lib/simulator/simulations/imap-session.ts index 279029a..2e74557 100644 --- a/src/lib/simulator/simulations/imap-session.ts +++ b/src/lib/simulator/simulations/imap-session.ts @@ -116,7 +116,7 @@ export const imapSession: SimulationConfig = { id: 'select-response', label: 'A002 OK', description: - 'The server returns the complete mailbox state: 47 messages exist, 2 are recent (new since last check), and the available flags for messages. The UIDVALIDITY value ensures the client\'s cached UIDs are still valid β€” if it changes, the client must re-sync everything.', + "The server returns the complete mailbox state: 47 messages exist, 2 are recent (new since last check), and the available flags for messages. The UIDVALIDITY value ensures the client's cached UIDs are still valid β€” if it changes, the client must re-sync everything.", fromActor: 'server', toActor: 'client', duration: 1000, @@ -138,7 +138,7 @@ export const imapSession: SimulationConfig = { id: 'fetch', label: 'A003 FETCH', description: - 'The client requests the newest message\'s envelope (sender, subject, date) and body text. IMAP can fetch specific parts of messages β€” just headers, just the text body, or individual MIME attachments β€” without downloading the entire message. This is one of IMAP\'s key advantages over POP3.', + "The client requests the newest message's envelope (sender, subject, date) and body text. IMAP can fetch specific parts of messages β€” just headers, just the text body, or individual MIME attachments β€” without downloading the entire message. This is one of IMAP's key advantages over POP3.", fromActor: 'client', toActor: 'server', duration: 800, diff --git a/src/lib/simulator/simulations/ip-routing.ts b/src/lib/simulator/simulations/ip-routing.ts index 89a437d..fee3c1c 100644 --- a/src/lib/simulator/simulations/ip-routing.ts +++ b/src/lib/simulator/simulations/ip-routing.ts @@ -18,7 +18,7 @@ export const ipRouting: SimulationConfig = { id: 'construct', label: 'Construct IP Packet', description: - 'The source host constructs an IP packet with TTL=64 (the standard initial value on Linux). The destination IP 93.184.216.34 is not on the local 192.168.1.0/24 subnet, so the host knows it must send the packet to its default gateway. The Ethernet destination MAC is set to the router\'s MAC β€” not the final destination\'s MAC.', + "The source host constructs an IP packet with TTL=64 (the standard initial value on Linux). The destination IP 93.184.216.34 is not on the local 192.168.1.0/24 subnet, so the host knows it must send the packet to its default gateway. The Ethernet destination MAC is set to the router's MAC β€” not the final destination's MAC.", fromActor: 'source', toActor: 'source', duration: 800, @@ -40,7 +40,7 @@ export const ipRouting: SimulationConfig = { id: 'send-to-gateway', label: 'Send to Default Gateway', description: - 'The packet is placed on the wire toward the default gateway (the router). The Ethernet frame is addressed to the router\'s MAC CC:DD:EE:FF:00:11, but the IP destination remains 93.184.216.34. This is the key insight: Layer 2 addressing is hop-by-hop, while Layer 3 addressing is end-to-end.', + "The packet is placed on the wire toward the default gateway (the router). The Ethernet frame is addressed to the router's MAC CC:DD:EE:FF:00:11, but the IP destination remains 93.184.216.34. This is the key insight: Layer 2 addressing is hop-by-hop, while Layer 3 addressing is end-to-end.", fromActor: 'source', toActor: 'router', duration: 600, @@ -84,7 +84,7 @@ export const ipRouting: SimulationConfig = { id: 'router-forwards', label: 'Router Forwards (new MACs)', description: - 'The router re-encapsulates the IP packet in a brand-new Ethernet frame for the next link. Notice: the source and destination IPs are completely unchanged, but the Ethernet MACs are entirely different β€” the router\'s outbound interface MAC is now the source, and the next hop\'s MAC is the destination. This MAC rewriting happens at every hop.', + "The router re-encapsulates the IP packet in a brand-new Ethernet frame for the next link. Notice: the source and destination IPs are completely unchanged, but the Ethernet MACs are entirely different β€” the router's outbound interface MAC is now the source, and the next hop's MAC is the destination. This MAC rewriting happens at every hop.", fromActor: 'router', toActor: 'dest', duration: 600, @@ -150,7 +150,7 @@ export const ipRouting: SimulationConfig = { id: 'return-route', label: 'Return Route (TTL 63)', description: - 'The router decrements TTL from 64 to 63 and re-encapsulates with new Ethernet MACs for the source\'s local network. The source\'s MAC is now the Ethernet destination, and the router\'s LAN-side MAC is the source. The IP addresses remain 93.184.216.34 β†’ 192.168.1.100, unchanged across the entire return path.', + "The router decrements TTL from 64 to 63 and re-encapsulates with new Ethernet MACs for the source's local network. The source's MAC is now the Ethernet destination, and the router's LAN-side MAC is the source. The IP addresses remain 93.184.216.34 β†’ 192.168.1.100, unchanged across the entire return path.", fromActor: 'router', toActor: 'source', duration: 600, diff --git a/src/lib/simulator/simulations/ipsec-tunnel.ts b/src/lib/simulator/simulations/ipsec-tunnel.ts index f3f0024..2a8250d 100644 --- a/src/lib/simulator/simulations/ipsec-tunnel.ts +++ b/src/lib/simulator/simulations/ipsec-tunnel.ts @@ -86,7 +86,7 @@ export const ipsecTunnel: SimulationConfig = { id: 'ike-intermediate', label: 'IKE_INTERMEDIATE', description: - "RFC 9242. PQ public keys are too large for a single UDP-fragmentable IKE_SA_INIT. IKE_INTERMEDIATE runs *inside* the IKE SA (encrypted), before identity is revealed, and can carry chained KEMs per RFC 9370 β€” here adding FrodoKEM as a second-line PQ backup.", + 'RFC 9242. PQ public keys are too large for a single UDP-fragmentable IKE_SA_INIT. IKE_INTERMEDIATE runs *inside* the IKE SA (encrypted), before identity is revealed, and can carry chained KEMs per RFC 9370 β€” here adding FrodoKEM as a second-line PQ backup.', fromActor: 'hq', toActor: 'branch', duration: 1300, @@ -107,7 +107,7 @@ export const ipsecTunnel: SimulationConfig = { id: 'ike-auth', label: 'IKE_AUTH (req)', description: - "HQ proves identity (`IDi`) with its certificate and signs the IKE_SA_INIT messages (`AUTH`). The first **Child SA** β€” a one-direction ESP key β€” is negotiated in the same exchange via `SAi2`, `TSi`, `TSr`. After this round trip, ESP traffic can flow.", + 'HQ proves identity (`IDi`) with its certificate and signs the IKE_SA_INIT messages (`AUTH`). The first **Child SA** β€” a one-direction ESP key β€” is negotiated in the same exchange via `SAi2`, `TSi`, `TSr`. After this round trip, ESP traffic can flow.', fromActor: 'hq', toActor: 'branch', duration: 1400, @@ -128,7 +128,7 @@ export const ipsecTunnel: SimulationConfig = { id: 'esp-traffic-1', label: 'ESP (HQ β†’ Branch)', description: - "Child SA up. An inner [[ip|IP]] packet (10.0.0.5 β†’ 10.1.0.42, payload `GET /index.html`) is encrypted with AES-GCM-256 and wrapped in ESP with SPI=0xC0FFEE01. Outer header is the public-internet IP pair. Receiver looks up SA by SPI, validates the 128-bit auth tag, decrypts, and forwards the inner packet.", + 'Child SA up. An inner [[ip|IP]] packet (10.0.0.5 β†’ 10.1.0.42, payload `GET /index.html`) is encrypted with AES-GCM-256 and wrapped in ESP with SPI=0xC0FFEE01. Outer header is the public-internet IP pair. Receiver looks up SA by SPI, validates the 128-bit auth tag, decrypts, and forwards the inner packet.', fromActor: 'hq', toActor: 'branch', duration: 1400, diff --git a/src/lib/simulator/simulations/ipv6-ndp.ts b/src/lib/simulator/simulations/ipv6-ndp.ts index 81a222e..f63713c 100644 --- a/src/lib/simulator/simulations/ipv6-ndp.ts +++ b/src/lib/simulator/simulations/ipv6-ndp.ts @@ -6,7 +6,7 @@ export const ipv6Ndp: SimulationConfig = { protocolId: 'ipv6', title: 'IPv6 β€” Neighbor Discovery and Routing', description: - 'Watch an IPv6 packet traverse a network using Neighbor Discovery Protocol (NDP) instead of ARP. Unlike IPv4\'s broadcast-based ARP, NDP uses efficient solicited-node multicast to resolve addresses. Observe how the fixed 40-byte header simplifies router processing, and how Hop Limit (IPv6\'s TTL) decrements at each hop.', + "Watch an IPv6 packet traverse a network using Neighbor Discovery Protocol (NDP) instead of ARP. Unlike IPv4's broadcast-based ARP, NDP uses efficient solicited-node multicast to resolve addresses. Observe how the fixed 40-byte header simplifies router processing, and how Hop Limit (IPv6's TTL) decrements at each hop.", tier: 'client', actors: [ { id: 'source', label: 'Source Host', icon: 'client', position: 'left' }, @@ -41,7 +41,7 @@ export const ipv6Ndp: SimulationConfig = { id: 'ndp-solicitation', label: 'Neighbor Solicitation (NDP)', description: - 'Before sending data, the source must resolve the router\'s IPv6 address to a MAC address. Instead of IPv4\'s ARP broadcast to FF:FF:FF:FF:FF:FF, IPv6 uses NDP Neighbor Solicitation (ICMPv6 Type 135) sent to the solicited-node multicast address ff02::1:ff00:1 β€” only the target and a handful of other nodes process this packet, not the entire network. This is dramatically more efficient than ARP broadcasts.', + "Before sending data, the source must resolve the router's IPv6 address to a MAC address. Instead of IPv4's ARP broadcast to FF:FF:FF:FF:FF:FF, IPv6 uses NDP Neighbor Solicitation (ICMPv6 Type 135) sent to the solicited-node multicast address ff02::1:ff00:1 β€” only the target and a handful of other nodes process this packet, not the entire network. This is dramatically more efficient than ARP broadcasts.", fromActor: 'source', toActor: 'router', duration: 600, @@ -64,7 +64,7 @@ export const ipv6Ndp: SimulationConfig = { id: 'ndp-advertisement', label: 'Neighbor Advertisement (reply)', description: - 'The router responds with a Neighbor Advertisement (ICMPv6 Type 136) containing its link-layer MAC address. The source now caches this mapping in its Neighbor Cache (IPv6\'s equivalent of the ARP cache). The Solicited flag is set, indicating this is a direct response. Unlike ARP\'s simple request/reply, NDP also supports Duplicate Address Detection (DAD) and Router Redirect.', + "The router responds with a Neighbor Advertisement (ICMPv6 Type 136) containing its link-layer MAC address. The source now caches this mapping in its Neighbor Cache (IPv6's equivalent of the ARP cache). The Solicited flag is set, indicating this is a direct response. Unlike ARP's simple request/reply, NDP also supports Duplicate Address Detection (DAD) and Router Redirect.", fromActor: 'router', toActor: 'source', duration: 600, @@ -110,7 +110,7 @@ export const ipv6Ndp: SimulationConfig = { id: 'router-process', label: 'Router Processes (Hop Limit 63)', description: - 'The router examines the IPv6 header. Unlike IPv4, there is no header checksum to recalculate β€” this was removed by design since upper layers (TCP, UDP) already have checksums. The router decrements Hop Limit from 64 to 63 (equivalent to IPv4\'s TTL). If Hop Limit reached 0, the router would send an ICMPv6 Time Exceeded message. It consults the routing table for 2001:db8:2::/64 and determines the outbound interface.', + "The router examines the IPv6 header. Unlike IPv4, there is no header checksum to recalculate β€” this was removed by design since upper layers (TCP, UDP) already have checksums. The router decrements Hop Limit from 64 to 63 (equivalent to IPv4's TTL). If Hop Limit reached 0, the router would send an ICMPv6 Time Exceeded message. It consults the routing table for 2001:db8:2::/64 and determines the outbound interface.", fromActor: 'router', toActor: 'router', duration: 800, @@ -133,7 +133,7 @@ export const ipv6Ndp: SimulationConfig = { id: 'router-forward', label: 'Forward with New MACs', description: - 'The router re-encapsulates the IPv6 packet in a new Ethernet frame for the destination\'s network segment. Just like IPv4 routing: the IPv6 addresses stay constant end-to-end, but the Ethernet MACs change at every hop. The router\'s outbound MAC becomes the new source, and the destination\'s MAC (resolved via NDP on that segment) becomes the new destination. No fragmentation by routers β€” IPv6 requires the source to use Path MTU Discovery.', + "The router re-encapsulates the IPv6 packet in a new Ethernet frame for the destination's network segment. Just like IPv4 routing: the IPv6 addresses stay constant end-to-end, but the Ethernet MACs change at every hop. The router's outbound MAC becomes the new source, and the destination's MAC (resolved via NDP on that segment) becomes the new destination. No fragmentation by routers β€” IPv6 requires the source to use Path MTU Discovery.", fromActor: 'router', toActor: 'dest', duration: 600, diff --git a/src/lib/simulator/simulations/json-rpc-call.ts b/src/lib/simulator/simulations/json-rpc-call.ts index d6dddb2..29e9bea 100644 --- a/src/lib/simulator/simulations/json-rpc-call.ts +++ b/src/lib/simulator/simulations/json-rpc-call.ts @@ -10,10 +10,34 @@ function jsonRpcRequestLayer(method: string, params: string, id: string | number osiLayer: 7, color: '#00D4FF', headerFields: [ - { name: 'Version', bits: 0, value: '"2.0"', editable: false, description: 'JSON-RPC protocol version β€” always "2.0"' }, - { name: 'Method', bits: 0, value: method, editable: false, description: 'Name of the method to invoke on the server' }, - { name: 'Params', bits: 0, value: params, editable: false, description: 'Method arguments β€” can be by-position (array) or by-name (object)' }, - { name: 'ID', bits: 0, value: String(id), editable: false, description: 'Request identifier β€” server echoes this back to correlate the response' } + { + name: 'Version', + bits: 0, + value: '"2.0"', + editable: false, + description: 'JSON-RPC protocol version β€” always "2.0"' + }, + { + name: 'Method', + bits: 0, + value: method, + editable: false, + description: 'Name of the method to invoke on the server' + }, + { + name: 'Params', + bits: 0, + value: params, + editable: false, + description: 'Method arguments β€” can be by-position (array) or by-name (object)' + }, + { + name: 'ID', + bits: 0, + value: String(id), + editable: false, + description: 'Request identifier β€” server echoes this back to correlate the response' + } ] }; } @@ -25,9 +49,28 @@ function jsonRpcResponseLayer(result: string, id: string | number, color: string osiLayer: 7, color: '#00D4FF', headerFields: [ - { name: 'Version', bits: 0, value: '"2.0"', editable: false, description: 'JSON-RPC protocol version' }, - { name: 'Result', bits: 0, value: result, editable: false, description: 'Method return value β€” present on success, absent on error', color }, - { name: 'ID', bits: 0, value: String(id), editable: false, description: 'Matches the request ID β€” confirms which call this responds to' } + { + name: 'Version', + bits: 0, + value: '"2.0"', + editable: false, + description: 'JSON-RPC protocol version' + }, + { + name: 'Result', + bits: 0, + value: result, + editable: false, + description: 'Method return value β€” present on success, absent on error', + color + }, + { + name: 'ID', + bits: 0, + value: String(id), + editable: false, + description: 'Matches the request ID β€” confirms which call this responds to' + } ] }; } @@ -39,10 +82,36 @@ function jsonRpcErrorLayer(code: number, message: string, id: string | number) { osiLayer: 7, color: '#00D4FF', headerFields: [ - { name: 'Version', bits: 0, value: '"2.0"', editable: false, description: 'JSON-RPC protocol version' }, - { name: 'Error Code', bits: 0, value: String(code), editable: false, description: 'Standard error code β€” negative numbers are reserved by the spec', color: '#ef4444' }, - { name: 'Error Message', bits: 0, value: message, editable: false, description: 'Human-readable error description', color: '#ef4444' }, - { name: 'ID', bits: 0, value: String(id), editable: false, description: 'Matches the request ID β€” even errors are correlated' } + { + name: 'Version', + bits: 0, + value: '"2.0"', + editable: false, + description: 'JSON-RPC protocol version' + }, + { + name: 'Error Code', + bits: 0, + value: String(code), + editable: false, + description: 'Standard error code β€” negative numbers are reserved by the spec', + color: '#ef4444' + }, + { + name: 'Error Message', + bits: 0, + value: message, + editable: false, + description: 'Human-readable error description', + color: '#ef4444' + }, + { + name: 'ID', + bits: 0, + value: String(id), + editable: false, + description: 'Matches the request ID β€” even errors are correlated' + } ] }; } @@ -54,10 +123,36 @@ function jsonRpcNotificationLayer(method: string, params: string) { osiLayer: 7, color: '#00D4FF', headerFields: [ - { name: 'Version', bits: 0, value: '"2.0"', editable: false, description: 'JSON-RPC protocol version' }, - { name: 'Method', bits: 0, value: method, editable: false, description: 'Notification method name β€” server will not reply' }, - { name: 'Params', bits: 0, value: params, editable: false, description: 'Notification parameters' }, - { name: 'ID', bits: 0, value: '(absent)', editable: false, description: 'No ID field β€” this is a notification, not a request. The server MUST NOT reply.', color: '#a855f7' } + { + name: 'Version', + bits: 0, + value: '"2.0"', + editable: false, + description: 'JSON-RPC protocol version' + }, + { + name: 'Method', + bits: 0, + value: method, + editable: false, + description: 'Notification method name β€” server will not reply' + }, + { + name: 'Params', + bits: 0, + value: params, + editable: false, + description: 'Notification parameters' + }, + { + name: 'ID', + bits: 0, + value: '(absent)', + editable: false, + description: + 'No ID field β€” this is a notification, not a request. The server MUST NOT reply.', + color: '#a855f7' + } ] }; } @@ -69,9 +164,28 @@ function httpRequestWrapper() { osiLayer: 7, color: '#4B5563', headerFields: [ - { name: 'Method', bits: 0, value: 'POST', editable: false, description: 'JSON-RPC always uses HTTP POST β€” the method is inside the JSON, not in the URL' }, - { name: 'Path', bits: 0, value: '/rpc', editable: false, description: 'Single endpoint β€” all methods go to the same URL' }, - { name: 'Content-Type', bits: 0, value: 'application/json', editable: false, description: 'JSON-RPC payload is always JSON' } + { + name: 'Method', + bits: 0, + value: 'POST', + editable: false, + description: + 'JSON-RPC always uses HTTP POST β€” the method is inside the JSON, not in the URL' + }, + { + name: 'Path', + bits: 0, + value: '/rpc', + editable: false, + description: 'Single endpoint β€” all methods go to the same URL' + }, + { + name: 'Content-Type', + bits: 0, + value: 'application/json', + editable: false, + description: 'JSON-RPC payload is always JSON' + } ] }; } @@ -183,7 +297,7 @@ export const jsonRpcCall: SimulationConfig = { id: 'batch-request', label: 'Batch Request', description: - 'Client sends an array of JSON-RPC calls in a single HTTP request. This is one of JSON-RPC\'s killer features β€” multiple independent calls in one round trip. The array can mix requests and notifications.', + "Client sends an array of JSON-RPC calls in a single HTTP request. This is one of JSON-RPC's killer features β€” multiple independent calls in one round trip. The array can mix requests and notifications.", fromActor: 'client', toActor: 'server', duration: 1000, @@ -199,9 +313,27 @@ export const jsonRpcCall: SimulationConfig = { osiLayer: 7, color: '#00D4FF', headerFields: [ - { name: 'Call 1', bits: 0, value: '{"method":"add","params":[1,2],"id":"a"}', editable: false, description: 'First call in the batch β€” will get a response' }, - { name: 'Call 2', bits: 0, value: '{"method":"log","params":["hi"]}', editable: false, description: 'Notification in the batch β€” no response expected' }, - { name: 'Call 3', bits: 0, value: '{"method":"multiply","params":[3,4],"id":"b"}', editable: false, description: 'Third call β€” will get a response' } + { + name: 'Call 1', + bits: 0, + value: '{"method":"add","params":[1,2],"id":"a"}', + editable: false, + description: 'First call in the batch β€” will get a response' + }, + { + name: 'Call 2', + bits: 0, + value: '{"method":"log","params":["hi"]}', + editable: false, + description: 'Notification in the batch β€” no response expected' + }, + { + name: 'Call 3', + bits: 0, + value: '{"method":"multiply","params":[3,4],"id":"b"}', + editable: false, + description: 'Third call β€” will get a response' + } ] } ] @@ -225,9 +357,30 @@ export const jsonRpcCall: SimulationConfig = { osiLayer: 7, color: '#00D4FF', headerFields: [ - { name: 'Result 1', bits: 0, value: '{"result":3,"id":"a"}', editable: false, description: 'Response for add(1,2) = 3', color: '#22c55e' }, - { name: 'Result 2', bits: 0, value: '{"result":12,"id":"b"}', editable: false, description: 'Response for multiply(3,4) = 12', color: '#22c55e' }, - { name: 'Note', bits: 0, value: 'No entry for notification', editable: false, description: 'The log notification had no id, so no response was generated', color: '#a855f7' } + { + name: 'Result 1', + bits: 0, + value: '{"result":3,"id":"a"}', + editable: false, + description: 'Response for add(1,2) = 3', + color: '#22c55e' + }, + { + name: 'Result 2', + bits: 0, + value: '{"result":12,"id":"b"}', + editable: false, + description: 'Response for multiply(3,4) = 12', + color: '#22c55e' + }, + { + name: 'Note', + bits: 0, + value: 'No entry for notification', + editable: false, + description: 'The log notification had no id, so no response was generated', + color: '#a855f7' + } ] } ] diff --git a/src/lib/simulator/simulations/kafka-events.ts b/src/lib/simulator/simulations/kafka-events.ts index 5cad17c..751c3d8 100644 --- a/src/lib/simulator/simulations/kafka-events.ts +++ b/src/lib/simulator/simulations/kafka-events.ts @@ -8,7 +8,7 @@ export const kafkaEvents: SimulationConfig = { protocolId: 'kafka', title: 'Kafka β€” Event Streaming', description: - 'Follow a producer connecting to a Kafka broker, discovering topic metadata, and publishing an event. Kafka\'s binary wire protocol uses API keys and versioning for backward-compatible evolution.', + "Follow a producer connecting to a Kafka broker, discovering topic metadata, and publishing an event. Kafka's binary wire protocol uses API keys and versioning for backward-compatible evolution.", tier: 'client', actors: [ { id: 'producer', label: 'Producer', icon: 'client', position: 'left' }, @@ -124,7 +124,7 @@ export const kafkaEvents: SimulationConfig = { id: 'produce-ack', label: 'Produce ACK', description: - 'The broker acknowledges the produce request after all in-sync replicas have written the records. The response includes the base offset β€” the position in the partition\'s append-only log where the records were written. Consumers use offsets to track their read position.', + "The broker acknowledges the produce request after all in-sync replicas have written the records. The response includes the base offset β€” the position in the partition's append-only log where the records were written. Consumers use offsets to track their read position.", fromActor: 'broker', toActor: 'producer', duration: 800, diff --git a/src/lib/simulator/simulations/kerberos-auth.ts b/src/lib/simulator/simulations/kerberos-auth.ts index 408713d..87a4d97 100644 --- a/src/lib/simulator/simulations/kerberos-auth.ts +++ b/src/lib/simulator/simulations/kerberos-auth.ts @@ -8,7 +8,7 @@ export const kerberosAuth: SimulationConfig = { protocolId: 'kerberos', title: 'Kerberos Authentication β€” TGT β†’ Service Ticket β†’ AP-REQ', description: - "Watch Alice log into a Kerberos realm, acquire a Ticket Granting Ticket, fetch a service ticket for a web server, and authenticate to that server β€” all without sending her password on the wire. Same flow that runs in every Active Directory domain and every Hadoop cluster on Earth.", + 'Watch Alice log into a Kerberos realm, acquire a Ticket Granting Ticket, fetch a service ticket for a web server, and authenticate to that server β€” all without sending her password on the wire. Same flow that runs in every Active Directory domain and every Hadoop cluster on Earth.', tier: 'client', actors: [ { id: 'client', label: 'Client (Alice)', icon: 'client', position: 'left' }, @@ -60,8 +60,7 @@ export const kerberosAuth: SimulationConfig = { appTag: '[APPLICATION 10] AS-REQ', msgType: 10, cname: 'alice@EXAMPLE.COM', - body: - 'kdc-options: forwardable, renewable; sname: krbtgt/EXAMPLE.COM; padata: PA-ENC-TIMESTAMP (enc with K_alice); nonce: 0xA1B2C3D4; etype: { AES-256, AES-128 }' + body: 'kdc-options: forwardable, renewable; sname: krbtgt/EXAMPLE.COM; padata: PA-ENC-TIMESTAMP (enc with K_alice); nonce: 0xA1B2C3D4; etype: { AES-256, AES-128 }' }) ] }, @@ -69,7 +68,7 @@ export const kerberosAuth: SimulationConfig = { id: 'as-rep', label: 'AS-REP β€” TGT delivered', description: - 'KDC looks up Alice\'s long-term key, generates a fresh session key, returns the AS-REP with **two encrypted blobs**: (a) the **TGT** encrypted under the krbtgt principal\'s key β€” only the KDC can later decrypt it, (b) the session key encrypted under Alice\'s long-term key β€” only Alice can decrypt it. Alice never sees her own password fly over the wire.', + "KDC looks up Alice's long-term key, generates a fresh session key, returns the AS-REP with **two encrypted blobs**: (a) the **TGT** encrypted under the krbtgt principal's key β€” only the KDC can later decrypt it, (b) the session key encrypted under Alice's long-term key β€” only Alice can decrypt it. Alice never sees her own password fly over the wire.", fromActor: 'kdc', toActor: 'client', duration: 1300, @@ -82,8 +81,7 @@ export const kerberosAuth: SimulationConfig = { appTag: '[APPLICATION 11] AS-REP', msgType: 11, cname: 'alice@EXAMPLE.COM', - body: - 'ticket: TGT enc[krbtgt key] { K_session, flags, times }; enc-part: enc[K_alice] { K_session, nonce echoed, sname=krbtgt }' + body: 'ticket: TGT enc[krbtgt key] { K_session, flags, times }; enc-part: enc[K_alice] { K_session, nonce echoed, sname=krbtgt }' }) ] }, @@ -91,7 +89,7 @@ export const kerberosAuth: SimulationConfig = { id: 'tgs-req', label: 'TGS-REQ β€” request a service ticket', description: - 'Alice now wants to access HTTP/web1.example.com. She sends a TGS-REQ to the KDC\'s Ticket Granting Service, presenting her TGT (proves who she is) plus a fresh **authenticator** encrypted under the TGT\'s session key (proves she just got it). No password again.', + "Alice now wants to access HTTP/web1.example.com. She sends a TGS-REQ to the KDC's Ticket Granting Service, presenting her TGT (proves who she is) plus a fresh **authenticator** encrypted under the TGT's session key (proves she just got it). No password again.", fromActor: 'client', toActor: 'kdc', duration: 1300, @@ -104,8 +102,7 @@ export const kerberosAuth: SimulationConfig = { appTag: '[APPLICATION 12] TGS-REQ', msgType: 12, cname: 'alice@EXAMPLE.COM', - body: - 'sname: HTTP/web1.example.com; padata: PA-TGS-REQ (AP-REQ with TGT + authenticator); nonce: 0xE5F60718; etype: { AES-256 }' + body: 'sname: HTTP/web1.example.com; padata: PA-TGS-REQ (AP-REQ with TGT + authenticator); nonce: 0xE5F60718; etype: { AES-256 }' }) ] }, @@ -126,8 +123,7 @@ export const kerberosAuth: SimulationConfig = { appTag: '[APPLICATION 13] TGS-REP', msgType: 13, cname: 'alice@EXAMPLE.COM', - body: - 'ticket: ServiceTicket enc[web1 keytab] { K_svc, flags, times }; enc-part: enc[K_TGT_session] { K_svc, sname=HTTP/web1, times }' + body: 'ticket: ServiceTicket enc[web1 keytab] { K_svc, flags, times }; enc-part: enc[K_TGT_session] { K_svc, sname=HTTP/web1, times }' }) ] }, @@ -169,8 +165,7 @@ export const kerberosAuth: SimulationConfig = { appTag: '[APPLICATION 14] AP-REQ', msgType: 14, cname: 'alice@EXAMPLE.COM', - body: - 'ticket: ServiceTicket enc[web1 keytab] { K_svc }; authenticator: enc[K_svc] { ctime, cusec, seq-number, subkey? }' + body: 'ticket: ServiceTicket enc[web1 keytab] { K_svc }; authenticator: enc[K_svc] { ctime, cusec, seq-number, subkey? }' }) ] }, @@ -247,7 +242,8 @@ export const kerberosAuth: SimulationConfig = { bits: 0, value: 'enc[K_svc] { user payload, seq-number }', editable: false, - description: 'For protocols that want Kerberos confidentiality (rare β€” most use TLS for that)' + description: + 'For protocols that want Kerberos confidentiality (rare β€” most use TLS for that)' } ] } diff --git a/src/lib/simulator/simulations/mcp-session.ts b/src/lib/simulator/simulations/mcp-session.ts index c9fadf1..ef67ebc 100644 --- a/src/lib/simulator/simulations/mcp-session.ts +++ b/src/lib/simulator/simulations/mcp-session.ts @@ -10,10 +10,34 @@ function mcpRequestLayer(method: string, params: string, id: string | number) { osiLayer: 7, color: '#00D4FF', headerFields: [ - { name: 'Version', bits: 0, value: '"2.0"', editable: false, description: 'JSON-RPC protocol version β€” MCP uses JSON-RPC 2.0 as its wire format' }, - { name: 'Method', bits: 0, value: method, editable: false, description: 'MCP method to invoke on the server' }, - { name: 'Params', bits: 0, value: params, editable: false, description: 'Method parameters as a JSON object' }, - { name: 'ID', bits: 0, value: String(id), editable: false, description: 'Request identifier β€” server echoes this back to correlate the response' } + { + name: 'Version', + bits: 0, + value: '"2.0"', + editable: false, + description: 'JSON-RPC protocol version β€” MCP uses JSON-RPC 2.0 as its wire format' + }, + { + name: 'Method', + bits: 0, + value: method, + editable: false, + description: 'MCP method to invoke on the server' + }, + { + name: 'Params', + bits: 0, + value: params, + editable: false, + description: 'Method parameters as a JSON object' + }, + { + name: 'ID', + bits: 0, + value: String(id), + editable: false, + description: 'Request identifier β€” server echoes this back to correlate the response' + } ] }; } @@ -25,9 +49,28 @@ function mcpResponseLayer(result: string, id: string | number, color: string) { osiLayer: 7, color: '#00D4FF', headerFields: [ - { name: 'Version', bits: 0, value: '"2.0"', editable: false, description: 'JSON-RPC protocol version' }, - { name: 'Result', bits: 0, value: result, editable: false, description: 'Response payload β€” contains the requested data or confirmation', color }, - { name: 'ID', bits: 0, value: String(id), editable: false, description: 'Matches the request ID β€” confirms which call this responds to' } + { + name: 'Version', + bits: 0, + value: '"2.0"', + editable: false, + description: 'JSON-RPC protocol version' + }, + { + name: 'Result', + bits: 0, + value: result, + editable: false, + description: 'Response payload β€” contains the requested data or confirmation', + color + }, + { + name: 'ID', + bits: 0, + value: String(id), + editable: false, + description: 'Matches the request ID β€” confirms which call this responds to' + } ] }; } @@ -39,10 +82,36 @@ function mcpNotificationLayer(method: string, params: string) { osiLayer: 7, color: '#00D4FF', headerFields: [ - { name: 'Version', bits: 0, value: '"2.0"', editable: false, description: 'JSON-RPC protocol version' }, - { name: 'Method', bits: 0, value: method, editable: false, description: 'Notification method β€” server acknowledges but MUST NOT reply' }, - { name: 'Params', bits: 0, value: params, editable: false, description: 'Notification parameters' }, - { name: 'ID', bits: 0, value: '(absent)', editable: false, description: 'No ID field β€” this is a notification, not a request. The server MUST NOT reply.', color: '#a855f7' } + { + name: 'Version', + bits: 0, + value: '"2.0"', + editable: false, + description: 'JSON-RPC protocol version' + }, + { + name: 'Method', + bits: 0, + value: method, + editable: false, + description: 'Notification method β€” server acknowledges but MUST NOT reply' + }, + { + name: 'Params', + bits: 0, + value: params, + editable: false, + description: 'Notification parameters' + }, + { + name: 'ID', + bits: 0, + value: '(absent)', + editable: false, + description: + 'No ID field β€” this is a notification, not a request. The server MUST NOT reply.', + color: '#a855f7' + } ] }; } @@ -54,9 +123,21 @@ function httpTransportLayer(method: string, path: string) { osiLayer: 7, color: '#4B5563', headerFields: [ - { name: 'Method', bits: 0, value: method, editable: false, description: 'HTTP method β€” MCP uses POST for JSON-RPC messages over Streamable HTTP' }, + { + name: 'Method', + bits: 0, + value: method, + editable: false, + description: 'HTTP method β€” MCP uses POST for JSON-RPC messages over Streamable HTTP' + }, { name: 'Path', bits: 0, value: path, editable: false, description: 'MCP endpoint path' }, - { name: 'Content-Type', bits: 0, value: 'application/json', editable: false, description: 'JSON-RPC payload is always JSON' } + { + name: 'Content-Type', + bits: 0, + value: 'application/json', + editable: false, + description: 'JSON-RPC payload is always JSON' + } ] }; } @@ -95,7 +176,11 @@ export const mcpSession: SimulationConfig = { createIPv4Layer({ protocol: 6 }), createTCPLayer({ srcPort: 54200, dstPort: 443, flags: 'PSH,ACK' }), httpTransportLayer('POST', '/mcp'), - mcpRequestLayer('initialize', '{"protocolVersion":"2025-03-26","capabilities":{"roots":{"listChanged":true}},"clientInfo":{"name":"MyAIApp","version":"1.0"}}', 1) + mcpRequestLayer( + 'initialize', + '{"protocolVersion":"2025-03-26","capabilities":{"roots":{"listChanged":true}},"clientInfo":{"name":"MyAIApp","version":"1.0"}}', + 1 + ) ] }, { @@ -111,7 +196,11 @@ export const mcpSession: SimulationConfig = { createEthernetLayer({ srcMac: 'AA:BB:CC:DD:EE:FF', dstMac: '00:1A:2B:3C:4D:5E' }), createIPv4Layer({ srcIp: '93.184.216.34', dstIp: '192.168.1.100', protocol: 6 }), createTCPLayer({ srcPort: 443, dstPort: 54200, flags: 'PSH,ACK' }), - mcpResponseLayer('{"protocolVersion":"2025-03-26","capabilities":{"tools":{"listChanged":true}},"serverInfo":{"name":"WeatherServer","version":"2.0"}}', 1, '#22c55e') + mcpResponseLayer( + '{"protocolVersion":"2025-03-26","capabilities":{"tools":{"listChanged":true}},"serverInfo":{"name":"WeatherServer","version":"2.0"}}', + 1, + '#22c55e' + ) ] }, { @@ -161,7 +250,11 @@ export const mcpSession: SimulationConfig = { createEthernetLayer({ srcMac: 'AA:BB:CC:DD:EE:FF', dstMac: '00:1A:2B:3C:4D:5E' }), createIPv4Layer({ srcIp: '93.184.216.34', dstIp: '192.168.1.100', protocol: 6 }), createTCPLayer({ srcPort: 443, dstPort: 54200, flags: 'PSH,ACK' }), - mcpResponseLayer('{"tools":[{"name":"weather","description":"Get current weather","inputSchema":{"type":"object","properties":{"city":{"type":"string"}},"required":["city"]}}]}', 2, '#22c55e') + mcpResponseLayer( + '{"tools":[{"name":"weather","description":"Get current weather","inputSchema":{"type":"object","properties":{"city":{"type":"string"}},"required":["city"]}}]}', + 2, + '#22c55e' + ) ] }, { @@ -194,7 +287,11 @@ export const mcpSession: SimulationConfig = { createEthernetLayer({ srcMac: 'AA:BB:CC:DD:EE:FF', dstMac: '00:1A:2B:3C:4D:5E' }), createIPv4Layer({ srcIp: '93.184.216.34', dstIp: '192.168.1.100', protocol: 6 }), createTCPLayer({ srcPort: 443, dstPort: 54200, flags: 'PSH,ACK' }), - mcpResponseLayer('{"content":[{"type":"text","text":"San Francisco: 62\u00b0F, partly cloudy, wind 12mph W"}],"isError":false}', 3, '#22c55e') + mcpResponseLayer( + '{"content":[{"type":"text","text":"San Francisco: 62\u00b0F, partly cloudy, wind 12mph W"}],"isError":false}', + 3, + '#22c55e' + ) ] } ] diff --git a/src/lib/simulator/simulations/mdns-discovery.ts b/src/lib/simulator/simulations/mdns-discovery.ts index be42939..908c74e 100644 --- a/src/lib/simulator/simulations/mdns-discovery.ts +++ b/src/lib/simulator/simulations/mdns-discovery.ts @@ -8,7 +8,7 @@ export const mdnsDiscovery: SimulationConfig = { protocolId: 'mdns-dns-sd', title: 'mDNS / DNS-SD β€” Probe, Announce, Discover, Goodbye', description: - "Watch a new printer claim `office-printer.local`, announce its IPP service, get discovered by a laptop browsing for `_ipp._tcp`, and send a clean goodbye on shutdown. The full Bonjour lifecycle on one link.", + 'Watch a new printer claim `office-printer.local`, announce its IPP service, get discovered by a laptop browsing for `_ipp._tcp`, and send a clean goodbye on shutdown. The full Bonjour lifecycle on one link.', tier: 'server', actors: [ { id: 'printer', label: 'Printer (responder)', icon: 'device', position: 'left' }, @@ -142,7 +142,7 @@ export const mdnsDiscovery: SimulationConfig = { id: 'sd-response', label: 'PTR Response (unicast)', description: - "Printer responds β€” unicast this time (because the querier set the unicast-response bit). Just the PTR pointing to its service instance. The laptop will follow up with SRV+TXT+A queries to complete the resolution.", + 'Printer responds β€” unicast this time (because the querier set the unicast-response bit). Just the PTR pointing to its service instance. The laptop will follow up with SRV+TXT+A queries to complete the resolution.', fromActor: 'printer', toActor: 'laptop', duration: 1200, diff --git a/src/lib/simulator/simulations/mptcp-multipath.ts b/src/lib/simulator/simulations/mptcp-multipath.ts index f0820e7..c8c5686 100644 --- a/src/lib/simulator/simulations/mptcp-multipath.ts +++ b/src/lib/simulator/simulations/mptcp-multipath.ts @@ -42,7 +42,7 @@ export const mptcpMultipath: SimulationConfig = { id: 'synack-capable', label: 'SYN-ACK + MP_CAPABLE', description: - 'The server responds with SYN-ACK and its own MP_CAPABLE option containing the server\'s key. Both keys are now exchanged β€” the client and server can derive tokens from each other\'s keys to authenticate additional subflows later. The primary subflow is established.', + "The server responds with SYN-ACK and its own MP_CAPABLE option containing the server's key. Both keys are now exchanged β€” the client and server can derive tokens from each other's keys to authenticate additional subflows later. The primary subflow is established.", fromActor: 'server', toActor: 'client', duration: 800, @@ -88,7 +88,7 @@ export const mptcpMultipath: SimulationConfig = { id: 'join', label: 'SYN + MP_JOIN', description: - 'The phone adds a second subflow over cellular. MP_JOIN uses a token derived from the server\'s key to identify which MPTCP connection to join. The server verifies the HMAC to ensure this is a legitimate subflow and not an attack. Data can now be split across both Wi-Fi and cellular paths.', + "The phone adds a second subflow over cellular. MP_JOIN uses a token derived from the server's key to identify which MPTCP connection to join. The server verifies the HMAC to ensure this is a legitimate subflow and not an attack. Data can now be split across both Wi-Fi and cellular paths.", fromActor: 'client', toActor: 'server', duration: 1000, diff --git a/src/lib/simulator/simulations/mqtt-pubsub.ts b/src/lib/simulator/simulations/mqtt-pubsub.ts index e23ad49..742b300 100644 --- a/src/lib/simulator/simulations/mqtt-pubsub.ts +++ b/src/lib/simulator/simulations/mqtt-pubsub.ts @@ -51,7 +51,7 @@ export const mqttPubSub: SimulationConfig = { id: 'connack', label: 'CONNACK', description: - 'The broker validates the client\'s credentials and session state, then responds with CONNACK. A return code of 0 means the connection is accepted. The broker can also signal whether a previous session exists for this client ID.', + "The broker validates the client's credentials and session state, then responds with CONNACK. A return code of 0 means the connection is accepted. The broker can also signal whether a previous session exists for this client ID.", fromActor: 'broker', toActor: 'device', duration: 800, diff --git a/src/lib/simulator/simulations/nat-traversal.ts b/src/lib/simulator/simulations/nat-traversal.ts index 1cd76ec..37f9b14 100644 --- a/src/lib/simulator/simulations/nat-traversal.ts +++ b/src/lib/simulator/simulations/nat-traversal.ts @@ -56,7 +56,7 @@ export const natTraversalIce: SimulationConfig = { id: 'stun-bind-resp', label: 'STUN Binding Success', description: - 'STUN replies with what it saw β€” Alice\'s public ip:port encoded in XOR-MAPPED-ADDRESS (XORed against the magic cookie so middleboxes can\'t rewrite it). That\'s Alice\'s **server-reflexive candidate**.', + "STUN replies with what it saw β€” Alice's public ip:port encoded in XOR-MAPPED-ADDRESS (XORed against the magic cookie so middleboxes can't rewrite it). That's Alice's **server-reflexive candidate**.", fromActor: 'server', toActor: 'alice', duration: 1200, @@ -91,7 +91,8 @@ export const natTraversalIce: SimulationConfig = { createSTUNLayer({ type: 'Allocate Request', length: 96, - attribute: 'REQUESTED-TRANSPORT=17 (UDP), LIFETIME=600, USERNAME, REALM, NONCE, MESSAGE-INTEGRITY-256' + attribute: + 'REQUESTED-TRANSPORT=17 (UDP), LIFETIME=600, USERNAME, REALM, NONCE, MESSAGE-INTEGRITY-256' }) ] }, @@ -122,7 +123,7 @@ export const natTraversalIce: SimulationConfig = { id: 'ice-check-alice-bob', label: 'ICE Connectivity Check (A β†’ B)', description: - 'Alice sends a STUN Binding Request directly to Bob\'s reflexive candidate, using short-term ICE credentials (the ufrag/pwd exchanged via SDP). PRIORITY carries the candidate priority; ICE-CONTROLLING carries a 64-bit tiebreaker.', + "Alice sends a STUN Binding Request directly to Bob's reflexive candidate, using short-term ICE credentials (the ufrag/pwd exchanged via SDP). PRIORITY carries the candidate priority; ICE-CONTROLLING carries a 64-bit tiebreaker.", fromActor: 'alice', toActor: 'bob', duration: 1400, @@ -134,7 +135,8 @@ export const natTraversalIce: SimulationConfig = { createSTUNLayer({ type: 'Binding Request', length: 32, - attribute: 'USERNAME (bob:alice), PRIORITY, ICE-CONTROLLING, MESSAGE-INTEGRITY, FINGERPRINT' + attribute: + 'USERNAME (bob:alice), PRIORITY, ICE-CONTROLLING, MESSAGE-INTEGRITY, FINGERPRINT' }) ] }, diff --git a/src/lib/simulator/simulations/nfc-tap.ts b/src/lib/simulator/simulations/nfc-tap.ts index 7df42db..80df977 100644 --- a/src/lib/simulator/simulations/nfc-tap.ts +++ b/src/lib/simulator/simulations/nfc-tap.ts @@ -5,7 +5,7 @@ export const nfcTap: SimulationConfig = { protocolId: 'nfc', title: 'NFC Tap β€” Apple Pay / EMV Contactless', description: - "Watch a phone present an EMV cryptogram to a contactless terminal in ~300 ms. The same nine beats β€” REQA β†’ ATQA β†’ SEL β†’ SAK β†’ RATS β†’ ATS β†’ SELECT PPSE β†’ SELECT AID β†’ GPO β†’ READ RECORD β†’ GENERATE AC β€” that runs ~$7.6 trillion in annualised Apple Pay transactions and every plastic contactless card on Earth.", + 'Watch a phone present an EMV cryptogram to a contactless terminal in ~300 ms. The same nine beats β€” REQA β†’ ATQA β†’ SEL β†’ SAK β†’ RATS β†’ ATS β†’ SELECT PPSE β†’ SELECT AID β†’ GPO β†’ READ RECORD β†’ GENERATE AC β€” that runs ~$7.6 trillion in annualised Apple Pay transactions and every plastic contactless card on Earth.', tier: 'client', actors: [ { id: 'phone', label: 'Phone (PICC)', icon: 'device', position: 'left' }, @@ -44,18 +44,32 @@ export const nfcTap: SimulationConfig = { toActor: 'terminal', duration: 800, highlight: ['Carrier'], - layers: [createNFCALayer({ frame: 'RF field (continuous)', direction: '13.56 MHz carrier from PCD', payload: 'Power transfer + clock recovery', crc: '(none β€” physical layer)' })] + layers: [ + createNFCALayer({ + frame: 'RF field (continuous)', + direction: '13.56 MHz carrier from PCD', + payload: 'Power transfer + clock recovery', + crc: '(none β€” physical layer)' + }) + ] }, { id: 'reqa', label: 'REQA β€” terminal asks "any Type A cards here?"', description: - "The terminal sends a 7-bit short frame `0x26` β€” Request-A β€” on the carrier. Any IDLE Type A PICC in the field transitions to READY and prepares to answer. (For deep-sleep cards the terminal would use `WUPA = 0x52` instead, which also wakes HALT cards.)", + 'The terminal sends a 7-bit short frame `0x26` β€” Request-A β€” on the carrier. Any IDLE Type A PICC in the field transitions to READY and prepares to answer. (For deep-sleep cards the terminal would use `WUPA = 0x52` instead, which also wakes HALT cards.)', fromActor: 'terminal', toActor: 'phone', duration: 700, highlight: ['Frame', 'Payload'], - layers: [createNFCALayer({ frame: 'Short frame (7 bits, no CRC)', direction: 'PCD β†’ PICC', payload: '0x26 (REQA)', crc: '(none β€” short frame)' })] + layers: [ + createNFCALayer({ + frame: 'Short frame (7 bits, no CRC)', + direction: 'PCD β†’ PICC', + payload: '0x26 (REQA)', + crc: '(none β€” short frame)' + }) + ] }, { id: 'atqa', @@ -66,29 +80,50 @@ export const nfcTap: SimulationConfig = { toActor: 'terminal', duration: 700, highlight: ['Frame', 'Payload'], - layers: [createNFCALayer({ frame: 'Standard frame (16 bits, no CRC)', direction: 'PICC β†’ PCD', payload: '0x04 0x00 (ATQA β€” 4-byte UID, std anti-collision)', crc: '(none)' })] + layers: [ + createNFCALayer({ + frame: 'Standard frame (16 bits, no CRC)', + direction: 'PICC β†’ PCD', + payload: '0x04 0x00 (ATQA β€” 4-byte UID, std anti-collision)', + crc: '(none)' + }) + ] }, { id: 'sel', label: 'SEL/NVB β€” bit-frame anti-collision converges on the UID', description: - "The terminal sends `SEL = 0x93` (cascade level 1), `NVB = 0x20` (no bits known yet). The card returns its 4 UID bytes + BCC (the XOR check byte). The terminal echoes them back with `NVB = 0x70` and a CRC_A. The card responds with `SAK = 0x28` β€” bit 6 set says *I support ISO 14443-4* (so RATS/ATS will follow); bit 3 clear says *the UID is complete, no further cascade needed*.", + 'The terminal sends `SEL = 0x93` (cascade level 1), `NVB = 0x20` (no bits known yet). The card returns its 4 UID bytes + BCC (the XOR check byte). The terminal echoes them back with `NVB = 0x70` and a CRC_A. The card responds with `SAK = 0x28` β€” bit 6 set says *I support ISO 14443-4* (so RATS/ATS will follow); bit 3 clear says *the UID is complete, no further cascade needed*.', fromActor: 'terminal', toActor: 'phone', duration: 900, highlight: ['Frame', 'Payload', 'CRC_A'], - layers: [createNFCALayer({ frame: 'Full frame (CRC_A protected)', direction: 'PCD ↔ PICC (multi-frame exchange)', payload: 'SEL=0x93 NVB=0x20 β†’ UID=04 1A 2B 3C BCC=4D β†’ SEL=0x93 NVB=0x70 ... β†’ SAK=0x28', crc: 'CRC_A on SEL+NVB+UID' })] + layers: [ + createNFCALayer({ + frame: 'Full frame (CRC_A protected)', + direction: 'PCD ↔ PICC (multi-frame exchange)', + payload: 'SEL=0x93 NVB=0x20 β†’ UID=04 1A 2B 3C BCC=4D β†’ SEL=0x93 NVB=0x70 ... β†’ SAK=0x28', + crc: 'CRC_A on SEL+NVB+UID' + }) + ] }, { id: 'rats', label: 'RATS / ATS β€” negotiate frame size and timing', description: - "Now in 14443-4 mode. The terminal sends `RATS = 0xE0 0x80` (Request for ATS, with CID=0 and FSDI=8 meaning *I can accept up to 256-byte frames*). The phone replies with **ATS** β€” `06 75 33 81 02 80` β€” declaring its Frame Size for the Card (FSCI=5 = 64 bytes max), Frame Waiting Time (FWI=3), and supports CID/NAD options. Both ends now know the framing budget for the rest of the conversation.", + 'Now in 14443-4 mode. The terminal sends `RATS = 0xE0 0x80` (Request for ATS, with CID=0 and FSDI=8 meaning *I can accept up to 256-byte frames*). The phone replies with **ATS** β€” `06 75 33 81 02 80` β€” declaring its Frame Size for the Card (FSCI=5 = 64 bytes max), Frame Waiting Time (FWI=3), and supports CID/NAD options. Both ends now know the framing budget for the rest of the conversation.', fromActor: 'terminal', toActor: 'phone', duration: 800, highlight: ['Frame', 'Payload'], - layers: [createNFCALayer({ frame: 'Full frame (CRC_A protected)', direction: 'PCD ↔ PICC', payload: 'RATS=E0 80 β†’ ATS=06 75 33 81 02 80 (FSCI=5, FWI=3, CID supported)', crc: 'CRC_A' })] + layers: [ + createNFCALayer({ + frame: 'Full frame (CRC_A protected)', + direction: 'PCD ↔ PICC', + payload: 'RATS=E0 80 β†’ ATS=06 75 33 81 02 80 (FSCI=5, FWI=3, CID supported)', + crc: 'CRC_A' + }) + ] }, { id: 'ppse', @@ -99,7 +134,15 @@ export const nfcTap: SimulationConfig = { toActor: 'phone', duration: 900, highlight: ['CLA INS P1 P2', 'Data', 'Response Data / SW1 SW2'], - layers: [createAPDULayer({ header: '00 A4 04 00', lc: '0E', data: "32 50 41 59 2E 53 59 53 2E 44 44 46 30 31 (PPSE AID '2PAY.SYS.DDF01')", le: '00', response: '6F .. A5 .. BF0C 1C 61 1A 4F 07 A0000000041010 50 0A MASTERCARD ... 90 00' })] + layers: [ + createAPDULayer({ + header: '00 A4 04 00', + lc: '0E', + data: "32 50 41 59 2E 53 59 53 2E 44 44 46 30 31 (PPSE AID '2PAY.SYS.DDF01')", + le: '00', + response: '6F .. A5 .. BF0C 1C 61 1A 4F 07 A0000000041010 50 0A MASTERCARD ... 90 00' + }) + ] }, { id: 'select-aid', @@ -110,7 +153,15 @@ export const nfcTap: SimulationConfig = { toActor: 'phone', duration: 900, highlight: ['CLA INS P1 P2', 'Data', 'Response Data / SW1 SW2'], - layers: [createAPDULayer({ header: '00 A4 04 00', lc: '07', data: 'A0 00 00 00 04 10 10 (AID: Mastercard credit/debit)', le: '00', response: '6F .. A5 .. 9F38 (PDOL list: amount, currency, country, TVR, ...) 90 00' })] + layers: [ + createAPDULayer({ + header: '00 A4 04 00', + lc: '07', + data: 'A0 00 00 00 04 10 10 (AID: Mastercard credit/debit)', + le: '00', + response: '6F .. A5 .. 9F38 (PDOL list: amount, currency, country, TVR, ...) 90 00' + }) + ] }, { id: 'gpo', @@ -121,18 +172,35 @@ export const nfcTap: SimulationConfig = { toActor: 'phone', duration: 1100, highlight: ['CLA INS P1 P2', 'Data', 'Response Data / SW1 SW2'], - layers: [createAPDULayer({ header: '80 A8 00 00', lc: '23', data: '83 21 ...PDOL filled: amount Β£28.50, currency GBP, country UK, TVR, UN...', le: '00', response: '77 .. 82 02 19 80 (AIP: CDA, CVM, RRP) 94 0C 18 01 02 00 ... (AFL) 90 00' })] + layers: [ + createAPDULayer({ + header: '80 A8 00 00', + lc: '23', + data: '83 21 ...PDOL filled: amount Β£28.50, currency GBP, country UK, TVR, UN...', + le: '00', + response: '77 .. 82 02 19 80 (AIP: CDA, CVM, RRP) 94 0C 18 01 02 00 ... (AFL) 90 00' + }) + ] }, { id: 'read-records', label: 'READ RECORD Γ—N β€” pull PAN, expiry, public-key certificates', description: - "For each entry in the AFL, the terminal issues `00 B2 <rec> <(sfi<<3)|0x04>` READ RECORD. The card returns the **PAN-equivalent** (DPAN, not the real card number β€” that lives at the issuer), expiry, CDOL1 (which tags GENERATE AC needs), the **Issuer Public-Key Certificate** and **ICC Public-Key Certificate** for offline CDA verification. Three to five READ RECORDs is typical.", + 'For each entry in the AFL, the terminal issues `00 B2 <rec> <(sfi<<3)|0x04>` READ RECORD. The card returns the **PAN-equivalent** (DPAN, not the real card number β€” that lives at the issuer), expiry, CDOL1 (which tags GENERATE AC needs), the **Issuer Public-Key Certificate** and **ICC Public-Key Certificate** for offline CDA verification. Three to five READ RECORDs is typical.', fromActor: 'terminal', toActor: 'phone', duration: 1100, highlight: ['CLA INS P1 P2', 'Data', 'Response Data / SW1 SW2'], - layers: [createAPDULayer({ header: '00 B2 01 0C', lc: '(none)', data: '(no command body)', le: '00', response: '70 .. 5F24 (expiry 12/27) 5A 08 5413 33xx xxxx xxxx (DPAN) 8F 01 ... (cert chain) 90 00' })] + layers: [ + createAPDULayer({ + header: '00 B2 01 0C', + lc: '(none)', + data: '(no command body)', + le: '00', + response: + '70 .. 5F24 (expiry 12/27) 5A 08 5413 33xx xxxx xxxx (DPAN) 8F 01 ... (cert chain) 90 00' + }) + ] }, { id: 'generate-ac', @@ -143,18 +211,35 @@ export const nfcTap: SimulationConfig = { toActor: 'phone', duration: 1300, highlight: ['CLA INS P1 P2', 'Data', 'Response Data / SW1 SW2'], - layers: [createAPDULayer({ header: '80 AE 80 00', lc: '1F', data: '...CDOL1 data: amount Β£28.50, currency GBP, TVR, UN 0x9C2A3B4D...', le: '00', response: '77 .. 9F27 80 (CID=ARQC) 9F36 02 00 7A (ATC) 9F26 08 1A 2B 3C 4D 5E 6F 70 81 (Application Cryptogram) 9F10 ...IAD... 90 00' })] + layers: [ + createAPDULayer({ + header: '80 AE 80 00', + lc: '1F', + data: '...CDOL1 data: amount Β£28.50, currency GBP, TVR, UN 0x9C2A3B4D...', + le: '00', + response: + '77 .. 9F27 80 (CID=ARQC) 9F36 02 00 7A (ATC) 9F26 08 1A 2B 3C 4D 5E 6F 70 81 (Application Cryptogram) 9F10 ...IAD... 90 00' + }) + ] }, { id: 'authorize', label: 'Issuer authorisation β€” terminal sends ARQC online, gets ARPC back', description: - "The terminal hands the ARQC to the acquirer (Stripe, Square, Worldpay), which routes it through the payment network (Mastercard) to the **issuing bank**. The issuer verifies the cryptogram against the per-DPAN key in its HSM and returns an **ARPC** (Authorisation Response Cryptogram) β€” `APPROVED`. Total time including network round-trip: typically 300–800 ms. The terminal beeps green; the phone vibrates with the Apple Pay success animation. Total airtime in the magnetic field was less than half a second.", + 'The terminal hands the ARQC to the acquirer (Stripe, Square, Worldpay), which routes it through the payment network (Mastercard) to the **issuing bank**. The issuer verifies the cryptogram against the per-DPAN key in its HSM and returns an **ARPC** (Authorisation Response Cryptogram) β€” `APPROVED`. Total time including network round-trip: typically 300–800 ms. The terminal beeps green; the phone vibrates with the Apple Pay success animation. Total airtime in the magnetic field was less than half a second.', fromActor: 'terminal', toActor: 'phone', duration: 1000, highlight: ['Response Data / SW1 SW2'], - layers: [createAPDULayer({ header: '(issuer round-trip via acquirer + payment network β€” not in-field)', lc: 'β€”', data: 'ARQC β†’ issuer HSM β†’ ARPC (APPROVED, ARC=00)', le: 'β€”', response: 'Terminal beeps green; phone shows Apple Pay tick' })] + layers: [ + createAPDULayer({ + header: '(issuer round-trip via acquirer + payment network β€” not in-field)', + lc: 'β€”', + data: 'ARQC β†’ issuer HSM β†’ ARPC (APPROVED, ARC=00)', + le: 'β€”', + response: 'Terminal beeps green; phone shows Apple Pay tick' + }) + ] } ] }; @@ -163,7 +248,7 @@ export const nfcTagRead: SimulationConfig = { protocolId: 'nfc', title: 'NFC Tag Read β€” Type 2 NDEF Smart Poster', description: - "Watch a phone pick up an NDEF URL from a passive transit-poster tag in a single tap. Same physics as Apple Pay, simpler stack: REQA β†’ ATQA β†’ SEL β†’ SAK (without 14443-4) β†’ T2T READ β†’ NDEF parse β†’ hand off to the browser.", + 'Watch a phone pick up an NDEF URL from a passive transit-poster tag in a single tap. Same physics as Apple Pay, simpler stack: REQA β†’ ATQA β†’ SEL β†’ SAK (without 14443-4) β†’ T2T READ β†’ NDEF parse β†’ hand off to the browser.', tier: 'client', actors: [ { id: 'phone', label: 'Phone (PCD)', icon: 'device', position: 'left' }, @@ -175,7 +260,12 @@ export const nfcTagRead: SimulationConfig = { label: 'Tag type', type: 'select', defaultValue: 'NTAG216 (T2T, 924 bytes)', - options: ['NTAG213 (T2T, 144 bytes)', 'NTAG216 (T2T, 924 bytes)', 'MIFARE Classic 1k (legacy)', 'ICODE SLIX2 (T5T)'] + options: [ + 'NTAG213 (T2T, 144 bytes)', + 'NTAG216 (T2T, 924 bytes)', + 'MIFARE Classic 1k (legacy)', + 'ICODE SLIX2 (T5T)' + ] } ], steps: [ @@ -188,40 +278,69 @@ export const nfcTagRead: SimulationConfig = { toActor: 'tag', duration: 800, highlight: ['Frame', 'Payload'], - layers: [createNFCALayer({ frame: 'Short β†’ standard frames', direction: 'PCD β†’ PICC β†’ PCD', payload: 'REQA 0x26 β†’ ATQA 0x00 0x44 (7-byte UID)', crc: '(none / short)' })] + layers: [ + createNFCALayer({ + frame: 'Short β†’ standard frames', + direction: 'PCD β†’ PICC β†’ PCD', + payload: 'REQA 0x26 β†’ ATQA 0x00 0x44 (7-byte UID)', + crc: '(none / short)' + }) + ] }, { id: 'sel', label: 'SEL cascade β€” converge on the 7-byte UID', description: - "Two cascade levels are needed for a 7-byte UID. Level 1 (SEL=0x93) returns bytes 0–3 (with the cascade tag CT=0x88 in byte 0) + BCC. Level 2 (SEL=0x95) returns bytes 4–6 + BCC. Final SAK is `0x00` β€” meaning *Type 2 tag, no ISO 14443-4*. We go straight to T2T commands.", + 'Two cascade levels are needed for a 7-byte UID. Level 1 (SEL=0x93) returns bytes 0–3 (with the cascade tag CT=0x88 in byte 0) + BCC. Level 2 (SEL=0x95) returns bytes 4–6 + BCC. Final SAK is `0x00` β€” meaning *Type 2 tag, no ISO 14443-4*. We go straight to T2T commands.', fromActor: 'phone', toActor: 'tag', duration: 900, highlight: ['Frame', 'Payload', 'CRC_A'], - layers: [createNFCALayer({ frame: 'Full frame, multi-step', direction: 'PCD ↔ PICC', payload: 'CL1 β†’ UID-CL1 (with CT=0x88) + BCC β†’ CL2 β†’ UID-CL2 + BCC β†’ SAK 0x00 (T2T)', crc: 'CRC_A' })] + layers: [ + createNFCALayer({ + frame: 'Full frame, multi-step', + direction: 'PCD ↔ PICC', + payload: 'CL1 β†’ UID-CL1 (with CT=0x88) + BCC β†’ CL2 β†’ UID-CL2 + BCC β†’ SAK 0x00 (T2T)', + crc: 'CRC_A' + }) + ] }, { id: 'read-cc', label: 'T2T READ β€” fetch the Capability Container', description: - "NDEF tags begin with a CC at page 3 (16 bytes). T2T READ command (`0x30 0x03`) returns 4 pages = 16 bytes. The CC is the first 4 bytes: `E1 10 6D 00` β€” magic byte 0xE1, version 1.0, memory size 0x6D Γ— 8 = 872 bytes available, read/write access flags 0x00. The reader knows this tag has NDEF content.", + 'NDEF tags begin with a CC at page 3 (16 bytes). T2T READ command (`0x30 0x03`) returns 4 pages = 16 bytes. The CC is the first 4 bytes: `E1 10 6D 00` β€” magic byte 0xE1, version 1.0, memory size 0x6D Γ— 8 = 872 bytes available, read/write access flags 0x00. The reader knows this tag has NDEF content.', fromActor: 'phone', toActor: 'tag', duration: 800, highlight: ['Frame', 'Payload'], - layers: [createNFCALayer({ frame: 'Full frame, CRC_A', direction: 'PCD ↔ PICC', payload: 'READ 0x30 0x03 β†’ 16 bytes: E1 10 6D 00 (CC) + first NDEF page', crc: 'CRC_A' })] + layers: [ + createNFCALayer({ + frame: 'Full frame, CRC_A', + direction: 'PCD ↔ PICC', + payload: 'READ 0x30 0x03 β†’ 16 bytes: E1 10 6D 00 (CC) + first NDEF page', + crc: 'CRC_A' + }) + ] }, { id: 'read-ndef', label: 'T2T READ β€” pull the NDEF TLV', description: - "Continue reading pages 4..N. Tag memory has an NDEF TLV: byte 0x03 (NDEF Message), 1-byte length, then the NDEF message bytes. One TLV may chain multiple NDEF records.", + 'Continue reading pages 4..N. Tag memory has an NDEF TLV: byte 0x03 (NDEF Message), 1-byte length, then the NDEF message bytes. One TLV may chain multiple NDEF records.', fromActor: 'phone', toActor: 'tag', duration: 800, highlight: ['Frame', 'Payload'], - layers: [createNFCALayer({ frame: 'Full frame, CRC_A', direction: 'PCD ↔ PICC', payload: 'READ 0x30 0x04..., 0x30 0x08, ...: 03 19 D1 01 15 55 03 t r a n s i t . e x a m p l e . c o m / q r', crc: 'CRC_A' })] + layers: [ + createNFCALayer({ + frame: 'Full frame, CRC_A', + direction: 'PCD ↔ PICC', + payload: + 'READ 0x30 0x04..., 0x30 0x08, ...: 03 19 D1 01 15 55 03 t r a n s i t . e x a m p l e . c o m / q r', + crc: 'CRC_A' + }) + ] }, { id: 'parse-ndef', @@ -232,19 +351,35 @@ export const nfcTagRead: SimulationConfig = { toActor: 'phone', duration: 800, highlight: ['Header byte', 'Type', 'Payload'], - layers: [createNDEFLayer({ header: 'MB=1 ME=1 SR=1 IL=0 TNF=1 (Well-Known)', typeLen: 1, payloadLen: 21, type: "'U' (URI Record)", payload: '0x03 transit.example.com/qr β†’ https://transit.example.com/qr' })] + layers: [ + createNDEFLayer({ + header: 'MB=1 ME=1 SR=1 IL=0 TNF=1 (Well-Known)', + typeLen: 1, + payloadLen: 21, + type: "'U' (URI Record)", + payload: '0x03 transit.example.com/qr β†’ https://transit.example.com/qr' + }) + ] }, { id: 'handoff', label: 'Hand-off β€” phone OS opens the URL', description: - "The phone OS receives the parsed NDEF URL and hands it off to the default browser. On iOS the tap-to-launch notification appears (if `com.apple.developer.nfc.readersession.iso7816.select-identifiers` is in the app entitlement); on Android the URL launches directly. Total time from tap to browser load: typically <300 ms.", + 'The phone OS receives the parsed NDEF URL and hands it off to the default browser. On iOS the tap-to-launch notification appears (if `com.apple.developer.nfc.readersession.iso7816.select-identifiers` is in the app entitlement); on Android the URL launches directly. Total time from tap to browser load: typically <300 ms.', fromActor: 'phone', toActor: 'tag', duration: 800, highlight: ['Payload'], data: 'OS opens https://transit.example.com/qr', - layers: [createNDEFLayer({ header: 'parsed', typeLen: 1, payloadLen: 21, type: "'U' (URI)", payload: 'https://transit.example.com/qr β†’ handed to default browser' })] + layers: [ + createNDEFLayer({ + header: 'parsed', + typeLen: 1, + payloadLen: 21, + type: "'U' (URI)", + payload: 'https://transit.example.com/qr β†’ handed to default browser' + }) + ] } ] }; diff --git a/src/lib/simulator/simulations/oauth2-flow.ts b/src/lib/simulator/simulations/oauth2-flow.ts index 883e989..fa2fb01 100644 --- a/src/lib/simulator/simulations/oauth2-flow.ts +++ b/src/lib/simulator/simulations/oauth2-flow.ts @@ -52,8 +52,7 @@ function httpRequestLayer( bits: 0, value: extra.auth, editable: false, - description: - 'Authorization header β€” carries the Bearer access token', + description: 'Authorization header β€” carries the Bearer access token', color: '#2DD4BF' } ] @@ -128,7 +127,7 @@ export const oauth2Flow: SimulationConfig = { protocolId: 'oauth2', title: 'OAuth 2.0 Authorization Code + PKCE', description: - 'See how OAuth 2.0 delegates authorization through a three-party redirect flow. The app never sees the user\'s password β€” instead it receives a scoped access token after the user consents at the authorization server.', + "See how OAuth 2.0 delegates authorization through a three-party redirect flow. The app never sees the user's password β€” instead it receives a scoped access token after the user consents at the authorization server.", tier: 'client', actors: [ { id: 'app', label: 'Your App', icon: 'browser', position: 'left' }, @@ -149,7 +148,7 @@ export const oauth2Flow: SimulationConfig = { id: 'pkce-redirect', label: 'Authorization Request', description: - 'App generates a random code_verifier and its SHA-256 hash (code_challenge) for PKCE. Then it redirects the user\'s browser to the authorization server with client_id, scope, state, and the code_challenge.', + "App generates a random code_verifier and its SHA-256 hash (code_challenge) for PKCE. Then it redirects the user's browser to the authorization server with client_id, scope, state, and the code_challenge.", fromActor: 'app', toActor: 'auth', duration: 800, @@ -182,7 +181,7 @@ export const oauth2Flow: SimulationConfig = { id: 'user-consent', label: 'User Consent', description: - 'Auth server presents a consent screen showing what the app is requesting. The user authenticates (if not already logged in) and approves the requested scopes. The app never sees the user\'s credentials.', + "Auth server presents a consent screen showing what the app is requesting. The user authenticates (if not already logged in) and approves the requested scopes. The app never sees the user's credentials.", fromActor: 'auth', toActor: 'app', duration: 1200, @@ -215,7 +214,7 @@ export const oauth2Flow: SimulationConfig = { id: 'auth-code', label: 'Authorization Code', description: - 'After consent, the auth server redirects the browser back to the app\'s callback URL with a short-lived authorization code and the original state parameter for CSRF verification.', + "After consent, the auth server redirects the browser back to the app's callback URL with a short-lived authorization code and the original state parameter for CSRF verification.", fromActor: 'auth', toActor: 'app', duration: 800, @@ -368,11 +367,7 @@ export const oauth2Flow: SimulationConfig = { cipherSuite: 'AES-256-GCM', length: 384 }), - httpResponseLayer( - '200 OK', - '#22c55e', - '{id:42, name:"Alice", email:"alice@example.com"}' - ) + httpResponseLayer('200 OK', '#22c55e', '{id:42, name:"Alice", email:"alice@example.com"}') ] } ] diff --git a/src/lib/simulator/simulations/ospf-adjacency.ts b/src/lib/simulator/simulations/ospf-adjacency.ts index 0415c48..5fc341e 100644 --- a/src/lib/simulator/simulations/ospf-adjacency.ts +++ b/src/lib/simulator/simulations/ospf-adjacency.ts @@ -7,7 +7,7 @@ export const ospfAdjacency: SimulationConfig = { protocolId: 'ospf', title: 'OSPF Adjacency β€” Cold Boot to Full', description: - "Watch two routers walk the eight-state OSPF adjacency machine, synchronise their link-state databases, and converge. The protocol runs directly on IP (protocol 89) using link-local multicast 224.0.0.5 β€” no TCP, no UDP.", + 'Watch two routers walk the eight-state OSPF adjacency machine, synchronise their link-state databases, and converge. The protocol runs directly on IP (protocol 89) using link-local multicast 224.0.0.5 β€” no TCP, no UDP.', tier: 'server', actors: [ { id: 'r1', label: 'Router R1', icon: 'router', position: 'left' }, @@ -154,7 +154,7 @@ export const ospfAdjacency: SimulationConfig = { id: 'lsack', label: 'LSAck (Full)', description: - "R1 acknowledges every LSA. OSPF implements reliable delivery on top of raw IP β€” no TCP underneath. Both routers are now Full: identical LSDB, ready to run Dijkstra.", + 'R1 acknowledges every LSA. OSPF implements reliable delivery on top of raw IP β€” no TCP underneath. Both routers are now Full: identical LSDB, ready to run Dijkstra.', fromActor: 'r1', toActor: 'r2', duration: 1000, @@ -190,23 +190,26 @@ export const ospfAdjacency: SimulationConfig = { { name: 'Algorithm', bits: 0, - value: "Dijkstra (E.W. Dijkstra, 1956)", + value: 'Dijkstra (E.W. Dijkstra, 1956)', editable: false, - description: 'The shortest-path-first algorithm β€” every link-state router runs it locally on its own LSDB' + description: + 'The shortest-path-first algorithm β€” every link-state router runs it locally on its own LSDB' }, { name: 'Throttle', bits: 0, value: 'RFC 8405: 50 / 200 / 5000 ms', editable: false, - description: 'SPF back-off: INITIAL, SHORT_WAIT, LONG_WAIT β€” prevents thrashing on rapid topology churn' + description: + 'SPF back-off: INITIAL, SHORT_WAIT, LONG_WAIT β€” prevents thrashing on rapid topology churn' }, { name: 'Result', bits: 0, value: 'Shortest-path tree from R1 installed into FIB', editable: false, - description: 'The forwarding information base β€” what hardware actually uses to forward packets' + description: + 'The forwarding information base β€” what hardware actually uses to forward packets' } ] } diff --git a/src/lib/simulator/simulations/quic-connection.ts b/src/lib/simulator/simulations/quic-connection.ts index 6d64d12..6ba2dc8 100644 --- a/src/lib/simulator/simulations/quic-connection.ts +++ b/src/lib/simulator/simulations/quic-connection.ts @@ -43,7 +43,7 @@ export const quicConnection: SimulationConfig = { id: 'handshake', label: 'Handshake', description: - 'The server responds with an Initial packet (containing ServerHello) followed by a Handshake packet with its certificate and Finished message. The server\'s Initial carries the TLS ServerHello, while the Handshake packet carries encrypted certificate data. This completes the server side of the cryptographic handshake.', + "The server responds with an Initial packet (containing ServerHello) followed by a Handshake packet with its certificate and Finished message. The server's Initial carries the TLS ServerHello, while the Handshake packet carries encrypted certificate data. This completes the server side of the cryptographic handshake.", fromActor: 'server', toActor: 'client', duration: 1000, @@ -115,7 +115,7 @@ export const quicConnection: SimulationConfig = { id: 'close', label: 'Connection Close', description: - 'Either side can close the connection immediately with a CONNECTION_CLOSE frame. Unlike TCP\'s four-way FIN handshake, QUIC closes in a single packet. The frame includes an error code (0 = no error) and an optional reason phrase. The peer enters a draining period before freeing connection state.', + "Either side can close the connection immediately with a CONNECTION_CLOSE frame. Unlike TCP's four-way FIN handshake, QUIC closes in a single packet. The frame includes an error code (0 = no error) and an optional reason phrase. The peer enters a draining period before freeing connection state.", fromActor: 'client', toActor: 'server', duration: 600, diff --git a/src/lib/simulator/simulations/rest-api.ts b/src/lib/simulator/simulations/rest-api.ts index 6483d99..8f34cc2 100644 --- a/src/lib/simulator/simulations/rest-api.ts +++ b/src/lib/simulator/simulations/rest-api.ts @@ -10,13 +10,59 @@ function httpRequestLayer(method: string, path: string, body?: string) { osiLayer: 7, color: '#00D4FF', headerFields: [ - { name: 'Method', bits: 0, value: method, editable: false, description: `HTTP method β€” ${method} retrieves or modifies a resource` }, - { name: 'Path', bits: 0, value: path, editable: false, description: 'REST resource path β€” follows /resource/{id} convention' }, - { name: 'Version', bits: 0, value: 'HTTP/1.1', editable: false, description: 'Protocol version' }, - { name: 'Host', bits: 0, value: 'api.example.com', editable: false, description: 'API server hostname' }, - { name: 'Content-Type', bits: 0, value: 'application/json', editable: false, description: 'MIME type β€” REST APIs typically use JSON' }, - ...(body ? [{ name: 'Body', bits: 0, value: body, editable: false, description: 'JSON request body β€” the resource representation' }] : []), - { name: 'Accept', bits: 0, value: 'application/json', editable: false, description: 'Client tells the server it expects JSON responses' } + { + name: 'Method', + bits: 0, + value: method, + editable: false, + description: `HTTP method β€” ${method} retrieves or modifies a resource` + }, + { + name: 'Path', + bits: 0, + value: path, + editable: false, + description: 'REST resource path β€” follows /resource/{id} convention' + }, + { + name: 'Version', + bits: 0, + value: 'HTTP/1.1', + editable: false, + description: 'Protocol version' + }, + { + name: 'Host', + bits: 0, + value: 'api.example.com', + editable: false, + description: 'API server hostname' + }, + { + name: 'Content-Type', + bits: 0, + value: 'application/json', + editable: false, + description: 'MIME type β€” REST APIs typically use JSON' + }, + ...(body + ? [ + { + name: 'Body', + bits: 0, + value: body, + editable: false, + description: 'JSON request body β€” the resource representation' + } + ] + : []), + { + name: 'Accept', + bits: 0, + value: 'application/json', + editable: false, + description: 'Client tells the server it expects JSON responses' + } ] }; } @@ -28,10 +74,35 @@ function httpResponseLayer(status: string, body: string, statusColor: string) { osiLayer: 7, color: '#00D4FF', headerFields: [ - { name: 'Version', bits: 0, value: 'HTTP/1.1', editable: false, description: 'Protocol version' }, - { name: 'Status', bits: 0, value: status, editable: false, description: `HTTP status code β€” ${status}`, color: statusColor }, - { name: 'Content-Type', bits: 0, value: 'application/json', editable: false, description: 'Response body is JSON-encoded' }, - { name: 'Body', bits: 0, value: body, editable: false, description: 'JSON response body β€” the resource representation' } + { + name: 'Version', + bits: 0, + value: 'HTTP/1.1', + editable: false, + description: 'Protocol version' + }, + { + name: 'Status', + bits: 0, + value: status, + editable: false, + description: `HTTP status code β€” ${status}`, + color: statusColor + }, + { + name: 'Content-Type', + bits: 0, + value: 'application/json', + editable: false, + description: 'Response body is JSON-encoded' + }, + { + name: 'Body', + bits: 0, + value: body, + editable: false, + description: 'JSON response body β€” the resource representation' + } ] }; } diff --git a/src/lib/simulator/simulations/rtp-media.ts b/src/lib/simulator/simulations/rtp-media.ts index 8b5e80f..aeb4d47 100644 --- a/src/lib/simulator/simulations/rtp-media.ts +++ b/src/lib/simulator/simulations/rtp-media.ts @@ -11,10 +11,34 @@ function createRTCPLayer(reportType: string, ssrc: string, payload: string): Pro osiLayer: 7, color: '#BE185D', headerFields: [ - { name: 'Version', bits: 2, value: 2, editable: false, description: 'RTCP version β€” always 2' }, - { name: 'Report Type', bits: 8, value: reportType, editable: false, description: 'RTCP packet type β€” SR (200), RR (201), SDES (202), BYE (203)' }, - { name: 'SSRC', bits: 32, value: ssrc, editable: false, description: 'SSRC of the report sender' }, - { name: 'Report Data', bits: 0, value: payload, editable: false, description: 'Statistics β€” NTP timestamp, packet count, jitter, loss fraction' } + { + name: 'Version', + bits: 2, + value: 2, + editable: false, + description: 'RTCP version β€” always 2' + }, + { + name: 'Report Type', + bits: 8, + value: reportType, + editable: false, + description: 'RTCP packet type β€” SR (200), RR (201), SDES (202), BYE (203)' + }, + { + name: 'SSRC', + bits: 32, + value: ssrc, + editable: false, + description: 'SSRC of the report sender' + }, + { + name: 'Report Data', + bits: 0, + value: payload, + editable: false, + description: 'Statistics β€” NTP timestamp, packet count, jitter, loss fraction' + } ] }; } @@ -89,7 +113,11 @@ export const rtpMedia: SimulationConfig = { createEthernetLayer(), createIPv4Layer({ protocol: 17 }), createUDPLayer({ srcPort: 5005, dstPort: 5005 }), - createRTCPLayer('SR (200)', '0x12345678', 'NTP: 2026-03-13 14:30:00, Packets: 1500, Bytes: 240000') + createRTCPLayer( + 'SR (200)', + '0x12345678', + 'NTP: 2026-03-13 14:30:00, Packets: 1500, Bytes: 240000' + ) ] }, { @@ -105,7 +133,11 @@ export const rtpMedia: SimulationConfig = { createEthernetLayer({ srcMac: 'AA:BB:CC:DD:EE:FF', dstMac: '00:1A:2B:3C:4D:5E' }), createIPv4Layer({ srcIp: '93.184.216.34', dstIp: '192.168.1.100', protocol: 17 }), createUDPLayer({ srcPort: 5005, dstPort: 5005 }), - createRTCPLayer('RR (201)', '0x87654321', 'Loss: 0.5%, Jitter: 12ms, Last SR: 14:30:00, Delay: 45ms') + createRTCPLayer( + 'RR (201)', + '0x87654321', + 'Loss: 0.5%, Jitter: 12ms, Last SR: 14:30:00, Delay: 45ms' + ) ] } ] diff --git a/src/lib/simulator/simulations/sctp-association.ts b/src/lib/simulator/simulations/sctp-association.ts index 8535a0f..2e4b4dd 100644 --- a/src/lib/simulator/simulations/sctp-association.ts +++ b/src/lib/simulator/simulations/sctp-association.ts @@ -7,7 +7,7 @@ export const sctpAssociation: SimulationConfig = { protocolId: 'sctp', title: 'SCTP β€” Multi-Stream Association', description: - 'Watch SCTP\'s four-way handshake that establishes a multi-stream association. Unlike TCP\'s three-way handshake, SCTP uses a cookie mechanism to prevent SYN flood attacks. SCTP also supports multi-homing β€” a single association can span multiple IP addresses for failover.', + "Watch SCTP's four-way handshake that establishes a multi-stream association. Unlike TCP's three-way handshake, SCTP uses a cookie mechanism to prevent SYN flood attacks. SCTP also supports multi-homing β€” a single association can span multiple IP addresses for failover.", tier: 'client', actors: [ { id: 'client', label: 'Client', icon: 'client', position: 'left' }, @@ -40,7 +40,7 @@ export const sctpAssociation: SimulationConfig = { id: 'init-ack', label: 'INIT-ACK', description: - 'The server responds with INIT-ACK containing its own parameters and a State Cookie. The cookie is a signed bundle of both sides\' parameters β€” crucially, the server still allocates no state. This cookie-based design makes SCTP immune to SYN flood denial-of-service attacks.', + "The server responds with INIT-ACK containing its own parameters and a State Cookie. The cookie is a signed bundle of both sides' parameters β€” crucially, the server still allocates no state. This cookie-based design makes SCTP immune to SYN flood denial-of-service attacks.", fromActor: 'server', toActor: 'client', duration: 800, diff --git a/src/lib/simulator/simulations/sdp-negotiation.ts b/src/lib/simulator/simulations/sdp-negotiation.ts index e5e820f..e5e1bfc 100644 --- a/src/lib/simulator/simulations/sdp-negotiation.ts +++ b/src/lib/simulator/simulations/sdp-negotiation.ts @@ -10,9 +10,28 @@ function createSDPLayer(type: string, fields: string, media: string): ProtocolLa osiLayer: 7, color: '#A855F7', headerFields: [ - { name: 'Type', bits: 0, value: type, editable: false, description: 'SDP role β€” Offer (initial proposal) or Answer (accepted subset)' }, - { name: 'Session Fields', bits: 0, value: fields, editable: false, description: 'Session-level fields β€” v= (version), o= (origin), s= (session name), t= (timing)' }, - { name: 'Media', bits: 0, value: media, editable: false, description: 'Media descriptions β€” m= lines with port, protocol, and format list' }, + { + name: 'Type', + bits: 0, + value: type, + editable: false, + description: 'SDP role β€” Offer (initial proposal) or Answer (accepted subset)' + }, + { + name: 'Session Fields', + bits: 0, + value: fields, + editable: false, + description: + 'Session-level fields β€” v= (version), o= (origin), s= (session name), t= (timing)' + }, + { + name: 'Media', + bits: 0, + value: media, + editable: false, + description: 'Media descriptions β€” m= lines with port, protocol, and format list' + } ] }; } @@ -24,8 +43,20 @@ function signalingLayer(action: string): ProtocolLayer { osiLayer: 7, color: '#6366F1', headerFields: [ - { name: 'Action', bits: 0, value: action, editable: false, description: 'Signaling action β€” carried over WebSocket, HTTP, or SIP' }, - { name: 'Content-Type', bits: 0, value: 'application/sdp', editable: false, description: 'The payload is an SDP description' } + { + name: 'Action', + bits: 0, + value: action, + editable: false, + description: 'Signaling action β€” carried over WebSocket, HTTP, or SIP' + }, + { + name: 'Content-Type', + bits: 0, + value: 'application/sdp', + editable: false, + description: 'The payload is an SDP description' + } ] }; } diff --git a/src/lib/simulator/simulations/sip-call.ts b/src/lib/simulator/simulations/sip-call.ts index 031e966..b94f95a 100644 --- a/src/lib/simulator/simulations/sip-call.ts +++ b/src/lib/simulator/simulations/sip-call.ts @@ -65,7 +65,7 @@ export const sipCall: SimulationConfig = { id: 'ringing', label: '180 Ringing', description: - 'The callee\'s phone is ringing. The 180 Ringing response is forwarded back through the proxy chain. The caller can now play a ringback tone. This provisional response can optionally include early media (ringback from the callee\'s network) via SDP.', + "The callee's phone is ringing. The 180 Ringing response is forwarded back through the proxy chain. The caller can now play a ringback tone. This provisional response can optionally include early media (ringback from the callee's network) via SDP.", fromActor: 'server', toActor: 'caller', duration: 800, diff --git a/src/lib/simulator/simulations/smtp-delivery.ts b/src/lib/simulator/simulations/smtp-delivery.ts index 8664a46..89b5f07 100644 --- a/src/lib/simulator/simulations/smtp-delivery.ts +++ b/src/lib/simulator/simulations/smtp-delivery.ts @@ -160,7 +160,7 @@ export const smtpDelivery: SimulationConfig = { id: 'queued', label: '250 Queued', description: - 'The server accepts the message for delivery and returns a queue ID. The 250 code means the server has taken responsibility for delivering this email. The message will now be relayed to the recipient\'s mail server by looking up MX records in DNS.', + "The server accepts the message for delivery and returns a queue ID. The 250 code means the server has taken responsibility for delivering this email. The message will now be relayed to the recipient's mail server by looking up MX records in DNS.", fromActor: 'server', toActor: 'client', duration: 800, diff --git a/src/lib/simulator/simulations/soap-request.ts b/src/lib/simulator/simulations/soap-request.ts index 1c3e00d..2c19d3c 100644 --- a/src/lib/simulator/simulations/soap-request.ts +++ b/src/lib/simulator/simulations/soap-request.ts @@ -58,8 +58,7 @@ function httpRequestLayer( bits: 0, value: extra.soapAction, editable: false, - description: - 'HTTP header identifying the SOAP operation β€” required by SOAP 1.1' + description: 'HTTP header identifying the SOAP operation β€” required by SOAP 1.1' } ] : []) @@ -252,11 +251,7 @@ export const soapRequest: SimulationConfig = { protocol: 6 }), createTCPLayer({ srcPort: 80, dstPort: 51400, flags: 'PSH,ACK' }), - httpResponseLayer( - '500 Internal Server Error', - 'text/xml; charset=utf-8', - '#ef4444' - ), + httpResponseLayer('500 Internal Server Error', 'text/xml; charset=utf-8', '#ef4444'), createSOAPLayer({ body: 'Fault(code: "Client", string: "Invalid user ID")', header: 'faultactor: http://example.com/UserService' diff --git a/src/lib/simulator/simulations/sse-stream.ts b/src/lib/simulator/simulations/sse-stream.ts index 56384e0..d206e70 100644 --- a/src/lib/simulator/simulations/sse-stream.ts +++ b/src/lib/simulator/simulations/sse-stream.ts @@ -11,11 +11,41 @@ function sseRequestLayer(): ProtocolLayer { osiLayer: 7, color: '#00D4FF', headerFields: [ - { name: 'Method', bits: 0, value: 'GET', editable: false, description: 'SSE uses a standard GET request β€” no upgrade or special handshake needed' }, - { name: 'Path', bits: 0, value: '/events', editable: false, description: 'Event stream endpoint β€” the server will hold this connection open' }, - { name: 'Accept', bits: 0, value: 'text/event-stream', editable: false, description: 'Tells the server the client wants an SSE stream, not a regular response' }, - { name: 'Cache-Control', bits: 0, value: 'no-cache', editable: false, description: 'Prevents caching β€” events should always be received fresh from the server' }, - { name: 'Connection', bits: 0, value: 'keep-alive', editable: false, description: 'The connection stays open for the stream duration' } + { + name: 'Method', + bits: 0, + value: 'GET', + editable: false, + description: 'SSE uses a standard GET request β€” no upgrade or special handshake needed' + }, + { + name: 'Path', + bits: 0, + value: '/events', + editable: false, + description: 'Event stream endpoint β€” the server will hold this connection open' + }, + { + name: 'Accept', + bits: 0, + value: 'text/event-stream', + editable: false, + description: 'Tells the server the client wants an SSE stream, not a regular response' + }, + { + name: 'Cache-Control', + bits: 0, + value: 'no-cache', + editable: false, + description: 'Prevents caching β€” events should always be received fresh from the server' + }, + { + name: 'Connection', + bits: 0, + value: 'keep-alive', + editable: false, + description: 'The connection stays open for the stream duration' + } ] }; } @@ -27,25 +57,85 @@ function sseResponseLayer(): ProtocolLayer { osiLayer: 7, color: '#00D4FF', headerFields: [ - { name: 'Status', bits: 0, value: '200 OK', editable: false, description: 'Stream opened successfully β€” data will follow incrementally', color: '#22c55e' }, - { name: 'Content-Type', bits: 0, value: 'text/event-stream', editable: false, description: 'SSE MIME type β€” tells the browser to use EventSource API' }, - { name: 'Cache-Control', bits: 0, value: 'no-cache', editable: false, description: 'No caching for live event streams' }, - { name: 'Connection', bits: 0, value: 'keep-alive', editable: false, description: 'Connection remains open β€” no Content-Length since the stream is infinite' } + { + name: 'Status', + bits: 0, + value: '200 OK', + editable: false, + description: 'Stream opened successfully β€” data will follow incrementally', + color: '#22c55e' + }, + { + name: 'Content-Type', + bits: 0, + value: 'text/event-stream', + editable: false, + description: 'SSE MIME type β€” tells the browser to use EventSource API' + }, + { + name: 'Cache-Control', + bits: 0, + value: 'no-cache', + editable: false, + description: 'No caching for live event streams' + }, + { + name: 'Connection', + bits: 0, + value: 'keep-alive', + editable: false, + description: 'Connection remains open β€” no Content-Length since the stream is infinite' + } ] }; } -function sseEventLayer(eventType: string, eventId: string, data: string, retry: string): ProtocolLayer { +function sseEventLayer( + eventType: string, + eventId: string, + data: string, + retry: string +): ProtocolLayer { return { name: 'SSE Event', abbreviation: 'SSE', osiLayer: 7, color: '#EF4444', headerFields: [ - { name: 'Event Type', bits: 0, value: eventType, editable: false, description: 'Named event type β€” clients listen for specific types with addEventListener()' }, - { name: 'Event ID', bits: 0, value: eventId, editable: false, description: 'Unique event identifier β€” sent as Last-Event-ID on reconnect for resumption' }, - { name: 'Data', bits: 0, value: data, editable: false, description: 'Event payload β€” UTF-8 text, typically JSON. Multiple data: lines are joined with newlines' }, - ...(retry ? [{ name: 'Retry', bits: 0, value: retry, editable: false, description: 'Reconnection interval in milliseconds β€” browser waits this long before reconnecting' }] : []) + { + name: 'Event Type', + bits: 0, + value: eventType, + editable: false, + description: 'Named event type β€” clients listen for specific types with addEventListener()' + }, + { + name: 'Event ID', + bits: 0, + value: eventId, + editable: false, + description: 'Unique event identifier β€” sent as Last-Event-ID on reconnect for resumption' + }, + { + name: 'Data', + bits: 0, + value: data, + editable: false, + description: + 'Event payload β€” UTF-8 text, typically JSON. Multiple data: lines are joined with newlines' + }, + ...(retry + ? [ + { + name: 'Retry', + bits: 0, + value: retry, + editable: false, + description: + 'Reconnection interval in milliseconds β€” browser waits this long before reconnecting' + } + ] + : []) ] }; } @@ -83,7 +173,10 @@ export const sseStream: SimulationConfig = { createEthernetLayer(), createIPv4Layer({ protocol: 6 }), createTCPLayer({ srcPort: 52500, dstPort: 443, flags: 'PSH,ACK' }), - createTLSRecordLayer({ contentType: 'Application Data (23)', handshakeType: 'N/A (encrypted)' }), + createTLSRecordLayer({ + contentType: 'Application Data (23)', + handshakeType: 'N/A (encrypted)' + }), sseRequestLayer() ] }, @@ -100,7 +193,10 @@ export const sseStream: SimulationConfig = { createEthernetLayer({ srcMac: 'AA:BB:CC:DD:EE:FF', dstMac: '00:1A:2B:3C:4D:5E' }), createIPv4Layer({ srcIp: '93.184.216.34', dstIp: '192.168.1.100', protocol: 6 }), createTCPLayer({ srcPort: 443, dstPort: 52500, flags: 'PSH,ACK' }), - createTLSRecordLayer({ contentType: 'Application Data (23)', handshakeType: 'N/A (encrypted)' }), + createTLSRecordLayer({ + contentType: 'Application Data (23)', + handshakeType: 'N/A (encrypted)' + }), sseResponseLayer() ] }, @@ -149,7 +245,12 @@ export const sseStream: SimulationConfig = { createEthernetLayer({ srcMac: 'AA:BB:CC:DD:EE:FF', dstMac: '00:1A:2B:3C:4D:5E' }), createIPv4Layer({ srcIp: '93.184.216.34', dstIp: '192.168.1.100', protocol: 6 }), createTCPLayer({ srcPort: 443, dstPort: 52500, flags: 'PSH,ACK' }), - sseEventLayer('notification', 'evt-003', '{"alert": "System maintenance in 10 minutes"}', '5000') + sseEventLayer( + 'notification', + 'evt-003', + '{"alert": "System maintenance in 10 minutes"}', + '5000' + ) ] }, { diff --git a/src/lib/simulator/simulations/stomp-subscription.ts b/src/lib/simulator/simulations/stomp-subscription.ts index ac13794..10d8de3 100644 --- a/src/lib/simulator/simulations/stomp-subscription.ts +++ b/src/lib/simulator/simulations/stomp-subscription.ts @@ -28,7 +28,7 @@ export const stompSubscription: SimulationConfig = { id: 'connect', label: 'CONNECT', description: - 'The client sends a CONNECT frame with login credentials and protocol version. STOMP frames are human-readable text: a command line, headers as key:value pairs, a blank line, an optional body, and a null character terminator. This simplicity is STOMP\'s main advantage.', + "The client sends a CONNECT frame with login credentials and protocol version. STOMP frames are human-readable text: a command line, headers as key:value pairs, a blank line, an optional body, and a null character terminator. This simplicity is STOMP's main advantage.", fromActor: 'client', toActor: 'broker', duration: 800, diff --git a/src/lib/simulator/simulations/tcp-handshake.ts b/src/lib/simulator/simulations/tcp-handshake.ts index fc70e0e..534505c 100644 --- a/src/lib/simulator/simulations/tcp-handshake.ts +++ b/src/lib/simulator/simulations/tcp-handshake.ts @@ -50,7 +50,7 @@ export const tcpHandshake: SimulationConfig = { id: 'syn-ack', label: 'SYN-ACK', description: - 'Server acknowledges the client\'s SYN and sends its own SYN. The ACK number equals the client\'s sequence + 1, confirming receipt.', + "Server acknowledges the client's SYN and sends its own SYN. The ACK number equals the client's sequence + 1, confirming receipt.", fromActor: 'server', toActor: 'client', duration: 1200, @@ -78,7 +78,7 @@ export const tcpHandshake: SimulationConfig = { id: 'ack', label: 'ACK', description: - 'Client completes the handshake by acknowledging the server\'s SYN. The connection is now ESTABLISHED β€” both sides agree on sequence numbers.', + "Client completes the handshake by acknowledging the server's SYN. The connection is now ESTABLISHED β€” both sides agree on sequence numbers.", fromActor: 'client', toActor: 'server', duration: 1000, diff --git a/src/lib/simulator/simulations/tls-handshake.ts b/src/lib/simulator/simulations/tls-handshake.ts index 9334393..aaee2f8 100644 --- a/src/lib/simulator/simulations/tls-handshake.ts +++ b/src/lib/simulator/simulations/tls-handshake.ts @@ -82,7 +82,7 @@ export const tlsHandshake: SimulationConfig = { createTLSRecordLayer({ handshakeType: 'Certificate + Verify', cipherSuite: 'TLS_AES_256_GCM_SHA384', - extensions: 'CN=example.com, Issuer=Let\'s Encrypt', + extensions: "CN=example.com, Issuer=Let's Encrypt", length: 2048 }) ] diff --git a/src/lib/simulator/simulations/udp-datagram.ts b/src/lib/simulator/simulations/udp-datagram.ts index d2e111e..f4cd1f0 100644 --- a/src/lib/simulator/simulations/udp-datagram.ts +++ b/src/lib/simulator/simulations/udp-datagram.ts @@ -27,7 +27,7 @@ export const udpDatagram: SimulationConfig = { id: 'dgram-1', label: 'Datagram #1', description: - 'UDP sends the first datagram immediately β€” no connection setup needed. Notice the minimal 8-byte header compared to TCP\'s 20 bytes.', + "UDP sends the first datagram immediately β€” no connection setup needed. Notice the minimal 8-byte header compared to TCP's 20 bytes.", fromActor: 'sender', toActor: 'receiver', duration: 800, @@ -42,7 +42,13 @@ export const udpDatagram: SimulationConfig = { osiLayer: 7, color: '#00D4FF', headerFields: [ - { name: 'Payload', bits: 0, value: 'Packet #1: Hello!', editable: false, description: 'Application payload β€” sent without waiting for acknowledgment' } + { + name: 'Payload', + bits: 0, + value: 'Packet #1: Hello!', + editable: false, + description: 'Application payload β€” sent without waiting for acknowledgment' + } ] } ] @@ -51,7 +57,7 @@ export const udpDatagram: SimulationConfig = { id: 'dgram-2', label: 'Datagram #2', description: - 'The second datagram is sent right away β€” UDP doesn\'t wait for the first one to be acknowledged. Each datagram is independent.', + "The second datagram is sent right away β€” UDP doesn't wait for the first one to be acknowledged. Each datagram is independent.", fromActor: 'sender', toActor: 'receiver', duration: 800, @@ -66,7 +72,13 @@ export const udpDatagram: SimulationConfig = { osiLayer: 7, color: '#00D4FF', headerFields: [ - { name: 'Payload', bits: 0, value: 'Packet #2: World!', editable: false, description: 'Another independent datagram' } + { + name: 'Payload', + bits: 0, + value: 'Packet #2: World!', + editable: false, + description: 'Another independent datagram' + } ] } ] @@ -90,7 +102,14 @@ export const udpDatagram: SimulationConfig = { osiLayer: 7, color: '#ef4444', headerFields: [ - { name: 'Payload', bits: 0, value: 'Packet #3: Lost!', editable: false, description: 'This datagram never arrives β€” lost in the network', color: '#ef4444' } + { + name: 'Payload', + bits: 0, + value: 'Packet #3: Lost!', + editable: false, + description: 'This datagram never arrives β€” lost in the network', + color: '#ef4444' + } ] } ] @@ -99,7 +118,7 @@ export const udpDatagram: SimulationConfig = { id: 'dgram-4', label: 'Datagram #4', description: - 'The sender keeps going, unaware that datagram #3 was lost. This is the trade-off: UDP is fast because it doesn\'t wait, but unreliable.', + "The sender keeps going, unaware that datagram #3 was lost. This is the trade-off: UDP is fast because it doesn't wait, but unreliable.", fromActor: 'sender', toActor: 'receiver', duration: 800, @@ -113,7 +132,13 @@ export const udpDatagram: SimulationConfig = { osiLayer: 7, color: '#00D4FF', headerFields: [ - { name: 'Payload', bits: 0, value: 'Packet #4: Still here', editable: false, description: 'The sender continues without knowing about the loss' } + { + name: 'Payload', + bits: 0, + value: 'Packet #4: Still here', + editable: false, + description: 'The sender continues without knowing about the loss' + } ] } ] @@ -122,7 +147,7 @@ export const udpDatagram: SimulationConfig = { id: 'dgram-5', label: 'Datagram #5', description: - 'Final datagram sent. The receiver got packets 1, 2, 4, and 5 β€” but not 3. If ordering matters, the application must handle that itself (UDP doesn\'t).', + "Final datagram sent. The receiver got packets 1, 2, 4, and 5 β€” but not 3. If ordering matters, the application must handle that itself (UDP doesn't).", fromActor: 'sender', toActor: 'receiver', duration: 800, @@ -136,7 +161,13 @@ export const udpDatagram: SimulationConfig = { osiLayer: 7, color: '#00D4FF', headerFields: [ - { name: 'Payload', bits: 0, value: 'Packet #5: Done', editable: false, description: 'Last datagram β€” receiver reconstructs what it can' } + { + name: 'Payload', + bits: 0, + value: 'Packet #5: Done', + editable: false, + description: 'Last datagram β€” receiver reconstructs what it can' + } ] } ] diff --git a/src/lib/simulator/simulations/uwb-ranging.ts b/src/lib/simulator/simulations/uwb-ranging.ts index f0465f7..6ddb4ea 100644 --- a/src/lib/simulator/simulations/uwb-ranging.ts +++ b/src/lib/simulator/simulations/uwb-ranging.ts @@ -5,7 +5,7 @@ export const uwbRanging: SimulationConfig = { protocolId: 'uwb', title: 'UWB Ranging β€” BLE bootstrap β†’ DS-TWR β†’ distance', description: - "The five beats every consumer UWB session walks: BLE advertise β†’ BLE GATT pairing + STS_KEY transport β†’ UWB Poll β†’ UWB Response β†’ UWB Final β†’ distance. Same flow under AirTag Precision Finding, BMW Digital Key, Aqara U400 hands-free unlock, and (from Feb 2026) Aliro 1.0 for everyone else.", + 'The five beats every consumer UWB session walks: BLE advertise β†’ BLE GATT pairing + STS_KEY transport β†’ UWB Poll β†’ UWB Response β†’ UWB Final β†’ distance. Same flow under AirTag Precision Finding, BMW Digital Key, Aqara U400 hands-free unlock, and (from Feb 2026) Aliro 1.0 for everyone else.', tier: 'client', actors: [ { id: 'phone', label: 'iPhone (Initiator)', icon: 'device', position: 'left' }, @@ -17,10 +17,7 @@ export const uwbRanging: SimulationConfig = { label: 'UWB channel', type: 'select', defaultValue: 'Channel 9 (7987.2 MHz)', - options: [ - 'Channel 5 (6489.6 MHz, universal)', - 'Channel 9 (7987.2 MHz, restricted in Japan)' - ] + options: ['Channel 5 (6489.6 MHz, universal)', 'Channel 9 (7987.2 MHz, restricted in Japan)'] }, { id: 'mode', @@ -165,7 +162,7 @@ export const uwbRanging: SimulationConfig = { id: 'compute-tof', label: 'Compute ToF β€” DS-TWR cross-product cancels clock drift', description: - "The anchor (or phone, in some implementations) plugs all six timestamps into the cross-product:\n\n`ToF = (T_round1 Β· T_round2 βˆ’ T_reply1 Β· T_reply2) / (T_round1 + T_round2 + T_reply1 + T_reply2)`\n\nwhere `T_round1 = t4βˆ’t1`, `T_reply1 = t3βˆ’t2`, `T_round2 = t6βˆ’t3`, `T_reply2 = t5βˆ’t4`. The cross-product cancels relative clock drift to first order β€” DS-TWR is insensitive to 20 ppm crystal offsets, where SS-TWR would yield ~1.2 m of bias under the same conditions. Multiply ToF by `c β‰ˆ 0.299792458 m/ns` to get distance.", + 'The anchor (or phone, in some implementations) plugs all six timestamps into the cross-product:\n\n`ToF = (T_round1 Β· T_round2 βˆ’ T_reply1 Β· T_reply2) / (T_round1 + T_round2 + T_reply1 + T_reply2)`\n\nwhere `T_round1 = t4βˆ’t1`, `T_reply1 = t3βˆ’t2`, `T_round2 = t6βˆ’t3`, `T_reply2 = t5βˆ’t4`. The cross-product cancels relative clock drift to first order β€” DS-TWR is insensitive to 20 ppm crystal offsets, where SS-TWR would yield ~1.2 m of bias under the same conditions. Multiply ToF by `c β‰ˆ 0.299792458 m/ns` to get distance.', fromActor: 'anchor', toActor: 'phone', duration: 800, diff --git a/src/lib/simulator/simulations/webrtc-peer.ts b/src/lib/simulator/simulations/webrtc-peer.ts index 01c455f..f7ec031 100644 --- a/src/lib/simulator/simulations/webrtc-peer.ts +++ b/src/lib/simulator/simulations/webrtc-peer.ts @@ -38,7 +38,8 @@ function createSDPLayer(type: 'Offer' | 'Answer') { bits: 0, value: 'sha-256 AB:CD:...', editable: false, - description: 'DTLS certificate fingerprint β€” verified during DTLS handshake for authentication' + description: + 'DTLS certificate fingerprint β€” verified during DTLS handshake for authentication' } ] }; @@ -170,7 +171,7 @@ export const webrtcPeer: SimulationConfig = { id: 'sdp-answer-relay', label: 'SDP Answer (relay)', description: - 'Signaling server relays the answer to Peer A. Both peers now know each other\'s capabilities. Next, ICE connectivity checks will find the best direct path between them.', + "Signaling server relays the answer to Peer A. Both peers now know each other's capabilities. Next, ICE connectivity checks will find the best direct path between them.", fromActor: 'signal', toActor: 'peerA', duration: 600, @@ -186,7 +187,7 @@ export const webrtcPeer: SimulationConfig = { id: 'ice-stun', label: 'ICE / STUN', description: - 'Peers exchange STUN Binding Requests directly to test connectivity. ICE tries multiple candidate paths (host, server-reflexive, relay) and picks the best one. STUN reveals each peer\'s public IP.', + "Peers exchange STUN Binding Requests directly to test connectivity. ICE tries multiple candidate paths (host, server-reflexive, relay) and picks the best one. STUN reveals each peer's public IP.", fromActor: 'peerA', toActor: 'peerB', duration: 1000, diff --git a/src/lib/simulator/simulations/websocket.ts b/src/lib/simulator/simulations/websocket.ts index 5b6f060..4a8b2e3 100644 --- a/src/lib/simulator/simulations/websocket.ts +++ b/src/lib/simulator/simulations/websocket.ts @@ -43,12 +43,49 @@ export const websocketConnection: SimulationConfig = { osiLayer: 7, color: '#00D4FF', headerFields: [ - { name: 'Method', bits: 0, value: 'GET', editable: false, description: 'WebSocket upgrade always starts with GET' }, - { name: 'Path', bits: 0, value: '/ws/chat', editable: false, description: 'WebSocket endpoint path' }, - { name: 'Upgrade', bits: 0, value: 'websocket', editable: false, description: 'Requests protocol switch to WebSocket' }, - { name: 'Connection', bits: 0, value: 'Upgrade', editable: false, description: 'Signals this is a connection upgrade, not a normal request' }, - { name: 'Sec-WebSocket-Key', bits: 0, value: 'dGhlIHNhbXBsZ...', editable: false, description: 'Base64-encoded random key β€” server hashes it to prove it supports WebSocket' }, - { name: 'Sec-WebSocket-Version', bits: 0, value: '13', editable: false, description: 'WebSocket protocol version (13 is the only current version)' } + { + name: 'Method', + bits: 0, + value: 'GET', + editable: false, + description: 'WebSocket upgrade always starts with GET' + }, + { + name: 'Path', + bits: 0, + value: '/ws/chat', + editable: false, + description: 'WebSocket endpoint path' + }, + { + name: 'Upgrade', + bits: 0, + value: 'websocket', + editable: false, + description: 'Requests protocol switch to WebSocket' + }, + { + name: 'Connection', + bits: 0, + value: 'Upgrade', + editable: false, + description: 'Signals this is a connection upgrade, not a normal request' + }, + { + name: 'Sec-WebSocket-Key', + bits: 0, + value: 'dGhlIHNhbXBsZ...', + editable: false, + description: + 'Base64-encoded random key β€” server hashes it to prove it supports WebSocket' + }, + { + name: 'Sec-WebSocket-Version', + bits: 0, + value: '13', + editable: false, + description: 'WebSocket protocol version (13 is the only current version)' + } ] } ] @@ -72,10 +109,36 @@ export const websocketConnection: SimulationConfig = { osiLayer: 7, color: '#00D4FF', headerFields: [ - { name: 'Status', bits: 0, value: '101 Switching Protocols', editable: false, description: 'Server agrees to switch from HTTP to WebSocket', color: '#22c55e' }, - { name: 'Upgrade', bits: 0, value: 'websocket', editable: false, description: 'Confirms the protocol switch' }, - { name: 'Connection', bits: 0, value: 'Upgrade', editable: false, description: 'Connection is now upgraded' }, - { name: 'Sec-WebSocket-Accept', bits: 0, value: 's3pPLMBiTxaQ9k...', editable: false, description: 'SHA-1 hash of the client key + magic GUID β€” proves server supports WebSocket' } + { + name: 'Status', + bits: 0, + value: '101 Switching Protocols', + editable: false, + description: 'Server agrees to switch from HTTP to WebSocket', + color: '#22c55e' + }, + { + name: 'Upgrade', + bits: 0, + value: 'websocket', + editable: false, + description: 'Confirms the protocol switch' + }, + { + name: 'Connection', + bits: 0, + value: 'Upgrade', + editable: false, + description: 'Connection is now upgraded' + }, + { + name: 'Sec-WebSocket-Accept', + bits: 0, + value: 's3pPLMBiTxaQ9k...', + editable: false, + description: + 'SHA-1 hash of the client key + magic GUID β€” proves server supports WebSocket' + } ] } ] @@ -109,7 +172,12 @@ export const websocketConnection: SimulationConfig = { createEthernetLayer({ srcMac: 'AA:BB:CC:DD:EE:FF', dstMac: '00:1A:2B:3C:4D:5E' }), createIPv4Layer({ srcIp: '93.184.216.34', dstIp: '192.168.1.100', protocol: 6 }), createTCPLayer({ srcPort: 443, dstPort: 52200, flags: 'PSH,ACK' }), - createWebSocketFrameLayer({ opcode: 'Text (0x1)', mask: 0, maskingKey: 'N/A', payload: 'Message received!' }) + createWebSocketFrameLayer({ + opcode: 'Text (0x1)', + mask: 0, + maskingKey: 'N/A', + payload: 'Message received!' + }) ] }, { @@ -125,7 +193,13 @@ export const websocketConnection: SimulationConfig = { createEthernetLayer({ srcMac: 'AA:BB:CC:DD:EE:FF', dstMac: '00:1A:2B:3C:4D:5E' }), createIPv4Layer({ srcIp: '93.184.216.34', dstIp: '192.168.1.100', protocol: 6 }), createTCPLayer({ srcPort: 443, dstPort: 52200, flags: 'PSH,ACK' }), - createWebSocketFrameLayer({ opcode: 'Ping (0x9)', mask: 0, payloadLength: 0, maskingKey: 'N/A', payload: '' }) + createWebSocketFrameLayer({ + opcode: 'Ping (0x9)', + mask: 0, + payloadLength: 0, + maskingKey: 'N/A', + payload: '' + }) ] }, { @@ -141,7 +215,12 @@ export const websocketConnection: SimulationConfig = { createEthernetLayer(), createIPv4Layer({ protocol: 6 }), createTCPLayer({ srcPort: 52200, dstPort: 443, flags: 'PSH,ACK' }), - createWebSocketFrameLayer({ opcode: 'Close (0x8)', payloadLength: 2, payload: '1000 (Normal)', maskingKey: '0x55AA33CC' }) + createWebSocketFrameLayer({ + opcode: 'Close (0x8)', + payloadLength: 2, + payload: '1000 (Normal)', + maskingKey: '0x55AA33CC' + }) ] } ] diff --git a/src/lib/simulator/simulations/wifi-association.ts b/src/lib/simulator/simulations/wifi-association.ts index 50f80ed..81cd1c6 100644 --- a/src/lib/simulator/simulations/wifi-association.ts +++ b/src/lib/simulator/simulations/wifi-association.ts @@ -38,7 +38,7 @@ export const wifiAssociation: SimulationConfig = { id: 'auth', label: 'Authentication', description: - 'The laptop sends an Authentication frame to the AP using WPA3\'s Simultaneous Authentication of Equals (SAE). Unlike WPA2\'s simple open-system authentication, SAE performs a zero-knowledge proof β€” neither side reveals the password, yet both can verify the other knows it. This prevents offline dictionary attacks.', + "The laptop sends an Authentication frame to the AP using WPA3's Simultaneous Authentication of Equals (SAE). Unlike WPA2's simple open-system authentication, SAE performs a zero-knowledge proof β€” neither side reveals the password, yet both can verify the other knows it. This prevents offline dictionary attacks.", fromActor: 'laptop', toActor: 'ap', duration: 800, @@ -57,7 +57,7 @@ export const wifiAssociation: SimulationConfig = { id: 'assoc-request', label: 'Association Request', description: - 'After successful authentication, the laptop sends an Association Request to join the BSS (Basic Service Set). This frame advertises the laptop\'s capabilities: supported PHY rates, power management mode, and QoS support. The AP uses this to decide whether the station is compatible and which rates to use.', + "After successful authentication, the laptop sends an Association Request to join the BSS (Basic Service Set). This frame advertises the laptop's capabilities: supported PHY rates, power management mode, and QoS support. The AP uses this to decide whether the station is compatible and which rates to use.", fromActor: 'laptop', toActor: 'ap', duration: 800, @@ -136,7 +136,7 @@ export const wifiAssociation: SimulationConfig = { id: 'bridge-to-ethernet', label: 'Bridge to Ethernet', description: - 'The AP decrypts the Wi-Fi frame and re-encapsulates the IP packet into a standard Ethernet frame for the wired LAN. The AP\'s MAC becomes the Ethernet source, and the LAN server\'s MAC becomes the destination. This bridging is transparent β€” the server sees a normal Ethernet frame and has no idea the traffic originated from a wireless client.', + "The AP decrypts the Wi-Fi frame and re-encapsulates the IP packet into a standard Ethernet frame for the wired LAN. The AP's MAC becomes the Ethernet source, and the LAN server's MAC becomes the destination. This bridging is transparent β€” the server sees a normal Ethernet frame and has no idea the traffic originated from a wireless client.", fromActor: 'ap', toActor: 'server', duration: 600, diff --git a/src/lib/simulator/simulations/wireguard-handshake.ts b/src/lib/simulator/simulations/wireguard-handshake.ts index c0aadc4..461499a 100644 --- a/src/lib/simulator/simulations/wireguard-handshake.ts +++ b/src/lib/simulator/simulations/wireguard-handshake.ts @@ -8,7 +8,7 @@ export const wireguardHandshake: SimulationConfig = { protocolId: 'wireguard', title: 'WireGuard β€” Noise_IKpsk2 Handshake and Transport', description: - "Watch two WireGuard peers β€” Alice and Bob β€” complete a one-round-trip Noise_IKpsk2 handshake and start exchanging encrypted IP packets. Then watch the 120-second rekey, the design that gives WireGuard per-handshake forward secrecy.", + 'Watch two WireGuard peers β€” Alice and Bob β€” complete a one-round-trip Noise_IKpsk2 handshake and start exchanging encrypted IP packets. Then watch the 120-second rekey, the design that gives WireGuard per-handshake forward secrecy.', tier: 'client', actors: [ { id: 'alice', label: 'Peer A (Alice)', icon: 'client', position: 'left' }, @@ -48,7 +48,8 @@ export const wireguardHandshake: SimulationConfig = { type: '1 (Handshake Init)', senderIndex: '0xABCD1234', receiverIndex: '0x00000000', - payload: 'ephemeral_pub (32 B) + enc_static (32+16 B) + enc_TAI64N (12+16 B) + MAC1 (16 B) + MAC2 (16 B)' + payload: + 'ephemeral_pub (32 B) + enc_static (32+16 B) + enc_TAI64N (12+16 B) + MAC1 (16 B) + MAC2 (16 B)' }) ] }, @@ -99,7 +100,7 @@ export const wireguardHandshake: SimulationConfig = { id: 'transport-data-2', label: 'Transport Data (B β†’ A)', description: - "Reverse direction uses a *different* key (WireGuard keys are unidirectional β€” separate `T_send` and `T_recv` derived from the same chaining key) and a *separate* counter. Each direction has its own anti-replay window.", + 'Reverse direction uses a *different* key (WireGuard keys are unidirectional β€” separate `T_send` and `T_recv` derived from the same chaining key) and a *separate* counter. Each direction has its own anti-replay window.', fromActor: 'bob', toActor: 'alice', duration: 1300, @@ -142,7 +143,7 @@ export const wireguardHandshake: SimulationConfig = { id: 'rekey', label: 'Rekey at REKEY_AFTER_TIME (120 s)', description: - "At 120 seconds, Alice (whoever sent the first handshake) initiates a fresh handshake. A new pair of ephemeral keys; the chaining key is freshly derived; the old session keys are wiped. **Per-handshake forward secrecy** across sessions, **per-message forward secrecy** within a session.", + 'At 120 seconds, Alice (whoever sent the first handshake) initiates a fresh handshake. A new pair of ephemeral keys; the chaining key is freshly derived; the old session keys are wiped. **Per-handshake forward secrecy** across sessions, **per-message forward secrecy** within a session.', fromActor: 'alice', toActor: 'bob', duration: 1400, diff --git a/src/lib/simulator/simulations/zigbee-join.ts b/src/lib/simulator/simulations/zigbee-join.ts index bf2fc6a..f53b26f 100644 --- a/src/lib/simulator/simulations/zigbee-join.ts +++ b/src/lib/simulator/simulations/zigbee-join.ts @@ -5,7 +5,7 @@ export const zigbeeJoin: SimulationConfig = { protocolId: 'zigbee', title: 'Zigbee Device Join β€” Coordinator β†’ new bulb β†’ first OnOff command', description: - "Watch a new Zigbee 3.0 bulb join a Trust Center–centralised network with an install code: beacon scan β†’ Association β†’ Transport-Key β†’ Toggle. Same flow under every Philips Hue join, IKEA TrΓ₯dfri pairing, and Aqara device commissioning in 2026.", + 'Watch a new Zigbee 3.0 bulb join a Trust Center–centralised network with an install code: beacon scan β†’ Association β†’ Transport-Key β†’ Toggle. Same flow under every Philips Hue join, IKEA TrΓ₯dfri pairing, and Aqara device commissioning in 2026.', tier: 'client', actors: [ { id: 'bulb', label: 'New Bulb (Joiner)', icon: 'device', position: 'left' }, @@ -18,14 +18,23 @@ export const zigbeeJoin: SimulationConfig = { label: 'Zigbee channel', type: 'select', defaultValue: '25 (2475 MHz)', - options: ['15 (2425 MHz, avoids Wi-Fi 6)', '20 (2450 MHz)', '25 (2475 MHz)', '26 (2480 MHz, regulatory limit)'] + options: [ + '15 (2425 MHz, avoids Wi-Fi 6)', + '20 (2450 MHz)', + '25 (2475 MHz)', + '26 (2480 MHz, regulatory limit)' + ] }, { id: 'auth', label: 'Pre-configured link key', type: 'select', defaultValue: 'Install code (secure)', - options: ['Install code (secure)', 'ZigBeeAlliance09 default (legacy)', 'R23 Dynamic Link Key (SPEKE/Curve25519)'] + options: [ + 'Install code (secure)', + 'ZigBeeAlliance09 default (legacy)', + 'R23 Dynamic Link Key (SPEKE/Curve25519)' + ] }, { id: 'panId', @@ -92,7 +101,8 @@ export const zigbeeJoin: SimulationConfig = { dstPan: '0x1A62', dstAddr: '0x0000 (Coordinator)', srcAddr: 'EUI-64 of the joiner', - payload: 'MAC Cmd 0x01 β€” Association Request. Capability=0x8E (FFD, mains-powered, security-capable, allocate-short)' + payload: + 'MAC Cmd 0x01 β€” Association Request. Capability=0x8E (FFD, mains-powered, security-capable, allocate-short)' }) ] }, @@ -112,7 +122,8 @@ export const zigbeeJoin: SimulationConfig = { dstPan: '0x1A62', dstAddr: 'EUI-64 of joiner', srcAddr: '0x0000 (Coordinator EUI-64)', - payload: 'MAC Cmd 0x02 β€” Association Response. Allocated short=0x3F4E. Status=0x00 (success)' + payload: + 'MAC Cmd 0x02 β€” Association Response. Allocated short=0x3F4E. Status=0x00 (success)' }) ] }, @@ -127,13 +138,15 @@ export const zigbeeJoin: SimulationConfig = { highlight: ['Frame Control', 'Aux Sec Hdr / MIC', 'Payload (APS frame)'], layers: [ createZigbeeNWKLayer({ - frameControl: '0x0048 (Data, ProtoVer=2, NWK Security off β€” APS-level only on Transport-Key)', + frameControl: + '0x0048 (Data, ProtoVer=2, NWK Security off β€” APS-level only on Transport-Key)', dstAddr: '0x3F4E', srcAddr: '0x0000', radius: 1, seq: 0x10, security: '(none at NWK; APS encrypts under pre-conf link key)', - payload: 'APS Cmd 0x05 β€” Transport-Key (Network Key). Encrypted under install-code-derived link key.' + payload: + 'APS Cmd 0x05 β€” Transport-Key (Network Key). Encrypted under install-code-derived link key.' }) ] }, @@ -141,7 +154,7 @@ export const zigbeeJoin: SimulationConfig = { id: 'device-announce', label: 'Device Announce β€” bulb broadcasts its arrival', description: - "The joiner now has both a short address and the network key. It NWK-broadcasts a **Device Announce** ZDO message (cluster 0x0013) β€” *I am 0x3F4E, EUI-64 = …, capability = …* β€” so every router knows to add it to their routing tables and binding tables. From here the device is on the mesh.", + 'The joiner now has both a short address and the network key. It NWK-broadcasts a **Device Announce** ZDO message (cluster 0x0013) β€” *I am 0x3F4E, EUI-64 = …, capability = …* β€” so every router knows to add it to their routing tables and binding tables. From here the device is on the mesh.', fromActor: 'bulb', toActor: 'router', duration: 900, @@ -162,7 +175,7 @@ export const zigbeeJoin: SimulationConfig = { id: 'onoff-toggle', label: 'First command β€” ZCL OnOff.Toggle = 0x02', description: - "A switch (or the Hue app via the bridge) sends a ZCL OnOff Toggle command to the new bulb. APS frame: Cluster 0x0006 (OnOff), Profile 0x0104 (Home Automation), Cmd 0x02 (Toggle). The ZCL FrameCtrl byte 0x11 says *cluster-specific, clientβ†’server, disable default response*. The whole on-the-wire payload is roughly 40 bytes including all the headers.", + 'A switch (or the Hue app via the bridge) sends a ZCL OnOff Toggle command to the new bulb. APS frame: Cluster 0x0006 (OnOff), Profile 0x0104 (Home Automation), Cmd 0x02 (Toggle). The ZCL FrameCtrl byte 0x11 says *cluster-specific, clientβ†’server, disable default response*. The whole on-the-wire payload is roughly 40 bytes including all the headers.', fromActor: 'coord', toActor: 'bulb', duration: 1000, diff --git a/src/lib/tour/app-tour.ts b/src/lib/tour/app-tour.ts index e420262..d3a0e60 100644 --- a/src/lib/tour/app-tour.ts +++ b/src/lib/tour/app-tour.ts @@ -33,8 +33,7 @@ export async function startTour(appState: AppState, allNodes: GraphNode[]): Prom // destroy so the user lands back where they started. const savedPath = window.location.pathname + window.location.search; const baseHome = `${base}/`; - const isAtHome = - window.location.pathname === baseHome || window.location.pathname === base; + const isAtHome = window.location.pathname === baseHome || window.location.pathname === base; if (!isAtHome) { await goto(baseHome, { replaceState: false, keepFocus: true }); } @@ -68,9 +67,7 @@ export async function startTour(appState: AppState, allNodes: GraphNode[]): Prom const PANEL_ANIM_MS = 380; - let tourDriver: ReturnType<typeof driver>; - - tourDriver = driver({ + const tourDriver = driver({ showProgress: true, animate: true, overlayColor: '#0f172a', @@ -428,8 +425,8 @@ export async function startTour(appState: AppState, allNodes: GraphNode[]): Prom appState.activeTour = { destroy: () => tourDriver.destroy() }; // Expose for dev testing (tree-shaken in prod via __dev check) - if (typeof window !== 'undefined' && (window as any).__dev) { - (window as any).__tourDriver = tourDriver; + if (typeof window !== 'undefined' && window.__dev) { + window.__tourDriver = tourDriver; } tourDriver.drive(); diff --git a/src/lib/utils/colors.test.ts b/src/lib/utils/colors.test.ts new file mode 100644 index 0000000..47aef4b --- /dev/null +++ b/src/lib/utils/colors.test.ts @@ -0,0 +1,54 @@ +import { describe, it, expect } from 'vitest'; +import { hexToRgba, shiftHsl, themedDomColor } from './colors'; + +describe('hexToRgba', () => { + it('converts a 6-digit hex + alpha to an rgba() string', () => { + expect(hexToRgba('#ff8800', 0.5)).toBe('rgba(255, 136, 0, 0.5)'); + expect(hexToRgba('#000000', 1)).toBe('rgba(0, 0, 0, 1)'); + }); +}); + +describe('shiftHsl', () => { + it('returns the input unchanged for non-hex values', () => { + expect(shiftHsl('rgb(1,2,3)', 0.1)).toBe('rgb(1,2,3)'); + expect(shiftHsl('not-a-color', 0.1)).toBe('not-a-color'); + }); + + it('round-trips a color (dl=0) to within rounding error', () => { + // Pure HSLβ†’RGBβ†’HSL with no shift should reproduce the input Β±1 per channel. + const out = shiftHsl('#3366cc', 0); + expect(out).toMatch(/^#[0-9a-f]{6}$/); + const chan = (s: string, i: number) => parseInt(s.slice(1 + i * 2, 3 + i * 2), 16); + for (let i = 0; i < 3; i++) { + expect(Math.abs(chan(out, i) - chan('#3366cc', i))).toBeLessThanOrEqual(2); + } + }); + + it('lightens with positive dl and darkens with negative dl', () => { + const luminance = (hex: string) => + parseInt(hex.slice(1, 3), 16) + parseInt(hex.slice(3, 5), 16) + parseInt(hex.slice(5, 7), 16); + const base = '#3366cc'; + expect(luminance(shiftHsl(base, 0.2))).toBeGreaterThan(luminance(base)); + expect(luminance(shiftHsl(base, -0.2))).toBeLessThan(luminance(base)); + }); + + it('expands 3-digit shorthand hex', () => { + expect(shiftHsl('#abc', 0)).toMatch(/^#[0-9a-f]{6}$/); + }); +}); + +describe('themedDomColor', () => { + it('passes colors through unchanged in dark theme', () => { + expect(themedDomColor('#abcdef', 'dark')).toBe('#abcdef'); + }); + + it('darkens an unmapped bright color for light backgrounds', () => { + const out = themedDomColor('#ffff00', 'light'); // very bright yellow + expect(out).not.toBe('#ffff00'); + expect(out).toMatch(/^#[0-9a-f]{6}$/); + }); + + it('leaves non-hex values alone in light theme', () => { + expect(themedDomColor('currentColor', 'light')).toBe('currentColor'); + }); +}); diff --git a/src/lib/utils/math.test.ts b/src/lib/utils/math.test.ts new file mode 100644 index 0000000..a5515d4 --- /dev/null +++ b/src/lib/utils/math.test.ts @@ -0,0 +1,64 @@ +import { describe, it, expect } from 'vitest'; +import { + lerp, + clamp, + distance, + pointInCircle, + easeOutCubic, + easeInOutCubic, + normalizeAngle +} from './math'; + +describe('lerp', () => { + it('returns endpoints at t=0 and t=1', () => { + expect(lerp(10, 20, 0)).toBe(10); + expect(lerp(10, 20, 1)).toBe(20); + }); + it('interpolates the midpoint and extrapolates past the range', () => { + expect(lerp(0, 100, 0.5)).toBe(50); + expect(lerp(0, 10, 1.5)).toBe(15); + }); +}); + +describe('clamp', () => { + it('bounds values to [min, max]', () => { + expect(clamp(5, 0, 10)).toBe(5); + expect(clamp(-3, 0, 10)).toBe(0); + expect(clamp(42, 0, 10)).toBe(10); + }); +}); + +describe('distance / pointInCircle', () => { + it('computes euclidean distance (3-4-5)', () => { + expect(distance(0, 0, 3, 4)).toBe(5); + }); + it('treats the radius as inclusive', () => { + expect(pointInCircle(3, 4, 0, 0, 5)).toBe(true); + expect(pointInCircle(3, 4, 0, 0, 4.99)).toBe(false); + }); +}); + +describe('easing', () => { + it('easeOutCubic maps [0,1] to [0,1] monotonically', () => { + expect(easeOutCubic(0)).toBe(0); + expect(easeOutCubic(1)).toBe(1); + expect(easeOutCubic(0.5)).toBeCloseTo(0.875, 5); + }); + it('easeInOutCubic is symmetric around 0.5', () => { + expect(easeInOutCubic(0)).toBe(0); + expect(easeInOutCubic(1)).toBe(1); + expect(easeInOutCubic(0.5)).toBeCloseTo(0.5, 5); + // symmetry: f(t) + f(1-t) === 1 + expect(easeInOutCubic(0.2) + easeInOutCubic(0.8)).toBeCloseTo(1, 5); + }); +}); + +describe('normalizeAngle', () => { + const TAU = 2 * Math.PI; + it('wraps into [0, 2Ο€)', () => { + expect(normalizeAngle(0)).toBeCloseTo(0, 5); + expect(normalizeAngle(TAU)).toBeCloseTo(0, 5); + expect(normalizeAngle(-Math.PI)).toBeCloseTo(Math.PI, 5); + expect(normalizeAngle(3 * TAU + 1)).toBeCloseTo(1, 5); + }); +}); diff --git a/src/lib/utils/mermaid-helpers.ts b/src/lib/utils/mermaid-helpers.ts index 771834c..51dc748 100644 --- a/src/lib/utils/mermaid-helpers.ts +++ b/src/lib/utils/mermaid-helpers.ts @@ -1,9 +1,38 @@ /** - * Shared mermaid rendering utilities used by MermaidDiagram and DiagramModal. + * Shared mermaid rendering utilities used by the diagram components. */ import { stripRichTextMarkup } from '$lib/utils/text-parser'; +type MermaidApi = typeof import('mermaid').default; + +/** Per-diagram-kind config merged onto the shared base. Values are passed + * straight to mermaid; kept loose so this module never statically imports + * mermaid's types (which would pull the library into the initial bundle). */ +interface MermaidOverrides { + sequence?: Record<string, unknown>; + flowchart?: Record<string, unknown>; +} + +/** + * Dynamically import mermaid (~200 KB β€” deliberately kept out of the initial + * bundle) and initialize it with the shared base config plus any per-component + * overrides. Every diagram component should go through this so the base theme / + * security / font settings live in exactly one place. + */ +export async function loadMermaid(overrides: MermaidOverrides = {}): Promise<MermaidApi> { + const mod = await import('mermaid'); + const config = { + startOnLoad: false, + theme: 'dark', + securityLevel: 'loose', + fontFamily: 'ui-sans-serif, system-ui, -apple-system, sans-serif', + ...overrides + }; + mod.default.initialize(config as Parameters<MermaidApi['initialize']>[0]); + return mod.default; +} + export function buildThemedDefinition( rawDef: string, color: string, diff --git a/src/lib/utils/sequence-parser.test.ts b/src/lib/utils/sequence-parser.test.ts new file mode 100644 index 0000000..bb9bd3a --- /dev/null +++ b/src/lib/utils/sequence-parser.test.ts @@ -0,0 +1,93 @@ +import { describe, it, expect } from 'vitest'; +import { parseSequenceSteps, visibleSteps } from './sequence-parser'; + +describe('parseSequenceSteps', () => { + it('ignores diagram preamble, declarations, comments and blank lines', () => { + const src = `sequenceDiagram + autonumber + participant A + actor B + %% a comment + + `; + expect(parseSequenceSteps(src)).toEqual([]); + }); + + it('parses notes with placement and multiple actors', () => { + const steps = parseSequenceSteps('Note over A,B: shared state'); + expect(steps).toEqual([ + { kind: 'note', placement: 'over', actors: ['A', 'B'], text: 'shared state' } + ]); + }); + + it('maps "left of" / "right of" placements', () => { + expect(parseSequenceSteps('Note left of A: x')[0]).toMatchObject({ placement: 'left' }); + expect(parseSequenceSteps('Note right of A: y')[0]).toMatchObject({ placement: 'right' }); + }); + + it('classifies all arrow kinds and prefers the longest token', () => { + const arrows = parseSequenceSteps( + [ + 'A->B: solid', + 'A->>B: solid-head', + 'A-->B: dashed', + 'A-->>B: dashed-head', + 'A-xB: lost-solid', + 'A--xB: lost-dashed' + ].join('\n') + ); + expect(arrows.map((s) => (s.kind === 'message' ? s.arrow : null))).toEqual([ + 'solid', + 'solid', + 'dashed', + 'dashed', + 'lost-solid', + 'lost-dashed' + ]); + }); + + it('captures message from/to/text', () => { + const [msg] = parseSequenceSteps('Client->>Server: SYN'); + expect(msg).toEqual({ + kind: 'message', + from: 'Client', + to: 'Server', + arrow: 'solid', + text: 'SYN' + }); + }); + + it('parses block markers (par/loop/alt/opt/and/else/end)', () => { + const steps = parseSequenceSteps( + ['par fan out', 'and branch', 'end', 'alt ok', 'else fail', 'end', 'loop retry', 'end'].join( + '\n' + ) + ); + expect(steps.map((s) => s.kind)).toEqual([ + 'block-start', + 'block-and', + 'block-end', + 'block-start', + 'block-and', + 'block-end', + 'block-start', + 'block-end' + ]); + expect(steps[0]).toMatchObject({ type: 'par', label: 'fan out' }); + expect(steps[3]).toMatchObject({ type: 'alt', label: 'ok' }); + }); + + it('preserves source order across mixed content', () => { + const steps = parseSequenceSteps( + ['Note over A: start', 'A->>B: req', 'B-->>A: res'].join('\n') + ); + expect(steps.map((s) => s.kind)).toEqual(['note', 'message', 'message']); + }); +}); + +describe('visibleSteps', () => { + it('keeps only notes and messages, dropping block markers', () => { + const steps = parseSequenceSteps(['par x', 'A->>B: hi', 'Note over A: n', 'end'].join('\n')); + expect(visibleSteps(steps).map((s) => s.kind)).toEqual(['message', 'note']); + }); +}); diff --git a/src/lib/utils/text-parser.test.ts b/src/lib/utils/text-parser.test.ts new file mode 100644 index 0000000..d2ad7e1 --- /dev/null +++ b/src/lib/utils/text-parser.test.ts @@ -0,0 +1,120 @@ +import { describe, it, expect } from 'vitest'; +import { parseRichText, parseParagraphs, stripRichTextMarkup } from './text-parser'; + +describe('parseRichText β€” primitives', () => { + it('returns a single text segment for plain prose', () => { + expect(parseRichText('just words')).toEqual([{ type: 'text', value: 'just words' }]); + }); + + it('parses **bold**, `code`, and *italic*', () => { + expect(parseRichText('**b**')).toEqual([{ type: 'bold', value: 'b' }]); + expect(parseRichText('`x = 1`')).toEqual([{ type: 'code', value: 'x = 1' }]); + expect(parseRichText('*em*')).toEqual([{ type: 'italic', value: 'em' }]); + }); + + it('does NOT treat spaced asterisks as italic (math-multiplication guard)', () => { + const segs = parseRichText('a * b * c'); + expect(segs).toEqual([{ type: 'text', value: 'a * b * c' }]); + }); + + it('preserves leading/trailing text around a match in order', () => { + expect(parseRichText('see **this** now')).toEqual([ + { type: 'text', value: 'see ' }, + { type: 'bold', value: 'this' }, + { type: 'text', value: ' now' } + ]); + }); +}); + +describe('parseRichText β€” cross references', () => { + it('parses a protocol link and fills the label from the registry', () => { + expect(parseRichText('[[tcp|TCP]]')).toEqual([ + { type: 'protocol-link', protocolId: 'tcp', label: 'TCP' } + ]); + // Bare form resolves the label from the protocol registry (abbreviation). + expect(parseRichText('[[tcp]]')).toEqual([ + { type: 'protocol-link', protocolId: 'tcp', label: 'TCP' } + ]); + }); + + it('parses a typed rfc: reference', () => { + const segs = parseRichText('[[rfc:9293|RFC 9293]]'); + expect(segs).toEqual([{ type: 'rfc-ref', number: '9293', label: 'RFC 9293' }]); + }); + + it('parses a concept tooltip token', () => { + expect(parseRichText('{{handshake|the handshake}}')).toEqual([ + { type: 'concept', conceptId: 'handshake', label: 'the handshake' } + ]); + }); + + it('falls back to visible plain text for an unknown [[prefix:…]]', () => { + // Surfacing typos rather than dropping them silently. + expect(parseRichText('[[bogus:xyz|Label]]')).toEqual([ + { type: 'text', value: '[[bogus:xyz|Label]]' } + ]); + }); +}); + +describe('parseRichText β€” bold-wrapped variants', () => { + it('parses **{{concept}}** as a bold-concept', () => { + expect(parseRichText('**{{handshake|Handshake}}**')).toEqual([ + { type: 'bold-concept', conceptId: 'handshake', label: 'Handshake' } + ]); + }); + + it('parses **[[tcp|TCP]]** as a bold-protocol-link', () => { + expect(parseRichText('**[[tcp|TCP]]**')).toEqual([ + { type: 'bold-protocol-link', protocolId: 'tcp', label: 'TCP' } + ]); + }); + + it('parses **bold with {{nested}}** as a recursive bold-group', () => { + const segs = parseRichText('**see {{handshake|the handshake}} live**'); + expect(segs).toHaveLength(1); + expect(segs[0].type).toBe('bold-group'); + if (segs[0].type === 'bold-group') { + expect(segs[0].segments.map((s) => s.type)).toEqual(['text', 'concept', 'text']); + } + }); +}); + +describe('parseParagraphs', () => { + it('splits on blank lines into one segment list per paragraph', () => { + const paras = parseParagraphs('one **two**\n\nthree'); + expect(paras).toHaveLength(2); + expect(paras[0].map((s) => s.type)).toEqual(['text', 'bold']); + expect(paras[1]).toEqual([{ type: 'text', value: 'three' }]); + }); +}); + +describe('stripRichTextMarkup', () => { + it('reduces atoms to their visible label', () => { + expect(stripRichTextMarkup('[[tcp|TCP]] over {{ip|IP}} is **fast**')).toBe( + 'TCP over IP is fast' + ); + }); + + it('does not eat the outer brackets of a nested Mermaid-style construct', () => { + // NODE[[[id|Label]]] β€” the id char-class excludes `[` so the inner wrap + // resolves to its label and the surrounding brackets survive. + expect(stripRichTextMarkup('NODE[[[tcp|TCP]]]')).toBe('NODE[TCP]'); + }); + + it('is idempotent on already-plain text', () => { + expect(stripRichTextMarkup('nothing to strip')).toBe('nothing to strip'); + }); + + it('resolves a bare [[id]] to its label instead of dropping it', () => { + // Regression: previously a label-less ref stripped to '' and the word + // vanished from tooltips / aria-labels. + expect(stripRichTextMarkup('runs on [[tcp]] today')).toBe('runs on TCP today'); + expect(stripRichTextMarkup('see [[rfc:9293]]')).toBe('see RFC 9293'); + }); + + it('resolves a bare {{concept}} to its term', () => { + const out = stripRichTextMarkup('the {{handshake}} step'); + expect(out).not.toContain('{{'); + expect(out.toLowerCase()).toContain('handshake'); + }); +}); diff --git a/src/lib/utils/text-parser.ts b/src/lib/utils/text-parser.ts index 3ed025a..a9859a9 100644 --- a/src/lib/utils/text-parser.ts +++ b/src/lib/utils/text-parser.ts @@ -182,7 +182,7 @@ export function parseRichText(raw: string): TextSegment[] { // recursively parse it and emit a bold-group; otherwise // keep the cheap `bold` segment so simple cases stay flat. const inner = match[9]; - if (/[\[{`*]/.test(inner)) { + if (/[[{`*]/.test(inner)) { segments.push({ type: 'bold-group', segments: parseRichText(inner) }); } else { segments.push({ type: 'bold', value: inner }); @@ -214,6 +214,35 @@ export function parseParagraphs(raw: string): TextSegment[][] { return raw.split('\n\n').map((p) => parseRichText(p)); } +/** + * Resolve a bracketed ref to the label text it should display when no explicit + * `|label` was given β€” mirrors {@link buildBracketSegment} so stripped text + * matches rendered text. A bare `[[tcp]]` becomes "TCP", not an empty string. + */ +function bracketFallbackLabel(rawId: string): string { + const colonIdx = rawId.indexOf(':'); + const prefix = colonIdx === -1 ? 'protocol' : rawId.slice(0, colonIdx); + const id = colonIdx === -1 ? rawId : rawId.slice(colonIdx + 1); + switch (prefix) { + case 'protocol': + return getProtocolById(id)?.abbreviation ?? id.toUpperCase(); + case 'rfc': + return `RFC ${id}`; + case 'outage': + return getOutageById(id)?.title ?? id; + case 'pioneer': + return getPioneerById(id)?.name ?? id; + case 'glossary': + return getConceptById(id)?.term ?? id; + case 'frontier': + return getFrontierById(id)?.title ?? id; + case 'chapter': + return id.includes('/') ? id.slice(id.indexOf('/') + 1) : id; + default: + return rawId; + } +} + /** * Strip rich-text atoms ([[…]] / {{…}} / **…**) down to their label * text. For surfaces that render strings as raw DOM text (screen-reader @@ -227,8 +256,17 @@ export function stripRichTextMarkup(raw: string): string { // outer brackets when an author nests a wrap inside another bracketed // construct β€” e.g. Mermaid's `NODE[[[id|Label]]]`. A legitimate id is // always a slug, so disallowing `[`/`{` inside it is strictly correct. + // + // A bare ref with no `|label` resolves to its display label (protocol + // abbreviation, concept term, …) rather than vanishing β€” otherwise a bare + // `[[tcp]]` in a stripped field (tooltip / aria-label) would silently drop + // the word. return raw - .replace(/\[\[[^\]\[|]+(?:\|([^\]]+))?\]\]/g, (_m, label) => label ?? '') - .replace(/\{\{[^}{|]+(?:\|([^}]+))?\}\}/g, (_m, label) => label ?? '') + .replace(/\[\[([^\][|]+)(?:\|([^\]]+))?\]\]/g, (_m, id, label) => + label != null ? label : bracketFallbackLabel(id) + ) + .replace(/\{\{([^}{|]+)(?:\|([^}]+))?\}\}/g, (_m, id, label) => + label != null ? label : (getConceptById(id)?.term ?? id) + ) .replace(/\*\*([^*]+)\*\*/g, '$1'); } diff --git a/src/routes/demo/+page.svelte b/src/routes/demo/+page.svelte deleted file mode 100644 index 372e8bc..0000000 --- a/src/routes/demo/+page.svelte +++ /dev/null @@ -1,5 +0,0 @@ -<script lang="ts"> - import { resolve } from '$app/paths'; -</script> - -<a href={resolve('/demo/playwright')}>playwright</a> diff --git a/src/routes/demo/playwright/+page.svelte b/src/routes/demo/playwright/+page.svelte deleted file mode 100644 index 5f0f2c9..0000000 --- a/src/routes/demo/playwright/+page.svelte +++ /dev/null @@ -1 +0,0 @@ -<h1>Playwright e2e test demo</h1> diff --git a/src/routes/demo/playwright/page.svelte.e2e.ts b/src/routes/demo/playwright/page.svelte.e2e.ts deleted file mode 100644 index 1000be6..0000000 --- a/src/routes/demo/playwright/page.svelte.e2e.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { expect, test } from '@playwright/test'; - -test('has expected h1', async ({ page }) => { - await page.goto('/demo/playwright'); - await expect(page.locator('h1')).toBeVisible(); -}); diff --git a/src/routes/layout.css b/src/routes/layout.css index a5ff270..f644435 100644 --- a/src/routes/layout.css +++ b/src/routes/layout.css @@ -2,6 +2,23 @@ @import 'driver.js/dist/driver.css'; @plugin '@tailwindcss/typography'; +/* ── Reduced-motion reset ── + When a user asks the OS for reduced motion, collapse all CSS animations, + transitions, and smooth scrolling to near-instant. Covers entrance + animations (detail panel, modals, tooltips, simulator arrows) in one place. + The canvas graph honors the same preference in JS (see GraphCanvas/ + prefersReducedMotion). */ +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + scroll-behavior: auto !important; + } +} + /* ── Semantic theme variables ── */ :root { --theme-bg: #090e1a; @@ -16,7 +33,13 @@ --theme-scrollbar: rgba(255, 255, 255, 0.12); --theme-scrollbar-thumb: rgba(255, 255, 255, 0.1); --theme-scrollbar-thumb-hover: rgba(255, 255, 255, 0.2); - --theme-panel-desktop: linear-gradient(to right, rgb(9 14 26 / 0.6), rgb(9 14 26 / 0.88) 25%, rgb(7 10 20 / 0.98) 70%, rgb(5 8 16 / 1)); + --theme-panel-desktop: linear-gradient( + to right, + rgb(9 14 26 / 0.6), + rgb(9 14 26 / 0.88) 25%, + rgb(7 10 20 / 0.98) 70%, + rgb(5 8 16 / 1) + ); --theme-panel-mobile: rgb(5 8 16 / 0.98); --theme-tooltip-bg: rgba(15, 23, 42, 0.92); --theme-shadow-color: rgba(0, 0, 0, 0.3); @@ -37,7 +60,13 @@ --theme-scrollbar: rgba(0, 0, 0, 0.08); --theme-scrollbar-thumb: rgba(0, 0, 0, 0.12); --theme-scrollbar-thumb-hover: rgba(0, 0, 0, 0.2); - --theme-panel-desktop: linear-gradient(to right, rgb(219 234 254 / 0.55), rgb(232 238 246 / 0.92) 25%, rgb(241 245 249 / 0.98) 70%, rgb(248 250 252 / 1)); + --theme-panel-desktop: linear-gradient( + to right, + rgb(219 234 254 / 0.55), + rgb(232 238 246 / 0.92) 25%, + rgb(241 245 249 / 0.98) 70%, + rgb(248 250 252 / 1) + ); --theme-panel-mobile: rgb(241 245 249 / 0.98); --theme-tooltip-bg: rgba(248, 250, 252, 0.95); --theme-shadow-color: rgba(0, 0, 0, 0.08); diff --git a/static/og-image.png b/static/og-image.png index 16d131c..755fe6c 100644 Binary files a/static/og-image.png and b/static/og-image.png differ diff --git a/static/screenshot.png b/static/screenshot.png deleted file mode 100644 index 16d131c..0000000 Binary files a/static/screenshot.png and /dev/null differ diff --git a/vite.config.ts b/vite.config.ts index 56f40c7..139c4c5 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,5 +1,14 @@ +/// <reference types="vitest/config" /> import tailwindcss from '@tailwindcss/vite'; import { sveltekit } from '@sveltejs/kit/vite'; import { defineConfig } from 'vite'; -export default defineConfig({ plugins: [tailwindcss(), sveltekit()] }); +export default defineConfig({ + plugins: [tailwindcss(), sveltekit()], + test: { + // Pure-logic unit tests (parsers, layout/sim math, utils, data validation). + // Component/DOM behavior is covered by the Playwright e2e suite instead. + include: ['src/**/*.{test,spec}.{js,ts}'], + environment: 'node' + } +});