diff --git a/docs/learning/index.md b/docs/learning/index.md index 0e5d923b..1f64d7fc 100644 --- a/docs/learning/index.md +++ b/docs/learning/index.md @@ -22,6 +22,7 @@ A curated set of roadmaps and references for learning systems software in 2026. | "I want the design rounds — LLD + HLD" | [System design](./system-design.md) | | "I want to learn how databases *actually work* (internals)" | [Disk-First DB roadmap](./db-roadmap.md) | | "I want one mental model that covers V8, JVM, Go runtime, vLLM, Workers" | [Runtime roadmap](./runtime-roadmap.md) | +| "I want a first hands-on distributed-systems exercise" | [Maelstrom Echo lab](./maelstrom-echo.md) | | "I want to see how real ML systems work in production" | [ML system design case studies](./ml-case-studies.md) | | "I want retrieval / search / vector / RAG depth" | 9-Day Reset → 30-Day Retrieval → 90-Day AI Search & Infra → 12-Month Advanced AI Infra (in-app `/learn`) | | "I want OS, cloud, containers, distributed systems, and reliability" | Systems Foundations → Infrastructure & Platforms → Distributed Systems (in-app `/learn`) | @@ -41,6 +42,7 @@ The four AI roadmaps are one progressive curriculum at four horizons — not fou | [System design](./system-design.md) | catalogue | LLD patterns + HLD components + the canonical "design X" practice problems | | [Disk-First Databases & RAM](./db-roadmap.md) | 12-month roadmap | DB internals: storage engines, execution, distributed | | [Runtime — what every runtime has to do](./runtime-roadmap.md) | 12-month roadmap | Cross-cutting: V8, JVM, Go, BEAM, vLLM, Workers as one shape | +| [Maelstrom Echo lab](./maelstrom-echo.md) | one-session lab | Request/reply envelopes, correlation IDs, and protocol-level testing | | [ML system design case studies](./ml-case-studies.md) | catalogue | 450 production ML write-ups, grouped by category | | 9-Day Reset → 12-Month AI Infra | in-app `/learn` | Retrieval, ANN, RAG, storage progression | | Systems Foundations → Distributed Systems | in-app `/learn` | OS, hardware, networks, cloud, containers, orchestration, reliability, workflows | diff --git a/docs/learning/maelstrom-echo.md b/docs/learning/maelstrom-echo.md new file mode 100644 index 00000000..92fa48f7 --- /dev/null +++ b/docs/learning/maelstrom-echo.md @@ -0,0 +1,77 @@ +# Maelstrom Echo — a first distributed-systems lab + +← [Learning OS index](./index.md) · [Runtime roadmap](./runtime-roadmap.md) + +This one-session lab practices reading a wire protocol, correlating a reply to +its request, and using a workload checker. It covers one node and one +request/reply operation. It does not cover consensus, persistence, membership, +or the rest of the Fly.io challenge sequence. + +## Before you start + +You should be comfortable writing a small program that reads and writes lines +of JSON. Choose a language you already know; this repository adds no language +runtime or Maelstrom dependency. The external exercise uses the +[Fly.io distributed-systems challenge 1](https://fly.io/dist-sys/1/) and the +[Maelstrom protocol](https://github.com/jepsen-io/maelstrom/blob/main/doc/protocol.md). +Follow their current setup and safety guidance if you choose to run it. + +## Trace the contract + +Read the Echo challenge and protocol reference, then write the request and +reply as two separate JSON envelopes. In your own words, identify: + +1. Which envelope fields identify the sender, recipient, and message body? +2. Which value must the reply use to point back to this particular request? +3. Which body field carries the exact text that must be echoed? +4. Why should diagnostics go somewhere other than the protocol output stream? + +Do not copy a reference implementation. Use the contract to make your own +small table with columns `input`, `required output`, and `invariant`. + +## Build and test + +Implement only the Echo operation in a scratch project using the language you +chose. Read one JSON message per input line and emit one JSON response per +line. For a request of type `echo`, preserve its payload in an `echo_ok` +response and set the response's `in_reply_to` to the request's `msg_id`. +Keep logs off standard output so they cannot be mistaken for protocol +messages. Treat the protocol's initialization message as setup, not as an Echo +request. + +If Maelstrom is already available in your environment, the upstream workload +is bounded to one node and ten seconds: + +```sh +./maelstrom test -w echo --bin ./your-program \ + --node-count 1 --time-limit 10 +``` + +Use the current command documented by the challenge if its interface changes. +Do not run this against a service or production system; the harness launches a +local process. If you do not have Maelstrom installed, the protocol trace and +your own table are still useful preparation, but they are not a passing test. + +## Explain the result + +Save a short artifact beside your scratch project containing: + +- the input/output envelope table; +- the exact test command and result, or “not run” with the reason; +- one bug you deliberately considered (for example, replying with the node's + latest message ID instead of the request ID) and how the invariant catches + it; +- a three-sentence explanation of why a correct reply needs correlation, not + just the original payload. + +The successful workload is evidence that the tested Echo contract held for +that run. It does not demonstrate fault tolerance or correctness under +concurrent, partitioned, or persistent workloads. + +## Primary sources + +- [Fly.io Distributed Systems Challenge 1: Echo](https://fly.io/dist-sys/1/) +- [Maelstrom protocol specification](https://github.com/jepsen-io/maelstrom/blob/main/doc/protocol.md) +- [Maelstrom getting-ready guide](https://github.com/jepsen-io/maelstrom/blob/main/doc/01-getting-ready/index.md) + +Last audited: 2026-10-02. diff --git a/docs/learning/runtime-roadmap.md b/docs/learning/runtime-roadmap.md index 152a6b2d..dfda2120 100644 --- a/docs/learning/runtime-roadmap.md +++ b/docs/learning/runtime-roadmap.md @@ -205,6 +205,10 @@ Pick one. Don't pick all four. capability API, measure per-tenant memory limit + CPU quota enforcement. Output: a multi-tenant evaluator runnable in one binary. +For a smaller first distributed-systems exercise, use the [Maelstrom Echo +lab](./maelstrom-echo.md). It focuses on message envelopes and request/reply +correlation; it does not replace the larger synthesis projects above. + --- ## Cross-runtime cheat sheet diff --git a/package.json b/package.json index 93f56c1f..b48446b4 100644 --- a/package.json +++ b/package.json @@ -119,19 +119,20 @@ }, "pnpm": { "overrides": { - "brace-expansion@<1.1.18": "1.1.18", + "brace-expansion@<1.1.21": "1.1.21", "brace-expansion@>=2.0.0 <2.1.4": "2.1.4", - "brace-expansion@>=4.0.0 <5.0.9": "5.0.9", + "brace-expansion@>=4.0.0 <5.0.12": "5.0.12", "fast-uri@<3.1.5": "3.1.5", "immutable@<4.3.9": "4.3.9", "js-yaml@>=3.0.0 <3.15.1": "3.15.1", "js-yaml@>=4.0.0 <4.3.1": "4.3.1", "lodash-es@>=4.0.0 <=4.17.23": "4.18.1", "minimatch@>=10.0.0 <10.2.3": "10.2.5", - "nanoid@<3.3.17": "3.3.17", - "nanoid@>=4.0.0 <5.1.11": "5.1.11", + "nanoid@<3.3.18": "3.3.18", + "nanoid@>=4.0.0 <5.1.16": "5.1.16", "postcss@<=8.5.22": "8.5.23", - "undici@>=7.0.0 <7.29.0": "7.29.0", + "undici@>=5.0.0 <6.27.0": "6.29.0", + "undici@>=7.0.0 <7.29.1": "7.29.1", "sharp@<0.35.4": "0.35.4", "js-yaml@>=4.0.0 <4.3.2": "4.3.2", "smol-toml@<1.7.1": "1.7.1" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7e8898e7..b42f3f68 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,19 +5,20 @@ settings: excludeLinksFromLockfile: false overrides: - brace-expansion@<1.1.18: 1.1.18 + brace-expansion@<1.1.21: 1.1.21 brace-expansion@>=2.0.0 <2.1.4: 2.1.4 - brace-expansion@>=4.0.0 <5.0.9: 5.0.9 + brace-expansion@>=4.0.0 <5.0.12: 5.0.12 fast-uri@<3.1.5: 3.1.5 immutable@<4.3.9: 4.3.9 js-yaml@>=3.0.0 <3.15.1: 3.15.1 js-yaml@>=4.0.0 <4.3.1: 4.3.1 lodash-es@>=4.0.0 <=4.17.23: 4.18.1 minimatch@>=10.0.0 <10.2.3: 10.2.5 - nanoid@<3.3.17: 3.3.17 - nanoid@>=4.0.0 <5.1.11: 5.1.11 + nanoid@<3.3.18: 3.3.18 + nanoid@>=4.0.0 <5.1.16: 5.1.16 postcss@<=8.5.22: 8.5.23 - undici@>=7.0.0 <7.29.0: 7.29.0 + undici@>=5.0.0 <6.27.0: 6.29.0 + undici@>=7.0.0 <7.29.1: 7.29.1 sharp@<0.35.4: 0.35.4 js-yaml@>=4.0.0 <4.3.2: 4.3.2 smol-toml@<1.7.1: 1.7.1 @@ -938,10 +939,6 @@ packages: resolution: {integrity: sha512-nULYsQxkWHnbmHvcs+efMkJ4/9TtvNyFeLyHdeGxW0zHs6P+jYVqcRff9A6Vq9w9JXeDRnRh2VKvTtS19GW2qA==} engines: {node: '>=10'} - '@fastify/busboy@2.1.1': - resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} - engines: {node: '>=14'} - '@floating-ui/core@1.7.5': resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} @@ -2682,11 +2679,11 @@ packages: bowser@2.14.1: resolution: {integrity: sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==} - brace-expansion@1.1.18: - resolution: {integrity: sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==} + brace-expansion@1.1.21: + resolution: {integrity: sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==} - brace-expansion@5.0.9: - resolution: {integrity: sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==} + brace-expansion@5.0.12: + resolution: {integrity: sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==} engines: {node: 20 || >=22} braces@3.0.3: @@ -3913,13 +3910,13 @@ packages: mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} - nanoid@3.3.17: - resolution: {integrity: sha512-xQLf0A3HOMlgHq0n247/LRuAOYmB7dXJ/DvAxGvsSBij45XtBSmQycu+F8ODbHwns/XyFZagyL1+J0Offw1E0g==} + nanoid@3.3.18: + resolution: {integrity: sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - nanoid@5.1.11: - resolution: {integrity: sha512-v+KEsUv2ps74PaSKv0gHTxTCgMXOIfBEbaqa6w6ISIGC7ZsvHN4N9oJ8d4cmf0n5oTzQz2SLmThbQWhjd/8eKg==} + nanoid@5.1.16: + resolution: {integrity: sha512-kVrnsrJqMR8+oLJnGEmSWw9BivK5mt7H3FZatVRjrc5wGqFYuBxX1yG7+A7Gi5AefkX6t/oCkizcQgpu0cY1dQ==} engines: {node: ^18 || >=20} hasBin: true @@ -4505,12 +4502,12 @@ packages: undici-types@8.3.0: resolution: {integrity: sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==} - undici@5.28.4: - resolution: {integrity: sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==} - engines: {node: '>=14.0'} + undici@6.29.0: + resolution: {integrity: sha512-R+RODBqp6i2pPflGdq+xIOUkl+RNfGgHwoinecKu/JCuf2uO06cOKoDbI2P7Dn6KcswdKwrczbU6IYJ6K8X+wg==} + engines: {node: '>=18.17'} - undici@7.29.0: - resolution: {integrity: sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==} + undici@7.29.1: + resolution: {integrity: sha512-RYONW2MeafgYlkVOKYKkA/Ag7BmXqgIWCa8t1m0JcxrQg9pI9lEqRhAOruOBCbAohOa/gkCF+iPi9hrgvTzu6Q==} engines: {node: '>=20.18.1'} unenv@2.0.0-rc.24: @@ -5295,7 +5292,7 @@ snapshots: jotai-scope: 0.7.2(jotai@2.11.0(@types/react@19.2.17)(react@19.2.8))(react@19.2.8) lodash.debounce: 4.0.8 lodash.throttle: 4.1.1 - nanoid: 3.3.17 + nanoid: 3.3.18 open-color: 1.9.1 pako: 2.0.3 perfect-freehand: 1.2.0 @@ -5324,12 +5321,10 @@ snapshots: '@excalidraw/markdown-to-text': 0.1.2 '@mermaid-js/parser': 0.6.3 mermaid: 11.14.0 - nanoid: 5.1.11 + nanoid: 5.1.16 '@excalidraw/random-username@1.1.0': {} - '@fastify/busboy@2.1.1': {} - '@floating-ui/core@1.7.5': dependencies: '@floating-ui/utils': 0.2.11 @@ -6656,7 +6651,7 @@ snapshots: ts-morph: 12.0.0 tsx: 4.21.0 typescript: 5.9.3 - undici: 5.28.4 + undici: 6.29.0 transitivePeerDependencies: - encoding - rollup @@ -6832,12 +6827,12 @@ snapshots: bowser@2.14.1: {} - brace-expansion@1.1.18: + brace-expansion@1.1.21: dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 - brace-expansion@5.0.9: + brace-expansion@5.0.12: dependencies: balanced-match: 4.0.4 @@ -8268,7 +8263,7 @@ snapshots: dependencies: '@cspotcode/source-map-support': 0.8.1 sharp: 0.35.4(@types/node@26.1.1) - undici: 7.29.0 + undici: 7.29.1 workerd: 1.20260722.1 ws: 8.21.0 youch: 4.1.0-beta.10 @@ -8279,11 +8274,11 @@ snapshots: minimatch@10.2.5: dependencies: - brace-expansion: 5.0.9 + brace-expansion: 5.0.12 minimatch@3.1.5: dependencies: - brace-expansion: 1.1.18 + brace-expansion: 1.1.21 minipass@7.1.3: {} @@ -8322,9 +8317,9 @@ snapshots: object-assign: 4.1.1 thenify-all: 1.6.0 - nanoid@3.3.17: {} + nanoid@3.3.18: {} - nanoid@5.1.11: {} + nanoid@5.1.16: {} nanospinner@1.2.2: dependencies: @@ -8502,7 +8497,7 @@ snapshots: postcss@8.5.23: dependencies: - nanoid: 3.3.17 + nanoid: 3.3.18 picocolors: 1.1.1 source-map-js: 1.2.1 @@ -8982,11 +8977,9 @@ snapshots: undici-types@8.3.0: {} - undici@5.28.4: - dependencies: - '@fastify/busboy': 2.1.1 + undici@6.29.0: {} - undici@7.29.0: {} + undici@7.29.1: {} unenv@2.0.0-rc.24: dependencies: diff --git a/src/pages/LearningDoc.tsx b/src/pages/LearningDoc.tsx index 6e6f6f94..47271b28 100644 --- a/src/pages/LearningDoc.tsx +++ b/src/pages/LearningDoc.tsx @@ -46,6 +46,10 @@ const DOC_META: Record = { blurb: 'Cross-cutting view of V8, JVM, Go, BEAM, vLLM, Workers — all do the same five jobs.', companionRoadmapId: 'runtime', }, + 'maelstrom-echo': { + title: 'Maelstrom Echo — a first distributed-systems lab', + blurb: 'A one-session exercise in message envelopes, reply correlation, and protocol testing.', + }, 'swe-landscape': { title: 'The Software Engineering Landscape (2026)', blurb: 'One page per major systems-software domain. Vocabulary first, depth on demand.',