Sprint: BEAM Ecosystem Mastery - Real World Projects

Goal: Learn the BEAM ecosystem through one prerequisite-aware sequence that starts with workstation proof, syntax, values, immutable transformations, and executable documentation, advances through raw Erlang processes and OTP, then covers Phoenix, Ash, Livebook, Pub/Sub, runtime internals, distribution, releases, and principal-level extension work. This guide keeps theory brief. Each project names an observable artifact and preserves the distinct learning outcomes from the six source guides and all 53 requested official Elixir topics without repeating projects that approach the same lesson from the same angle.

Introduction

This is a standalone merged curriculum. Each of the 144 entries is one self-contained build, even when several source projects contributed requirements. Every project includes its outcome, design questions, milestones, testing strategy, pitfalls, and definition of done here; the source guides and official Elixir pages are references rather than required navigation.

data transformations
        |
raw processes -> OTP -> local state
        |                 |
        +------> Phoenix/Ecto/Ash
                         |
             LiveView/PubSub/Livebook
                         |
        runtime internals + distribution
                         |
          releases, resilience, capstones

How to Use This Guide

  • Build projects in order inside a phase; skip a whole phase only when you can reproduce its mastery signals.
  • Curriculum difficulty is normalized across the merged guides and official Elixir topic projects: Levels 1-5 increase monotonically by phase because the original source scales were not directly comparable.
  • Keep a short decision log for state ownership, failure semantics, durability, and validation evidence.
  • Complete the embedded milestones, testing strategy, and Definition of Done before advancing.
  • Do not turn every pure transformation into a process, or every notification into durable state.

Prerequisites & Background Knowledge

Essential prerequisites

  • Basic command-line use, Git, and one prior programming language.
  • Enough Elixir or Erlang syntax to define modules, call functions, pattern match, and run tests; Projects 1-41 deliberately build and reinforce these skills.
  • A willingness to read tagged results and failure evidence instead of treating every non-happy path as an exception.

Helpful but not required

  • SQL, HTTP, and Docker help in the Phoenix and deployment phases.
  • Distributed-systems and systems-programming knowledge can be learned during Phases 6-8.

Development environment

  • Install a current Erlang/OTP and Elixir pair supported by the libraries you choose.
  • Keep Mix, Rebar3, Git, a SQL database, and container tooling available as each project requires them.
  • Verify the toolchain with elixir --version, erl -version, mix test, and rebar3 --version before beginning.

Time investment

  • Foundational projects: 4-8 hours; intermediate: 8-16; applied: 12-24; advanced: 20-40; expert: 30-60.
  • Treat the sequence as a long curriculum. Build fewer projects with strong evidence rather than rushing through every checkbox.

Big Picture / Mental Model

pure data contracts
        |
mailboxes and process ownership
        |
OTP behaviours and supervision
        |
Phoenix / Ecto / Ash / Livebook
        |
PubSub, clusters, storage, native boundaries
        |
VM internals, releases, resilience, capstones

Every later layer depends on the earlier question: who owns state, which facts are durable, which messages may be lost or duplicated, and what evidence proves recovery.

Theory Primer

This primer is deliberately brief because this is a project guide. Each project embeds the concepts, design questions, and references needed for its build.

  • Immutable transformations keep parsing, validation, and business rules deterministic and easy to test.
  • Processes and mailboxes provide isolated state ownership; they are runtime tools, not a replacement for ordinary functions.
  • OTP behaviours and supervisors standardize process protocols, lifecycle, restart scope, and failure escalation.
  • Phoenix, Ecto, and Ash turn those foundations into web, persistence, and declarative domain boundaries.
  • LiveView, PubSub, Presence, and Livebook add reactive interfaces, transient fanout, membership, and executable analysis.
  • Distribution and durable state introduce partitions, replicas, transactions, recovery authority, and operational policy.
  • VM and native boundaries require measurement of schedulers, heaps, mailboxes, NIF safety, bytecode, and release behavior.
  • Production reliability combines idempotency, backpressure, observability, deployment, chaos, and bounded recovery.

Glossary

  • BEAM: The Erlang virtual machine that executes Erlang, Elixir, and other BEAM languages.
  • Process: A lightweight isolated BEAM execution unit with its own mailbox and heap.
  • OTP: Libraries, behaviours, and design principles for building supervised BEAM systems.
  • Tagged result: An explicit success or failure value such as {:ok, value} or {:error, reason}.
  • Supervision tree: A hierarchy that defines child startup, shutdown, and restart policy.
  • Pub/Sub: Transient fanout from publishers to subscribers; it is not durable work by itself.
  • Presence: Eventually convergent metadata describing connected participants or devices.
  • Backpressure: A policy that bounds or slows producers when consumers cannot keep up.
  • Idempotency: The property that repeating an operation does not repeat its effective result.
  • Netsplit: A network partition that divides previously connected BEAM nodes.
  • Release: A self-contained deployable artifact containing the application and selected runtime components.

Why the BEAM Ecosystem Matters

The BEAM makes failure isolation, concurrency, and runtime introspection first-class design concerns. Elixir supplies a productive language and tooling layer; Erlang exposes the runtime’s original semantics; Phoenix, Ecto, Ash, Livebook, and the messaging ecosystem turn those semantics into practical products. The important skill is not syntax—it is choosing honest boundaries for state, durability, delivery, overload, and recovery.

Concept Summary Table

Concept cluster What you need to internalize
Language and data Pattern matching, immutable pipelines, parsing, validation, and tagged outcomes
Processes and OTP Mailboxes, monitors, behaviours, supervision, ownership, and restart scope
Product frameworks Plug/Phoenix requests, Ecto persistence, Ash resources/actions/policies, LiveView lifecycle
Data and notebooks Reproducible inputs, lazy plans, provenance, Kino interaction, deployment
Real-time systems Pub/Sub semantics, Presence convergence, backpressure, durable handoff
Distribution and storage Node formation, partitions, Mnesia, registries, recovery authority
Runtime and releases Scheduler/heap/mailbox evidence, bytecode, native code, upgrades, rollback
Reliability architecture Idempotency, event sourcing, telemetry, chaos, multi-tenancy, SLOs

Project-to-Concept Map

Phase Projects Primary concepts
1 1-41 Language, Immutable Data, and Reproducible Analysis
2 42-72 Processes, Message Passing, OTP, and Local State
3 73-85 Phoenix, Ecto, Web Security, and Durable Work
4 86-96 Ash Framework Resource and Policy Mastery
5 97-100 Livebook Applications and Data Portability
6 101-117 Real-Time Flow, Native Boundaries, and Numerical Computing
7 118-136 State Machines, Distribution, VM Internals, and Releases
8 137-144 Advanced Architecture and Capstones

Deep Dive Reading by Concept

Concept Book or primary documentation Why it matters
Elixir and OTP Elixir in Action by Saša Jurić Connects functional code, processes, supervision, and releases
Erlang foundations Learn You Some Erlang for Great Good! by Fred Hébert Makes mailbox, OTP, and failure semantics concrete
Scalable OTP Designing for Scalability with Erlang/OTP Covers distribution, architecture, and operations
Phoenix and LiveView Official Phoenix and LiveView guides Defines current framework lifecycle and contracts
Persistence Programming Ecto Explains schemas, queries, constraints, and transactions
Distributed data Designing Data-Intensive Applications Frames replication, consistency, recovery, and stream trade-offs
Reliability Release It! and Systems Performance Connects failure patterns to measurable production behavior

Quick Start: Your First 48 Hours

Day 1

  1. Read the glossary, install a supported Elixir and OTP pair, and start Project 1.
  2. Capture runtime versions, IEx evidence, script evidence, compiler evidence, and clean-exit behavior.
  3. Break one PATH or version assumption deliberately and make the verifier explain it.

Day 2

  1. Finish Project 1 from a clean shell and retain its acceptance transcript.
  2. Start Project 2 with one valid syntax fixture and one expected parser failure.
  3. Explain why toolchain evidence precedes syntax, data, processes, frameworks, and distribution.
  • Complete ecosystem: Projects 1-144 in order.
  • Phoenix product engineer: Projects 1-85, then 101-105, 118, 129-130, and 137-144.
  • BEAM runtime engineer: Projects 1-72, then 101-140.
  • Data and internal tools: Projects 1-41, 60-70, and 86-117.
  • Distributed real-time specialist: Projects 42-72, 79-85, 101-136, then 141-143.

Success Metrics

  • Every project ends with executable evidence: tests, transcripts, reports, dashboards, or failure-drill results.
  • You can state which process owns state, what survives a crash, and which messages may be lost or duplicated.
  • You distinguish ephemeral notification, durable work, durable state, membership, and consensus boundaries.
  • You can diagnose scheduler, heap, mailbox, network, database, and release failures from bounded evidence.
  • The capstones preserve correctness and tenant isolation under overload, duplicate delivery, restart, and partition.

Source Inventory and Raw Counts

The curriculum accounts for 128 project entries from the six original guides plus 53 Markdown or cheatsheet topics from the official Elixir v1.20.2 repository. A requested official topic always receives its own distinct project, even when a nearby existing project exercises a related mechanism from a different angle.

Alias Source Entries Integration rule
BEAM BEAM Erlang/Elixir learning guide 38 Original source projects
PHX Phoenix deep-dive guide 28 Original source projects
ASH Ash mastery guide 17 Original source projects
ERL Erlang from first principles 19 Original source projects
LIVE Livebook deep-dive guide 13 Original source projects
PUB Elixir PubSub deep-dive guide 13 Original source projects
ELX-GS Getting started 24 One distinct project per topic
ELX-CHEAT Cheatsheets 2 One distinct project per topic
ELX-ANTI Anti-patterns 5 One distinct project per topic
ELX-META Metaprogramming 3 One distinct project per topic
ELX-OTP Mix and OTP 9 One distinct project per topic
ELX-REF References 10 One distinct project per topic
Total Six source guides plus official Elixir v1.20.2 topics 181 144 final projects

Official Elixir v1.20.2 Topic Coverage Ledger

Each requested Markdown or cheatsheet topic maps to exactly one new project. The source page is an optional primary reference; the concepts, build instructions, failure cases, tests, and completion criteria are fully embedded in this guide.

Official folder Source topic Project
getting-started Introduction 1
references Syntax reference 2
getting-started Basic types 3
references Operators reference 4
getting-started Lists and tuples 5
getting-started Keyword lists and maps 6
getting-started Pattern matching 7
references Patterns and guards 8
getting-started case, cond, and if 9
getting-started Anonymous functions 10
getting-started Binaries, strings, and charlists 11
references Unicode syntax 12
getting-started Modules and functions 13
getting-started alias, require, import, and use 14
references Naming conventions 15
getting-started Module attributes 16
getting-started Structs 17
getting-started Recursion 18
getting-started Enumerables and Streams 20
cheatsheets Enum cheatsheet 21
getting-started Comprehensions 22
getting-started Protocols 23
getting-started Sigils 24
getting-started try, catch, and rescue 25
getting-started IO and the file system 26
getting-started Writing documentation 27
getting-started Optional syntax sheet 28
getting-started Erlang libraries 29
getting-started Debugging 30
mix-and-otp Introduction to Mix 31
anti-patterns What are anti-patterns? 32
cheatsheets Set-theoretic types cheatsheet 42
getting-started Processes 43
mix-and-otp Simple state with agents 46
mix-and-otp Client-server with GenServer 51
mix-and-otp Registries and supervision trees 52
mix-and-otp Supervising dynamic children 53
mix-and-otp Task and gen_tcp 54
mix-and-otp Doctests, patterns, and with 55
anti-patterns Process-related anti-patterns 59
anti-patterns Code-related anti-patterns 64
references Software Bill of Materials 66
references Typespecs reference 67
anti-patterns Design-related anti-patterns 68
references Library guidelines 70
mix-and-otp Configuration and distribution 103
references Gradual set-theoretic types 106
meta-programming Quote and unquote 107
meta-programming Macros 108
meta-programming Domain-Specific Languages (DSLs) 109
anti-patterns Meta-programming anti-patterns 110
references Compatibility and deprecations 120
mix-and-otp Releases 121

Deduplication Method

Projects were normalized on three axes: learning objective, system angle, and observable outcome. Entries were merged only when all three substantially overlapped. A merged project retains every non-overlapping challenge from its sources. Projects remain separate when the abstraction or failure boundary changes: raw processes versus OTP, raw C NIF work versus Elixir/Rustler integration, transient Pub/Sub versus durable delivery, and local registration versus distributed discovery are deliberately different projects.

The six original guides still reduce to 91 projects: twenty-nine merge groups collapse 66 raw entries into 29 projects, while 62 raw entries remain distinct. The 53 official documentation topics are then added one-for-one, yielding 91 + 53 = 144 projects from 181 accounted source entries/topics.

Merge Ledger

Consolidated Project Raw Entries Merged Reason
39 LIVE-P1, LIVE-P2 Reproducible notebook plus interactive validated report
40 LIVE-P3, LIVE-P5 The same tabular-data triage and transformation pipeline angle
47 PUB-P1, PUB-P2 Local fanout mechanics from mailboxes to Registry
57 BEAM-P6, PHX-P2 Supervision strategies observed through injected crashes
71 PUB-P3, PUB-P4 Versioned domain events delivered through Phoenix.PubSub
73 PHX-P3, PHX-P4 Plug request flow progressing directly into a Phoenix app
80 BEAM-P4, PHX-P7, PUB-P5 LiveView lifecycle, diffs, Pub/Sub refresh, and reconnect correctness
82 BEAM-P24, PHX-P11 Oban fundamentals and the same durable workflow outcome
83 BEAM-P10, PHX-P12 Telemetry collection rendered as production live metrics
86 ASH-P1, ASH-P2 First Ash resource and its attribute/type contract
87 ASH-P3, ASH-P4 Related resources exercised through CRUD actions
88 ASH-P5, ASH-P6 Custom business actions persisted through AshPostgres
89 ASH-P7, ASH-P8, ASH-P9 One derived-and-queryable read-model learning objective
93 ASH-P13, ASH-P14 Exposing the same Ash domain through two API adapters
100 LIVE-P12, LIVE-CAP Deployable multi-session app plus its governed operations-studio outcome
101 BEAM-P7, PUB-P6 Multi-node presence, multi-device identity, and convergence
102 BEAM-P5, PUB-P8 Demand-aware GenStage/Broadway flow and bounded fanout
105 PHX-P10, PUB-P10 The same three-node distributed Phoenix.PubSub laboratory
115 BEAM-P27, PHX-P20 Elixir/Rustler native work plus ports-versus-NIF safety comparison
118 BEAM-P30, ERL-P10, PHX-P16 gen_statem protocol, durable workflow, and OTP control-plane synthesis
119 BEAM-P3, BEAM-P35, ERL-P9 Distributed KV evolution into transactional Mnesia recovery
128 BEAM-P32, ERL-P11 BEAM chunks, bytecode, build metadata, and reproducibility
129 ERL-P12, PHX-P18 Bounded tracing feeding a Phoenix performance investigation
130 PHX-P15, ERL-P13, ERL-P14, PUB-P7 Heap, scheduler, reductions, and mailbox pressure in one runtime lab
133 BEAM-P9, ERL-P16, PHX-P19 One hot-upgrade and rollback release-engineering drill
135 BEAM-P13, PUB-P11 Federated edge streams plus a tenant-safe durable broker boundary
141 PUB-P12, PUB-CAP The same multi-tenant real-time operations platform capstone
142 BEAM-CAP, PHX-P25 Multi-tenant BEAM reliability and production SaaS operations
143 PHX-CAP, PHX-P22, PHX-P27 Real-time collaboration, Presence internals, convergence, and scale

Why This Order

The curriculum now starts with the official Elixir workstation, syntax, data, function, module, documentation, and debugging topics before it reaches the original builds. Functions and data still precede concurrency because the official Elixir material introduces the language before processes, and the GenServer documentation recommends processes for runtime properties rather than code organization. Raw message loops precede standard behaviours; Erlang/OTP design principles describe gen_server, gen_statem, and supervisors as reusable process structures, while Supervisor adds lifecycle and restart semantics.

Phoenix and Ash follow local OTP because Channels, LiveView, PubSub, and resource actions run on those foundations. Local real-time systems precede clusters because Distributed Erlang adds node connectivity and failure modes, while Mnesia adds replication and transactions. The ordering also keeps the raw Erlang ladder intact: syntax, manual processes, OTP, Mnesia/state machines, VM internals, native code and upgrades, distribution, then the message-queue capstone. Native code, hot upgrades, distributed recovery, capstones, and a custom Ecto adapter come last because they cross scheduler, release, consistency, or framework-contract boundaries.

Project List

Phase 1 - Language, Immutable Data, and Reproducible Analysis

Project 1: Reproducible Elixir Workstation Smoke Test

Official topic: Introduction — Elixir v1.20.2

Source file: lib/elixir/pages/getting-started/introduction.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Toolchain / Runtime Setup
  • Software or Tool: IEx, elixir, elixirc
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build an elixir-doctor script and evidence bundle that proves IEx, elixir, elixirc, script execution, runtime versions, and clean shell exit all work on the declared workstation.

Why it teaches this official topic: The artifact makes runtime installation, interactive evaluation, script execution, version evidence observable through one bounded build instead of isolated syntax examples.

Scope boundary: Stop at local toolchain proof; do not introduce Mix dependencies, releases, or deployment.

Core challenges you will face:

  • runtime installation -> identify the accepted case, the counterexample, and the observable result at the IEx, elixir, elixirc boundary
  • interactive evaluation -> identify the accepted case, the counterexample, and the observable result at the IEx, elixir, elixirc boundary
  • script execution -> identify the accepted case, the counterexample, and the observable result at the IEx, elixir, elixirc boundary
  • version evidence -> identify the accepted case, the counterexample, and the observable result at the IEx, elixir, elixirc boundary

Real World Outcome

Build an elixir-doctor script and evidence bundle that proves IEx, elixir, elixirc, script execution, runtime versions, and clean shell exit all work on the declared workstation. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • The declared Elixir and OTP versions are captured.
  • IEx expressions and script files produce equivalent results.
  • Compilation and clean exit are independently verified.

Acceptance transcript:

$ elixir scripts/elixir_doctor.exs
SOURCE_TOPIC=getting-started/introduction.md
ARTIFACT=reproducible-elixir-workstation-smoke-test
CHECK 01 PASS :: The declared Elixir and OTP versions are captured
CHECK 02 PASS :: IEx expressions and script files produce equivalent results
CHECK 03 PASS :: Compilation and clean exit are independently verified
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“How can another developer prove that this exact Elixir and OTP workstation is ready before writing application code?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. runtime installation
    • Working rule: Make “runtime installation” an explicit rule at the IEx, elixir, elixirc boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "runtime-installation-positive", focus: "runtime installation", mode: :positive, expect: :observable} and %{id: "runtime-installation-negative", focus: "runtime installation", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Introduction
  2. interactive evaluation
    • Working rule: Make “interactive evaluation” an explicit rule at the IEx, elixir, elixirc boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "interactive-evaluation-positive", focus: "interactive evaluation", mode: :positive, expect: :observable} and %{id: "interactive-evaluation-negative", focus: "interactive evaluation", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Introduction
  3. script execution
    • Working rule: Make “script execution” an explicit rule at the IEx, elixir, elixirc boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "script-execution-positive", focus: "script execution", mode: :positive, expect: :observable} and %{id: "script-execution-negative", focus: "script execution", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Introduction
  4. version evidence
    • Working rule: Make “version evidence” an explicit rule at the IEx, elixir, elixirc boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "version-evidence-positive", focus: "version evidence", mode: :positive, expect: :observable} and %{id: "version-evidence-negative", focus: "version evidence", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Introduction

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “runtime installation” be enforced?
    • Which check catches the risk “Shell PATH selects an unintended runtime”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “The declared Elixir and OTP versions are captured”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Introduction”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: runtime installation, interactive evaluation, script execution, version evidence. Then trace the named counterexample “Shell PATH selects an unintended runtime” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose runtime installation, and what does this project prove about it?”
  2. “What interaction between the concept ‘interactive evaluation’ and the concept ‘runtime installation’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘Shell PATH selects an unintended runtime’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with runtime-installation-positive and shell-path-selects-an-unintended-runtime-counterexample. The first must make the concept “runtime installation” observable and establish “The declared Elixir and OTP versions are captured”; the second must reproduce “Shell PATH selects an unintended runtime”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for getting-started/introduction.md
evaluate "runtime installation" through IEx, elixir, elixirc
compare actual evidence with "The declared Elixir and OTP versions are captured"
run negative fixture for "Shell PATH selects an unintended runtime"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run elixir scripts/elixir_doctor.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Introduction Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
runtime installation Elixir in Action, 3rd Edition Ch. 2-4
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement runtime-installation-positive and prove “The declared Elixir and OTP versions are captured”.
  3. Topic coverage: add fixtures for interactive evaluation, script execution, version evidence.
  4. Failure campaign: reproduce each named risk: “Shell PATH selects an unintended runtime”; “The transcript omits OTP compatibility”; “A cached artifact hides a broken compiler”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute runtime-installation-positive, interactive-evaluation-positive, script-execution-positive, version-evidence-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute runtime-installation-negative, interactive-evaluation-negative, script-execution-negative, version-evidence-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute shell-path-selects-an-unintended-runtime-counterexample, the-transcript-omits-otp-compatibility-counterexample, a-cached-artifact-hides-a-broken-compiler-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run elixir scripts/elixir_doctor.exs through the real IEx, elixir, elixirc boundary from a clean shell.
  • Mutation check: violate “The declared Elixir and OTP versions are captured” and prove the suite reports fixture runtime-installation-positive as failed.
  • Regression corpus: retain the risks “Shell PATH selects an unintended runtime”; “The transcript omits OTP compatibility”; “A cached artifact hides a broken compiler” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “Shell PATH selects an unintended runtime”

  • Why: This breaks one or more observable capabilities at the IEx, elixir, elixirc boundary while allowing the happy path to look correct.
  • Fix: Run shell-path-selects-an-unintended-runtime-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: elixir scripts/elixir_doctor.exs

Problem 2: “The transcript omits OTP compatibility”

  • Why: This breaks one or more observable capabilities at the IEx, elixir, elixirc boundary while allowing the happy path to look correct.
  • Fix: Run the-transcript-omits-otp-compatibility-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: elixir scripts/elixir_doctor.exs

Problem 3: “A cached artifact hides a broken compiler”

  • Why: This breaks one or more observable capabilities at the IEx, elixir, elixirc boundary while allowing the happy path to look correct.
  • Fix: Run a-cached-artifact-hides-a-broken-compiler-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: elixir scripts/elixir_doctor.exs

Definition of Done

  • The declared Elixir and OTP versions are captured.
  • IEx expressions and script files produce equivalent results.
  • Compilation and clean exit are independently verified.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 2: Elixir Syntax Conformance Playground

Official topic: Syntax reference — Elixir v1.20.2

Source file: lib/elixir/pages/references/syntax-reference.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Language Grammar / AST
  • Software or Tool: Code.string_to_quoted, Macro, mix format
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build a corpus of valid and invalid Elixir forms that round-trips supported constructs through the parser, an AST renderer, and the formatter while preserving deliberate rejection evidence.

Why it teaches this official topic: The artifact makes reserved words, literal and container syntax, calls and blocks, syntax-to-AST forms observable through one bounded build instead of isolated syntax examples.

Scope boundary: Own grammar coverage and syntax-to-AST fidelity; leave AST injection to the quote/unquote project and migration policy to the linter.

Core challenges you will face:

  • reserved words -> identify the accepted case, the counterexample, and the observable result at the Code.string_to_quoted, Macro, mix format boundary
  • literal and container syntax -> identify the accepted case, the counterexample, and the observable result at the Code.string_to_quoted, Macro, mix format boundary
  • calls and blocks -> identify the accepted case, the counterexample, and the observable result at the Code.string_to_quoted, Macro, mix format boundary
  • syntax-to-AST forms -> identify the accepted case, the counterexample, and the observable result at the Code.string_to_quoted, Macro, mix format boundary

Real World Outcome

Build a corpus of valid and invalid Elixir forms that round-trips supported constructs through the parser, an AST renderer, and the formatter while preserving deliberate rejection evidence. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Every supported syntax family has a valid fixture.
  • Every invalid fixture fails with an expected parser reason.
  • Formatted valid forms parse to the same structural AST.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=references/syntax-reference.md
ARTIFACT=elixir-syntax-conformance-playground
CHECK 01 PASS :: Every supported syntax family has a valid fixture
CHECK 02 PASS :: Every invalid fixture fails with an expected parser reason
CHECK 03 PASS :: Formatted valid forms parse to the same structural AST
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“Which parts of Elixir source are surface sugar, and which structural AST must remain invariant after formatting?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. reserved words
    • Working rule: Make “reserved words” an explicit rule at the Code.string_to_quoted, Macro, mix format boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "reserved-words-positive", focus: "reserved words", mode: :positive, expect: :observable} and %{id: "reserved-words-negative", focus: "reserved words", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Syntax reference
  2. literal and container syntax
    • Working rule: Make “literal and container syntax” an explicit rule at the Code.string_to_quoted, Macro, mix format boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "literal-and-container-syntax-positive", focus: "literal and container syntax", mode: :positive, expect: :observable} and %{id: "literal-and-container-syntax-negative", focus: "literal and container syntax", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Syntax reference
  3. calls and blocks
    • Working rule: Make “calls and blocks” an explicit rule at the Code.string_to_quoted, Macro, mix format boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "calls-and-blocks-positive", focus: "calls and blocks", mode: :positive, expect: :observable} and %{id: "calls-and-blocks-negative", focus: "calls and blocks", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Syntax reference
  4. syntax-to-AST forms
    • Working rule: Make “syntax-to-AST forms” an explicit rule at the Code.string_to_quoted, Macro, mix format boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "syntax-to-ast-forms-positive", focus: "syntax-to-AST forms", mode: :positive, expect: :observable} and %{id: "syntax-to-ast-forms-negative", focus: "syntax-to-AST forms", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Syntax reference

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “reserved words” be enforced?
    • Which check catches the risk “A formatter change is mistaken for semantic change”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Every supported syntax family has a valid fixture”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Syntax reference”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: reserved words, literal and container syntax, calls and blocks, syntax-to-AST forms. Then trace the named counterexample “A formatter change is mistaken for semantic change” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose reserved words, and what does this project prove about it?”
  2. “What interaction between the concept ‘literal and container syntax’ and the concept ‘reserved words’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘A formatter change is mistaken for semantic change’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with reserved-words-positive and a-formatter-change-is-mistaken-for-semantic-change-counterexample. The first must make the concept “reserved words” observable and establish “Every supported syntax family has a valid fixture”; the second must reproduce “A formatter change is mistaken for semantic change”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for references/syntax-reference.md
evaluate "reserved words" through Code.string_to_quoted, Macro, mix format
compare actual evidence with "Every supported syntax family has a valid fixture"
run negative fixture for "A formatter change is mistaken for semantic change"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Syntax reference Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
reserved words Elixir in Action, 3rd Edition Ch. 2-4
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement reserved-words-positive and prove “Every supported syntax family has a valid fixture”.
  3. Topic coverage: add fixtures for literal and container syntax, calls and blocks, syntax-to-AST forms.
  4. Failure campaign: reproduce each named risk: “A formatter change is mistaken for semantic change”; “Metadata makes AST comparison unstable”; “The corpus silently omits a syntax family”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute reserved-words-positive, literal-and-container-syntax-positive, calls-and-blocks-positive, syntax-to-ast-forms-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute reserved-words-negative, literal-and-container-syntax-negative, calls-and-blocks-negative, syntax-to-ast-forms-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute a-formatter-change-is-mistaken-for-semantic-change-counterexample, metadata-makes-ast-comparison-unstable-counterexample, the-corpus-silently-omits-a-syntax-family-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real Code.string_to_quoted, Macro, mix format boundary from a clean shell.
  • Mutation check: violate “Every supported syntax family has a valid fixture” and prove the suite reports fixture reserved-words-positive as failed.
  • Regression corpus: retain the risks “A formatter change is mistaken for semantic change”; “Metadata makes AST comparison unstable”; “The corpus silently omits a syntax family” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “A formatter change is mistaken for semantic change”

  • Why: This breaks one or more observable capabilities at the Code.string_to_quoted, Macro, mix format boundary while allowing the happy path to look correct.
  • Fix: Run a-formatter-change-is-mistaken-for-semantic-change-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “Metadata makes AST comparison unstable”

  • Why: This breaks one or more observable capabilities at the Code.string_to_quoted, Macro, mix format boundary while allowing the happy path to look correct.
  • Fix: Run metadata-makes-ast-comparison-unstable-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “The corpus silently omits a syntax family”

  • Why: This breaks one or more observable capabilities at the Code.string_to_quoted, Macro, mix format boundary while allowing the happy path to look correct.
  • Fix: Run the-corpus-silently-omits-a-syntax-family-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • Every supported syntax family has a valid fixture.
  • Every invalid fixture fails with an expected parser reason.
  • Formatted valid forms parse to the same structural AST.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 3: Subscription Quote Rules REPL

Official topic: Basic types — Elixir v1.20.2

Source file: lib/elixir/pages/getting-started/basic-types.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Core Language / Values
  • Software or Tool: IEx and Elixir scripts
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build a fixed subscription quotation REPL that combines numeric bases, integer and float operations, atoms, booleans, nil, strict comparison, interpolation, and Unicode receipt text.

Why it teaches this official topic: The artifact makes numbers and arithmetic, strict booleans and truthiness, atoms and nil, UTF-8 strings and comparison observable through one bounded build instead of isolated syntax examples.

Scope boundary: Keep this a fixed calculation and value-semantics exercise, not an open calculator or compile-time business DSL.

Core challenges you will face:

  • numbers and arithmetic -> identify the accepted case, the counterexample, and the observable result at the IEx and Elixir scripts boundary
  • strict booleans and truthiness -> identify the accepted case, the counterexample, and the observable result at the IEx and Elixir scripts boundary
  • atoms and nil -> identify the accepted case, the counterexample, and the observable result at the IEx and Elixir scripts boundary
  • UTF-8 strings and comparison -> identify the accepted case, the counterexample, and the observable result at the IEx and Elixir scripts boundary

Real World Outcome

Build a fixed subscription quotation REPL that combines numeric bases, integer and float operations, atoms, booleans, nil, strict comparison, interpolation, and Unicode receipt text. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Quotes distinguish integer and floating-point rules.
  • Eligibility uses explicit boolean policy.
  • Unicode receipt byte and grapheme measurements are reported.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=getting-started/basic-types.md
ARTIFACT=subscription-quote-rules-repl
CHECK 01 PASS :: Quotes distinguish integer and floating-point rules
CHECK 02 PASS :: Eligibility uses explicit boolean policy
CHECK 03 PASS :: Unicode receipt byte and grapheme measurements are reported
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“How do Elixir value types and comparison rules shape a small business calculation without hidden coercion?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. numbers and arithmetic
    • Working rule: Make “numbers and arithmetic” an explicit rule at the IEx and Elixir scripts boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "numbers-and-arithmetic-positive", focus: "numbers and arithmetic", mode: :positive, expect: :observable} and %{id: "numbers-and-arithmetic-negative", focus: "numbers and arithmetic", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Basic types
  2. strict booleans and truthiness
    • Working rule: Make “strict booleans and truthiness” an explicit rule at the IEx and Elixir scripts boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "strict-booleans-and-truthiness-positive", focus: "strict booleans and truthiness", mode: :positive, expect: :observable} and %{id: "strict-booleans-and-truthiness-negative", focus: "strict booleans and truthiness", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Basic types
  3. atoms and nil
    • Working rule: Make “atoms and nil” an explicit rule at the IEx and Elixir scripts boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "atoms-and-nil-positive", focus: "atoms and nil", mode: :positive, expect: :observable} and %{id: "atoms-and-nil-negative", focus: "atoms and nil", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Basic types
  4. UTF-8 strings and comparison
    • Working rule: Make “UTF-8 strings and comparison” an explicit rule at the IEx and Elixir scripts boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "utf-8-strings-and-comparison-positive", focus: "UTF-8 strings and comparison", mode: :positive, expect: :observable} and %{id: "utf-8-strings-and-comparison-negative", focus: "UTF-8 strings and comparison", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Basic types

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “numbers and arithmetic” be enforced?
    • Which check catches the risk “Strict and structural equality are conflated”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Quotes distinguish integer and floating-point rules”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Basic types”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: numbers and arithmetic, strict booleans and truthiness, atoms and nil, UTF-8 strings and comparison. Then trace the named counterexample “Strict and structural equality are conflated” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose numbers and arithmetic, and what does this project prove about it?”
  2. “What interaction between the concept ‘strict booleans and truthiness’ and the concept ‘numbers and arithmetic’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘Strict and structural equality are conflated’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with numbers-and-arithmetic-positive and strict-and-structural-equality-are-conflated-counterexample. The first must make the concept “numbers and arithmetic” observable and establish “Quotes distinguish integer and floating-point rules”; the second must reproduce “Strict and structural equality are conflated”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for getting-started/basic-types.md
evaluate "numbers and arithmetic" through IEx and Elixir scripts
compare actual evidence with "Quotes distinguish integer and floating-point rules"
run negative fixture for "Strict and structural equality are conflated"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Basic types Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
numbers and arithmetic Elixir in Action, 3rd Edition Ch. 2-4
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement numbers-and-arithmetic-positive and prove “Quotes distinguish integer and floating-point rules”.
  3. Topic coverage: add fixtures for strict booleans and truthiness, atoms and nil, UTF-8 strings and comparison.
  4. Failure campaign: reproduce each named risk: “Strict and structural equality are conflated”; “Truthiness accepts an unintended value”; “Byte length is presented as user-visible length”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute numbers-and-arithmetic-positive, strict-booleans-and-truthiness-positive, atoms-and-nil-positive, utf-8-strings-and-comparison-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute numbers-and-arithmetic-negative, strict-booleans-and-truthiness-negative, atoms-and-nil-negative, utf-8-strings-and-comparison-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute strict-and-structural-equality-are-conflated-counterexample, truthiness-accepts-an-unintended-value-counterexample, byte-length-is-presented-as-user-visible-length-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real IEx and Elixir scripts boundary from a clean shell.
  • Mutation check: violate “Quotes distinguish integer and floating-point rules” and prove the suite reports fixture numbers-and-arithmetic-positive as failed.
  • Regression corpus: retain the risks “Strict and structural equality are conflated”; “Truthiness accepts an unintended value”; “Byte length is presented as user-visible length” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “Strict and structural equality are conflated”

  • Why: This breaks one or more observable capabilities at the IEx and Elixir scripts boundary while allowing the happy path to look correct.
  • Fix: Run strict-and-structural-equality-are-conflated-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “Truthiness accepts an unintended value”

  • Why: This breaks one or more observable capabilities at the IEx and Elixir scripts boundary while allowing the happy path to look correct.
  • Fix: Run truthiness-accepts-an-unintended-value-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “Byte length is presented as user-visible length”

  • Why: This breaks one or more observable capabilities at the IEx and Elixir scripts boundary while allowing the happy path to look correct.
  • Fix: Run byte-length-is-presented-as-user-visible-length-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • Quotes distinguish integer and floating-point rules.
  • Eligibility uses explicit boolean policy.
  • Unicode receipt byte and grapheme measurements are reported.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 4: Operator Precedence and Readability Auditor

Official topic: Operators reference — Elixir v1.20.2

Source file: lib/elixir/pages/references/operators.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Language Semantics / Readability
  • Software or Tool: Code.string_to_quoted and Macro.to_string
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build a diagnostic that parses expressions, renders their grouping and AST, contrasts strict and relaxed boolean and equality operators, and flags unjustified custom operator imports.

Why it teaches this official topic: The artifact makes operator precedence, associativity, strict versus relaxed booleans, custom operator imports observable through one bounded build instead of isolated syntax examples.

Scope boundary: This is a diagnostic and readability artifact, not a business operator DSL.

Core challenges you will face:

  • operator precedence -> identify the accepted case, the counterexample, and the observable result at the Code.string_to_quoted and Macro.to_string boundary
  • associativity -> identify the accepted case, the counterexample, and the observable result at the Code.string_to_quoted and Macro.to_string boundary
  • strict versus relaxed booleans -> identify the accepted case, the counterexample, and the observable result at the Code.string_to_quoted and Macro.to_string boundary
  • custom operator imports -> identify the accepted case, the counterexample, and the observable result at the Code.string_to_quoted and Macro.to_string boundary

Real World Outcome

Build a diagnostic that parses expressions, renders their grouping and AST, contrasts strict and relaxed boolean and equality operators, and flags unjustified custom operator imports. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Grouping is rendered for every precedence tier.
  • Strict and relaxed semantics have counterexamples.
  • Custom operators require an explicit readability waiver.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=references/operators.md
ARTIFACT=operator-precedence-and-readability-auditor
CHECK 01 PASS :: Grouping is rendered for every precedence tier
CHECK 02 PASS :: Strict and relaxed semantics have counterexamples
CHECK 03 PASS :: Custom operators require an explicit readability waiver
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“Can a reviewer predict an expression result from precedence, associativity, and operator semantics before running it?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. operator precedence
    • Working rule: Make “operator precedence” an explicit rule at the Code.string_to_quoted and Macro.to_string boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "operator-precedence-positive", focus: "operator precedence", mode: :positive, expect: :observable} and %{id: "operator-precedence-negative", focus: "operator precedence", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Operators reference
  2. associativity
    • Working rule: Make “associativity” an explicit rule at the Code.string_to_quoted and Macro.to_string boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "associativity-positive", focus: "associativity", mode: :positive, expect: :observable} and %{id: "associativity-negative", focus: "associativity", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Operators reference
  3. strict versus relaxed booleans
    • Working rule: Make “strict versus relaxed booleans” an explicit rule at the Code.string_to_quoted and Macro.to_string boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "strict-versus-relaxed-booleans-positive", focus: "strict versus relaxed booleans", mode: :positive, expect: :observable} and %{id: "strict-versus-relaxed-booleans-negative", focus: "strict versus relaxed booleans", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Operators reference
  4. custom operator imports
    • Working rule: Make “custom operator imports” an explicit rule at the Code.string_to_quoted and Macro.to_string boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "custom-operator-imports-positive", focus: "custom operator imports", mode: :positive, expect: :observable} and %{id: "custom-operator-imports-negative", focus: "custom operator imports", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Operators reference

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “operator precedence” be enforced?
    • Which check catches the risk “Rendered source hides original grouping”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Grouping is rendered for every precedence tier”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Operators reference”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: operator precedence, associativity, strict versus relaxed booleans, custom operator imports. Then trace the named counterexample “Rendered source hides original grouping” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose operator precedence, and what does this project prove about it?”
  2. “What interaction between the concept ‘associativity’ and the concept ‘operator precedence’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘Rendered source hides original grouping’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with operator-precedence-positive and rendered-source-hides-original-grouping-counterexample. The first must make the concept “operator precedence” observable and establish “Grouping is rendered for every precedence tier”; the second must reproduce “Rendered source hides original grouping”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for references/operators.md
evaluate "operator precedence" through Code.string_to_quoted and Macro.to_string
compare actual evidence with "Grouping is rendered for every precedence tier"
run negative fixture for "Rendered source hides original grouping"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Operators reference Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
operator precedence Elixir in Action, 3rd Edition Ch. 2-4
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement operator-precedence-positive and prove “Grouping is rendered for every precedence tier”.
  3. Topic coverage: add fixtures for associativity, strict versus relaxed booleans, custom operator imports.
  4. Failure campaign: reproduce each named risk: “Rendered source hides original grouping”; “Numeric equality policy is left implicit”; “A custom operator changes meaning through import scope”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute operator-precedence-positive, associativity-positive, strict-versus-relaxed-booleans-positive, custom-operator-imports-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute operator-precedence-negative, associativity-negative, strict-versus-relaxed-booleans-negative, custom-operator-imports-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute rendered-source-hides-original-grouping-counterexample, numeric-equality-policy-is-left-implicit-counterexample, a-custom-operator-changes-meaning-through-import-scope-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real Code.string_to_quoted and Macro.to_string boundary from a clean shell.
  • Mutation check: violate “Grouping is rendered for every precedence tier” and prove the suite reports fixture operator-precedence-positive as failed.
  • Regression corpus: retain the risks “Rendered source hides original grouping”; “Numeric equality policy is left implicit”; “A custom operator changes meaning through import scope” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “Rendered source hides original grouping”

  • Why: This breaks one or more observable capabilities at the Code.string_to_quoted and Macro.to_string boundary while allowing the happy path to look correct.
  • Fix: Run rendered-source-hides-original-grouping-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “Numeric equality policy is left implicit”

  • Why: This breaks one or more observable capabilities at the Code.string_to_quoted and Macro.to_string boundary while allowing the happy path to look correct.
  • Fix: Run numeric-equality-policy-is-left-implicit-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “A custom operator changes meaning through import scope”

  • Why: This breaks one or more observable capabilities at the Code.string_to_quoted and Macro.to_string boundary while allowing the happy path to look correct.
  • Fix: Run a-custom-operator-changes-meaning-through-import-scope-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • Grouping is rendered for every precedence tier.
  • Strict and relaxed semantics have counterexamples.
  • Custom operators require an explicit readability waiver.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 5: Batch Delivery Outcome Ledger

Official topic: Lists and tuples — Elixir v1.20.2

Source file: lib/elixir/pages/getting-started/lists-and-tuples.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Data Structures / Complexity
  • Software or Tool: IEx, Benchee optional
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build an in-memory delivery ledger that stores ordered attempts in lists, represents each result as a tagged tuple, and reports the measured cost of prepend, append, length, and tuple access choices.

Why it teaches this official topic: The artifact makes linked-list structure, tagged tuples, structural sharing, size versus length observable through one bounded build instead of isolated syntax examples.

Scope boundary: Use in-memory outcomes only; do not parse settlement files or build persistence.

Core challenges you will face:

  • linked-list structure -> identify the accepted case, the counterexample, and the observable result at the IEx, Benchee optional boundary
  • tagged tuples -> identify the accepted case, the counterexample, and the observable result at the IEx, Benchee optional boundary
  • structural sharing -> identify the accepted case, the counterexample, and the observable result at the IEx, Benchee optional boundary
  • size versus length -> identify the accepted case, the counterexample, and the observable result at the IEx, Benchee optional boundary

Real World Outcome

Build an in-memory delivery ledger that stores ordered attempts in lists, represents each result as a tagged tuple, and reports the measured cost of prepend, append, length, and tuple access choices. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Delivery order and tagged outcomes are preserved.
  • Chosen operations match the collection cost model.
  • Improper and charlist-looking lists are identified explicitly.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=getting-started/lists-and-tuples.md
ARTIFACT=batch-delivery-outcome-ledger
CHECK 01 PASS :: Delivery order and tagged outcomes are preserved
CHECK 02 PASS :: Chosen operations match the collection cost model
CHECK 03 PASS :: Improper and charlist-looking lists are identified explicitly
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“When should an immutable sequence be a list and when should a fixed result be a tuple?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. linked-list structure
    • Working rule: Make “linked-list structure” an explicit rule at the IEx, Benchee optional boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "linked-list-structure-positive", focus: "linked-list structure", mode: :positive, expect: :observable} and %{id: "linked-list-structure-negative", focus: "linked-list structure", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Lists and tuples
  2. tagged tuples
    • Working rule: Make “tagged tuples” an explicit rule at the IEx, Benchee optional boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "tagged-tuples-positive", focus: "tagged tuples", mode: :positive, expect: :observable} and %{id: "tagged-tuples-negative", focus: "tagged tuples", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Lists and tuples
  3. structural sharing
    • Working rule: Make “structural sharing” an explicit rule at the IEx, Benchee optional boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "structural-sharing-positive", focus: "structural sharing", mode: :positive, expect: :observable} and %{id: "structural-sharing-negative", focus: "structural sharing", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Lists and tuples
  4. size versus length
    • Working rule: Make “size versus length” an explicit rule at the IEx, Benchee optional boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "size-versus-length-positive", focus: "size versus length", mode: :positive, expect: :observable} and %{id: "size-versus-length-negative", focus: "size versus length", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Lists and tuples

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “linked-list structure” be enforced?
    • Which check catches the risk “Repeated append creates quadratic work”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Delivery order and tagged outcomes are preserved”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Lists and tuples”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: linked-list structure, tagged tuples, structural sharing, size versus length. Then trace the named counterexample “Repeated append creates quadratic work” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose linked-list structure, and what does this project prove about it?”
  2. “What interaction between the concept ‘tagged tuples’ and the concept ‘linked-list structure’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘Repeated append creates quadratic work’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with linked-list-structure-positive and repeated-append-creates-quadratic-work-counterexample. The first must make the concept “linked-list structure” observable and establish “Delivery order and tagged outcomes are preserved”; the second must reproduce “Repeated append creates quadratic work”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for getting-started/lists-and-tuples.md
evaluate "linked-list structure" through IEx, Benchee optional
compare actual evidence with "Delivery order and tagged outcomes are preserved"
run negative fixture for "Repeated append creates quadratic work"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Lists and tuples Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
linked-list structure Elixir in Action, 3rd Edition Ch. 2-4
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement linked-list-structure-positive and prove “Delivery order and tagged outcomes are preserved”.
  3. Topic coverage: add fixtures for tagged tuples, structural sharing, size versus length.
  4. Failure campaign: reproduce each named risk: “Repeated append creates quadratic work”; “A tuple is used for variable-cardinality data”; “A list of integers is misread as text”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute linked-list-structure-positive, tagged-tuples-positive, structural-sharing-positive, size-versus-length-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute linked-list-structure-negative, tagged-tuples-negative, structural-sharing-negative, size-versus-length-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute repeated-append-creates-quadratic-work-counterexample, a-tuple-is-used-for-variable-cardinality-data-counterexample, a-list-of-integers-is-misread-as-text-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real IEx, Benchee optional boundary from a clean shell.
  • Mutation check: violate “Delivery order and tagged outcomes are preserved” and prove the suite reports fixture linked-list-structure-positive as failed.
  • Regression corpus: retain the risks “Repeated append creates quadratic work”; “A tuple is used for variable-cardinality data”; “A list of integers is misread as text” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “Repeated append creates quadratic work”

  • Why: This breaks one or more observable capabilities at the IEx, Benchee optional boundary while allowing the happy path to look correct.
  • Fix: Run repeated-append-creates-quadratic-work-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “A tuple is used for variable-cardinality data”

  • Why: This breaks one or more observable capabilities at the IEx, Benchee optional boundary while allowing the happy path to look correct.
  • Fix: Run a-tuple-is-used-for-variable-cardinality-data-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “A list of integers is misread as text”

  • Why: This breaks one or more observable capabilities at the IEx, Benchee optional boundary while allowing the happy path to look correct.
  • Fix: Run a-list-of-integers-is-misread-as-text-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • Delivery order and tagged outcomes are preserved.
  • Chosen operations match the collection cost model.
  • Improper and charlist-looking lists are identified explicitly.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 6: Conference Registration Options Normalizer

Official topic: Keyword lists and maps — Elixir v1.20.2

Source file: lib/elixir/pages/getting-started/keywords-and-maps.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Collections / Configuration Shapes
  • Software or Tool: Keyword, Map, Access
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build a pure registration normalizer that preserves repeated keyword options, validates fixed attendee-map keys, and immutably updates nested accessibility and meal preferences.

Why it teaches this official topic: The artifact makes keyword-list semantics, map key access, subset pattern matching, nested immutable updates observable through one bounded build instead of isolated syntax examples.

Scope boundary: Keep the lesson to collection semantics; exclude application configuration, databases, and dynamic tenant settings.

Core challenges you will face:

  • keyword-list semantics -> identify the accepted case, the counterexample, and the observable result at the Keyword, Map, Access boundary
  • map key access -> identify the accepted case, the counterexample, and the observable result at the Keyword, Map, Access boundary
  • subset pattern matching -> identify the accepted case, the counterexample, and the observable result at the Keyword, Map, Access boundary
  • nested immutable updates -> identify the accepted case, the counterexample, and the observable result at the Keyword, Map, Access boundary

Real World Outcome

Build a pure registration normalizer that preserves repeated keyword options, validates fixed attendee-map keys, and immutably updates nested accessibility and meal preferences. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Repeated ordered options remain observable.
  • Required fixed keys fail assertively.
  • Nested updates preserve unrelated preferences.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=getting-started/keywords-and-maps.md
ARTIFACT=conference-registration-options-normalizer
CHECK 01 PASS :: Repeated ordered options remain observable
CHECK 02 PASS :: Required fixed keys fail assertively
CHECK 03 PASS :: Nested updates preserve unrelated preferences
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“How do keyword lists and maps communicate different contracts even though both contain key-value pairs?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. keyword-list semantics
    • Working rule: Make “keyword-list semantics” an explicit rule at the Keyword, Map, Access boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "keyword-list-semantics-positive", focus: "keyword-list semantics", mode: :positive, expect: :observable} and %{id: "keyword-list-semantics-negative", focus: "keyword-list semantics", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Keyword lists and maps
  2. map key access
    • Working rule: Make “map key access” an explicit rule at the Keyword, Map, Access boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "map-key-access-positive", focus: "map key access", mode: :positive, expect: :observable} and %{id: "map-key-access-negative", focus: "map key access", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Keyword lists and maps
  3. subset pattern matching
    • Working rule: Make “subset pattern matching” an explicit rule at the Keyword, Map, Access boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "subset-pattern-matching-positive", focus: "subset pattern matching", mode: :positive, expect: :observable} and %{id: "subset-pattern-matching-negative", focus: "subset pattern matching", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Keyword lists and maps
  4. nested immutable updates
    • Working rule: Make “nested immutable updates” an explicit rule at the Keyword, Map, Access boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "nested-immutable-updates-positive", focus: "nested immutable updates", mode: :positive, expect: :observable} and %{id: "nested-immutable-updates-negative", focus: "nested immutable updates", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Keyword lists and maps

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “keyword-list semantics” be enforced?
    • Which check catches the risk “A keyword list is treated as a general map”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Repeated ordered options remain observable”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Keyword lists and maps”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: keyword-list semantics, map key access, subset pattern matching, nested immutable updates. Then trace the named counterexample “A keyword list is treated as a general map” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose keyword-list semantics, and what does this project prove about it?”
  2. “What interaction between the concept ‘map key access’ and the concept ‘keyword-list semantics’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘A keyword list is treated as a general map’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with keyword-list-semantics-positive and a-keyword-list-is-treated-as-a-general-map-counterexample. The first must make the concept “keyword-list semantics” observable and establish “Repeated ordered options remain observable”; the second must reproduce “A keyword list is treated as a general map”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for getting-started/keywords-and-maps.md
evaluate "keyword-list semantics" through Keyword, Map, Access
compare actual evidence with "Repeated ordered options remain observable"
run negative fixture for "A keyword list is treated as a general map"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Keyword lists and maps Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
keyword-list semantics Elixir in Action, 3rd Edition Ch. 2-4
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement keyword-list-semantics-positive and prove “Repeated ordered options remain observable”.
  3. Topic coverage: add fixtures for map key access, subset pattern matching, nested immutable updates.
  4. Failure campaign: reproduce each named risk: “A keyword list is treated as a general map”; “Bracket access hides a required missing key”; “A nested update silently creates the wrong path”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute keyword-list-semantics-positive, map-key-access-positive, subset-pattern-matching-positive, nested-immutable-updates-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute keyword-list-semantics-negative, map-key-access-negative, subset-pattern-matching-negative, nested-immutable-updates-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute a-keyword-list-is-treated-as-a-general-map-counterexample, bracket-access-hides-a-required-missing-key-counterexample, a-nested-update-silently-creates-the-wrong-path-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real Keyword, Map, Access boundary from a clean shell.
  • Mutation check: violate “Repeated ordered options remain observable” and prove the suite reports fixture keyword-list-semantics-positive as failed.
  • Regression corpus: retain the risks “A keyword list is treated as a general map”; “Bracket access hides a required missing key”; “A nested update silently creates the wrong path” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “A keyword list is treated as a general map”

  • Why: This breaks one or more observable capabilities at the Keyword, Map, Access boundary while allowing the happy path to look correct.
  • Fix: Run a-keyword-list-is-treated-as-a-general-map-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “Bracket access hides a required missing key”

  • Why: This breaks one or more observable capabilities at the Keyword, Map, Access boundary while allowing the happy path to look correct.
  • Fix: Run bracket-access-hides-a-required-missing-key-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “A nested update silently creates the wrong path”

  • Why: This breaks one or more observable capabilities at the Keyword, Map, Access boundary while allowing the happy path to look correct.
  • Fix: Run a-nested-update-silently-creates-the-wrong-path-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • Repeated ordered options remain observable.
  • Required fixed keys fail assertively.
  • Nested updates preserve unrelated preferences.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 7: Warehouse Scan Correlator

Official topic: Pattern matching — Elixir v1.20.2

Source file: lib/elixir/pages/getting-started/pattern-matching.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Language Semantics / Destructuring
  • Software or Tool: Elixir pattern matching
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build a pure correlator that destructures scan tuples and lists, pins the expected shipment identifier, separates accepted and mismatched shapes, and records unmatched evidence.

Why it teaches this official topic: The artifact makes match operator, tuple and list destructuring, repeated variables, pin operator observable through one bounded build instead of isolated syntax examples.

Scope boundary: Keep the artifact local and structural; do not add event delivery, persistence, or authenticated webhooks.

Core challenges you will face:

  • match operator -> identify the accepted case, the counterexample, and the observable result at the Elixir pattern matching boundary
  • tuple and list destructuring -> identify the accepted case, the counterexample, and the observable result at the Elixir pattern matching boundary
  • repeated variables -> identify the accepted case, the counterexample, and the observable result at the Elixir pattern matching boundary
  • pin operator -> identify the accepted case, the counterexample, and the observable result at the Elixir pattern matching boundary

Real World Outcome

Build a pure correlator that destructures scan tuples and lists, pins the expected shipment identifier, separates accepted and mismatched shapes, and records unmatched evidence. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Expected shipment identifiers cannot be rebound.
  • Every supported scan shape has one explicit clause.
  • Unmatched input remains data in the verification report.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=getting-started/pattern-matching.md
ARTIFACT=warehouse-scan-correlator
CHECK 01 PASS :: Expected shipment identifiers cannot be rebound
CHECK 02 PASS :: Every supported scan shape has one explicit clause
CHECK 03 PASS :: Unmatched input remains data in the verification report
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“How does pattern matching turn data shape into an executable contract rather than a sequence of field lookups?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. match operator
    • Working rule: Make “match operator” an explicit rule at the Elixir pattern matching boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "match-operator-positive", focus: "match operator", mode: :positive, expect: :observable} and %{id: "match-operator-negative", focus: "match operator", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Pattern matching
  2. tuple and list destructuring
    • Working rule: Make “tuple and list destructuring” an explicit rule at the Elixir pattern matching boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "tuple-and-list-destructuring-positive", focus: "tuple and list destructuring", mode: :positive, expect: :observable} and %{id: "tuple-and-list-destructuring-negative", focus: "tuple and list destructuring", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Pattern matching
  3. repeated variables
    • Working rule: Make “repeated variables” an explicit rule at the Elixir pattern matching boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "repeated-variables-positive", focus: "repeated variables", mode: :positive, expect: :observable} and %{id: "repeated-variables-negative", focus: "repeated variables", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Pattern matching
  4. pin operator
    • Working rule: Make “pin operator” an explicit rule at the Elixir pattern matching boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "pin-operator-positive", focus: "pin operator", mode: :positive, expect: :observable} and %{id: "pin-operator-negative", focus: "pin operator", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Pattern matching

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “match operator” be enforced?
    • Which check catches the risk “A variable is accidentally rebound”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Expected shipment identifiers cannot be rebound”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Pattern matching”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: match operator, tuple and list destructuring, repeated variables, pin operator. Then trace the named counterexample “A variable is accidentally rebound” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose match operator, and what does this project prove about it?”
  2. “What interaction between the concept ‘tuple and list destructuring’ and the concept ‘match operator’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘A variable is accidentally rebound’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with match-operator-positive and a-variable-is-accidentally-rebound-counterexample. The first must make the concept “match operator” observable and establish “Expected shipment identifiers cannot be rebound”; the second must reproduce “A variable is accidentally rebound”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for getting-started/pattern-matching.md
evaluate "match operator" through Elixir pattern matching
compare actual evidence with "Expected shipment identifiers cannot be rebound"
run negative fixture for "A variable is accidentally rebound"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Pattern matching Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
match operator Elixir in Action, 3rd Edition Ch. 2-4
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement match-operator-positive and prove “Expected shipment identifiers cannot be rebound”.
  3. Topic coverage: add fixtures for tuple and list destructuring, repeated variables, pin operator.
  4. Failure campaign: reproduce each named risk: “A variable is accidentally rebound”; “A broad clause shadows a specific one”; “MatchError is used for ordinary external input”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute match-operator-positive, tuple-and-list-destructuring-positive, repeated-variables-positive, pin-operator-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute match-operator-negative, tuple-and-list-destructuring-negative, repeated-variables-negative, pin-operator-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute a-variable-is-accidentally-rebound-counterexample, a-broad-clause-shadows-a-specific-one-counterexample, matcherror-is-used-for-ordinary-external-input-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real Elixir pattern matching boundary from a clean shell.
  • Mutation check: violate “Expected shipment identifiers cannot be rebound” and prove the suite reports fixture match-operator-positive as failed.
  • Regression corpus: retain the risks “A variable is accidentally rebound”; “A broad clause shadows a specific one”; “MatchError is used for ordinary external input” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “A variable is accidentally rebound”

  • Why: This breaks one or more observable capabilities at the Elixir pattern matching boundary while allowing the happy path to look correct.
  • Fix: Run a-variable-is-accidentally-rebound-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “A broad clause shadows a specific one”

  • Why: This breaks one or more observable capabilities at the Elixir pattern matching boundary while allowing the happy path to look correct.
  • Fix: Run a-broad-clause-shadows-a-specific-one-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “MatchError is used for ordinary external input”

  • Why: This breaks one or more observable capabilities at the Elixir pattern matching boundary while allowing the happy path to look correct.
  • Fix: Run matcherror-is-used-for-ordinary-external-input-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • Expected shipment identifiers cannot be rebound.
  • Every supported scan shape has one explicit clause.
  • Unmatched input remains data in the verification report.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 8: Explainable Event Contract Router

Official topic: Patterns and guards — Elixir v1.20.2

Source file: lib/elixir/pages/references/patterns-and-guards.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Dispatch / Guards
  • Software or Tool: Patterns, guards, defguard
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build a pure router for tuple, list, map, struct, and binary events that emits the matched clause and guard decision, backed by a property-oriented contract matrix.

Why it teaches this official topic: The artifact makes data-shape patterns, guard whitelist, guard failure as non-match, custom guard expressions observable through one bounded build instead of isolated syntax examples.

Scope boundary: Teach dispatch semantics across term shapes; do not become another binary parser or network gateway.

Core challenges you will face:

  • data-shape patterns -> identify the accepted case, the counterexample, and the observable result at the Patterns, guards, defguard boundary
  • guard whitelist -> identify the accepted case, the counterexample, and the observable result at the Patterns, guards, defguard boundary
  • guard failure as non-match -> identify the accepted case, the counterexample, and the observable result at the Patterns, guards, defguard boundary
  • custom guard expressions -> identify the accepted case, the counterexample, and the observable result at the Patterns, guards, defguard boundary

Real World Outcome

Build a pure router for tuple, list, map, struct, and binary events that emits the matched clause and guard decision, backed by a property-oriented contract matrix. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Every event family reports the selected clause.
  • Guard errors become documented non-matches.
  • Custom guards remain legal in guard context.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=references/patterns-and-guards.md
ARTIFACT=explainable-event-contract-router
CHECK 01 PASS :: Every event family reports the selected clause
CHECK 02 PASS :: Guard errors become documented non-matches
CHECK 03 PASS :: Custom guards remain legal in guard context
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“How can patterns and guards express an explainable routing contract without hiding failures in nested conditionals?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. data-shape patterns
    • Working rule: Make “data-shape patterns” an explicit rule at the Patterns, guards, defguard boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "data-shape-patterns-positive", focus: "data-shape patterns", mode: :positive, expect: :observable} and %{id: "data-shape-patterns-negative", focus: "data-shape patterns", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Patterns and guards
  2. guard whitelist
    • Working rule: Make “guard whitelist” an explicit rule at the Patterns, guards, defguard boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "guard-whitelist-positive", focus: "guard whitelist", mode: :positive, expect: :observable} and %{id: "guard-whitelist-negative", focus: "guard whitelist", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Patterns and guards
  3. guard failure as non-match
    • Working rule: Make “guard failure as non-match” an explicit rule at the Patterns, guards, defguard boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "guard-failure-as-non-match-positive", focus: "guard failure as non-match", mode: :positive, expect: :observable} and %{id: "guard-failure-as-non-match-negative", focus: "guard failure as non-match", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Patterns and guards
  4. custom guard expressions
    • Working rule: Make “custom guard expressions” an explicit rule at the Patterns, guards, defguard boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "custom-guard-expressions-positive", focus: "custom guard expressions", mode: :positive, expect: :observable} and %{id: "custom-guard-expressions-negative", focus: "custom guard expressions", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Patterns and guards

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “data-shape patterns” be enforced?
    • Which check catches the risk “A guard calls an unsupported function”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Every event family reports the selected clause”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Patterns and guards”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: data-shape patterns, guard whitelist, guard failure as non-match, custom guard expressions. Then trace the named counterexample “A guard calls an unsupported function” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose data-shape patterns, and what does this project prove about it?”
  2. “What interaction between the concept ‘guard whitelist’ and the concept ‘data-shape patterns’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘A guard calls an unsupported function’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with data-shape-patterns-positive and a-guard-calls-an-unsupported-function-counterexample. The first must make the concept “data-shape patterns” observable and establish “Every event family reports the selected clause”; the second must reproduce “A guard calls an unsupported function”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for references/patterns-and-guards.md
evaluate "data-shape patterns" through Patterns, guards, defguard
compare actual evidence with "Every event family reports the selected clause"
run negative fixture for "A guard calls an unsupported function"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Patterns and guards Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
data-shape patterns Elixir in Action, 3rd Edition Ch. 2-4
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement data-shape-patterns-positive and prove “Every event family reports the selected clause”.
  3. Topic coverage: add fixtures for guard whitelist, guard failure as non-match, custom guard expressions.
  4. Failure campaign: reproduce each named risk: “A guard calls an unsupported function”; “Clause order changes the selected contract”; “Map subset matching is mistaken for exact matching”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute data-shape-patterns-positive, guard-whitelist-positive, guard-failure-as-non-match-positive, custom-guard-expressions-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute data-shape-patterns-negative, guard-whitelist-negative, guard-failure-as-non-match-negative, custom-guard-expressions-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute a-guard-calls-an-unsupported-function-counterexample, clause-order-changes-the-selected-contract-counterexample, map-subset-matching-is-mistaken-for-exact-matching-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real Patterns, guards, defguard boundary from a clean shell.
  • Mutation check: violate “Every event family reports the selected clause” and prove the suite reports fixture data-shape-patterns-positive as failed.
  • Regression corpus: retain the risks “A guard calls an unsupported function”; “Clause order changes the selected contract”; “Map subset matching is mistaken for exact matching” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “A guard calls an unsupported function”

  • Why: This breaks one or more observable capabilities at the Patterns, guards, defguard boundary while allowing the happy path to look correct.
  • Fix: Run a-guard-calls-an-unsupported-function-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “Clause order changes the selected contract”

  • Why: This breaks one or more observable capabilities at the Patterns, guards, defguard boundary while allowing the happy path to look correct.
  • Fix: Run clause-order-changes-the-selected-contract-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “Map subset matching is mistaken for exact matching”

  • Why: This breaks one or more observable capabilities at the Patterns, guards, defguard boundary while allowing the happy path to look correct.
  • Fix: Run map-subset-matching-is-mistaken-for-exact-matching-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • Every event family reports the selected clause.
  • Guard errors become documented non-matches.
  • Custom guards remain legal in guard context.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 9: Travel Reimbursement Decision Table

Official topic: case, cond, and if — Elixir v1.20.2

Source file: lib/elixir/pages/getting-started/case-cond-and-if.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Control Flow / Decision Modeling
  • Software or Tool: case, cond, if
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build pure reimbursement rules that classify claim shapes with case, apply guarded thresholds, isolate one truthy exception with if, and use ordered cond fallbacks.

Why it teaches this official topic: The artifact makes case clauses, guards and pinning, truthiness, ordered cond fallbacks observable through one bounded build instead of isolated syntax examples.

Scope boundary: This is a fixed pure decision table, not a configurable DSL or authorization policy engine.

Core challenges you will face:

  • case clauses -> identify the accepted case, the counterexample, and the observable result at the case, cond, if boundary
  • guards and pinning -> identify the accepted case, the counterexample, and the observable result at the case, cond, if boundary
  • truthiness -> identify the accepted case, the counterexample, and the observable result at the case, cond, if boundary
  • ordered cond fallbacks -> identify the accepted case, the counterexample, and the observable result at the case, cond, if boundary

Real World Outcome

Build pure reimbursement rules that classify claim shapes with case, apply guarded thresholds, isolate one truthy exception with if, and use ordered cond fallbacks. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Every claim category reaches one named decision.
  • Thresholds are enforced in guards.
  • The fallback clause is explicit and tested.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=getting-started/case-cond-and-if.md
ARTIFACT=travel-reimbursement-decision-table
CHECK 01 PASS :: Every claim category reaches one named decision
CHECK 02 PASS :: Thresholds are enforced in guards
CHECK 03 PASS :: The fallback clause is explicit and tested
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“Which Elixir branching construct best communicates each kind of business decision and its fallback?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. case clauses
    • Working rule: Make “case clauses” an explicit rule at the case, cond, if boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "case-clauses-positive", focus: "case clauses", mode: :positive, expect: :observable} and %{id: "case-clauses-negative", focus: "case clauses", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: case, cond, and if
  2. guards and pinning
    • Working rule: Make “guards and pinning” an explicit rule at the case, cond, if boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "guards-and-pinning-positive", focus: "guards and pinning", mode: :positive, expect: :observable} and %{id: "guards-and-pinning-negative", focus: "guards and pinning", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: case, cond, and if
  3. truthiness
    • Working rule: Make “truthiness” an explicit rule at the case, cond, if boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "truthiness-positive", focus: "truthiness", mode: :positive, expect: :observable} and %{id: "truthiness-negative", focus: "truthiness", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: case, cond, and if
  4. ordered cond fallbacks
    • Working rule: Make “ordered cond fallbacks” an explicit rule at the case, cond, if boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "ordered-cond-fallbacks-positive", focus: "ordered cond fallbacks", mode: :positive, expect: :observable} and %{id: "ordered-cond-fallbacks-negative", focus: "ordered cond fallbacks", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: case, cond, and if

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “case clauses” be enforced?
    • Which check catches the risk “A case expression is non-exhaustive”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Every claim category reaches one named decision”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “case, cond, and if”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: case clauses, guards and pinning, truthiness, ordered cond fallbacks. Then trace the named counterexample “A case expression is non-exhaustive” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose case clauses, and what does this project prove about it?”
  2. “What interaction between the concept ‘guards and pinning’ and the concept ‘case clauses’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘A case expression is non-exhaustive’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with case-clauses-positive and a-case-expression-is-non-exhaustive-counterexample. The first must make the concept “case clauses” observable and establish “Every claim category reaches one named decision”; the second must reproduce “A case expression is non-exhaustive”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for getting-started/case-cond-and-if.md
evaluate "case clauses" through case, cond, if
compare actual evidence with "Every claim category reaches one named decision"
run negative fixture for "A case expression is non-exhaustive"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
case, cond, and if Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
case clauses Elixir in Action, 3rd Edition Ch. 2-4
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement case-clauses-positive and prove “Every claim category reaches one named decision”.
  3. Topic coverage: add fixtures for guards and pinning, truthiness, ordered cond fallbacks.
  4. Failure campaign: reproduce each named risk: “A case expression is non-exhaustive”; “Nested if statements hide rule order”; “A truthy non-boolean passes an unintended condition”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute case-clauses-positive, guards-and-pinning-positive, truthiness-positive, ordered-cond-fallbacks-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute case-clauses-negative, guards-and-pinning-negative, truthiness-negative, ordered-cond-fallbacks-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute a-case-expression-is-non-exhaustive-counterexample, nested-if-statements-hide-rule-order-counterexample, a-truthy-non-boolean-passes-an-unintended-condition-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real case, cond, if boundary from a clean shell.
  • Mutation check: violate “Every claim category reaches one named decision” and prove the suite reports fixture case-clauses-positive as failed.
  • Regression corpus: retain the risks “A case expression is non-exhaustive”; “Nested if statements hide rule order”; “A truthy non-boolean passes an unintended condition” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “A case expression is non-exhaustive”

  • Why: This breaks one or more observable capabilities at the case, cond, if boundary while allowing the happy path to look correct.
  • Fix: Run a-case-expression-is-non-exhaustive-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “Nested if statements hide rule order”

  • Why: This breaks one or more observable capabilities at the case, cond, if boundary while allowing the happy path to look correct.
  • Fix: Run nested-if-statements-hide-rule-order-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “A truthy non-boolean passes an unintended condition”

  • Why: This breaks one or more observable capabilities at the case, cond, if boundary while allowing the happy path to look correct.
  • Fix: Run a-truthy-non-boolean-passes-an-unintended-condition-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • Every claim category reaches one named decision.
  • Thresholds are enforced in guards.
  • The fallback clause is explicit and tested.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 10: Dynamic Survey Scoring Pipeline

Official topic: Anonymous functions — Elixir v1.20.2

Source file: lib/elixir/pages/getting-started/anonymous-functions.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Functional Composition
  • Software or Tool: fn, capture operator, Function
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build a runtime scoring pipeline whose callbacks include closure-captured weights, guarded multi-clause anonymous functions, captured named functions, and explicit name/arity reporting.

Why it teaches this official topic: The artifact makes function name and arity, anonymous functions, closures, capture operator observable through one bounded build instead of isolated syntax examples.

Scope boundary: Keep strategies as runtime values; exclude compile-time macros, behaviours, and supervised pipelines.

Core challenges you will face:

  • function name and arity -> identify the accepted case, the counterexample, and the observable result at the fn, capture operator, Function boundary
  • anonymous functions -> identify the accepted case, the counterexample, and the observable result at the fn, capture operator, Function boundary
  • closures -> identify the accepted case, the counterexample, and the observable result at the fn, capture operator, Function boundary
  • capture operator -> identify the accepted case, the counterexample, and the observable result at the fn, capture operator, Function boundary

Real World Outcome

Build a runtime scoring pipeline whose callbacks include closure-captured weights, guarded multi-clause anonymous functions, captured named functions, and explicit name/arity reporting. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Runtime scoring strategies are first-class values.
  • Closure-captured weights remain lexically scoped.
  • Invalid answer shapes select an explicit guarded clause.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=getting-started/anonymous-functions.md
ARTIFACT=dynamic-survey-scoring-pipeline
CHECK 01 PASS :: Runtime scoring strategies are first-class values
CHECK 02 PASS :: Closure-captured weights remain lexically scoped
CHECK 03 PASS :: Invalid answer shapes select an explicit guarded clause
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“What becomes possible when behavior is passed as an immutable function value with a precise arity?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. function name and arity
    • Working rule: Make “function name and arity” an explicit rule at the fn, capture operator, Function boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "function-name-and-arity-positive", focus: "function name and arity", mode: :positive, expect: :observable} and %{id: "function-name-and-arity-negative", focus: "function name and arity", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Anonymous functions
  2. anonymous functions
    • Working rule: Make “anonymous functions” an explicit rule at the fn, capture operator, Function boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "anonymous-functions-positive", focus: "anonymous functions", mode: :positive, expect: :observable} and %{id: "anonymous-functions-negative", focus: "anonymous functions", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Anonymous functions
  3. closures
    • Working rule: Make “closures” an explicit rule at the fn, capture operator, Function boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "closures-positive", focus: "closures", mode: :positive, expect: :observable} and %{id: "closures-negative", focus: "closures", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Anonymous functions
  4. capture operator
    • Working rule: Make “capture operator” an explicit rule at the fn, capture operator, Function boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "capture-operator-positive", focus: "capture operator", mode: :positive, expect: :observable} and %{id: "capture-operator-negative", focus: "capture operator", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Anonymous functions

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “function name and arity” be enforced?
    • Which check catches the risk “Invocation dot syntax is omitted”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Runtime scoring strategies are first-class values”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Anonymous functions”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: function name and arity, anonymous functions, closures, capture operator. Then trace the named counterexample “Invocation dot syntax is omitted” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose function name and arity, and what does this project prove about it?”
  2. “What interaction between the concept ‘anonymous functions’ and the concept ‘function name and arity’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘Invocation dot syntax is omitted’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with function-name-and-arity-positive and invocation-dot-syntax-is-omitted-counterexample. The first must make the concept “function name and arity” observable and establish “Runtime scoring strategies are first-class values”; the second must reproduce “Invocation dot syntax is omitted”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for getting-started/anonymous-functions.md
evaluate "function name and arity" through fn, capture operator, Function
compare actual evidence with "Runtime scoring strategies are first-class values"
run negative fixture for "Invocation dot syntax is omitted"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Anonymous functions Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
function name and arity Elixir in Action, 3rd Edition Ch. 2-4
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement function-name-and-arity-positive and prove “Runtime scoring strategies are first-class values”.
  3. Topic coverage: add fixtures for anonymous functions, closures, capture operator.
  4. Failure campaign: reproduce each named risk: “Invocation dot syntax is omitted”; “A closure captures stale mutable assumptions”; “A capture shorthand obscures the intended arity”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute function-name-and-arity-positive, anonymous-functions-positive, closures-positive, capture-operator-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute function-name-and-arity-negative, anonymous-functions-negative, closures-negative, capture-operator-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute invocation-dot-syntax-is-omitted-counterexample, a-closure-captures-stale-mutable-assumptions-counterexample, a-capture-shorthand-obscures-the-intended-arity-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real fn, capture operator, Function boundary from a clean shell.
  • Mutation check: violate “Runtime scoring strategies are first-class values” and prove the suite reports fixture function-name-and-arity-positive as failed.
  • Regression corpus: retain the risks “Invocation dot syntax is omitted”; “A closure captures stale mutable assumptions”; “A capture shorthand obscures the intended arity” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “Invocation dot syntax is omitted”

  • Why: This breaks one or more observable capabilities at the fn, capture operator, Function boundary while allowing the happy path to look correct.
  • Fix: Run invocation-dot-syntax-is-omitted-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “A closure captures stale mutable assumptions”

  • Why: This breaks one or more observable capabilities at the fn, capture operator, Function boundary while allowing the happy path to look correct.
  • Fix: Run a-closure-captures-stale-mutable-assumptions-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “A capture shorthand obscures the intended arity”

  • Why: This breaks one or more observable capabilities at the fn, capture operator, Function boundary while allowing the happy path to look correct.
  • Fix: Run a-capture-shorthand-obscures-the-intended-arity-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • Runtime scoring strategies are first-class values.
  • Closure-captured weights remain lexically scoped.
  • Invalid answer shapes select an explicit guarded clause.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 11: Unicode Display-Name Audit CLI

Official topic: Binaries, strings, and charlists — Elixir v1.20.2

Source file: lib/elixir/pages/getting-started/binaries-strings-and-charlists.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Text / Binary Representation
  • Software or Tool: String, :unicode, bitstring syntax
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build a CLI that audits multilingual display names by bytes, code points, graphemes, binary segments, invalid UTF-8 fixtures, and charlist interchange with an Erlang API.

Why it teaches this official topic: The artifact makes UTF-8 encoding, code points and graphemes, binary and bitstring matching, charlist interoperability observable through one bounded build instead of isolated syntax examples.

Scope boundary: Focus on representation and interoperability, not general parsing or native acceleration.

Core challenges you will face:

  • UTF-8 encoding -> identify the accepted case, the counterexample, and the observable result at the String, :unicode, bitstring syntax boundary
  • code points and graphemes -> identify the accepted case, the counterexample, and the observable result at the String, :unicode, bitstring syntax boundary
  • binary and bitstring matching -> identify the accepted case, the counterexample, and the observable result at the String, :unicode, bitstring syntax boundary
  • charlist interoperability -> identify the accepted case, the counterexample, and the observable result at the String, :unicode, bitstring syntax boundary

Real World Outcome

Build a CLI that audits multilingual display names by bytes, code points, graphemes, binary segments, invalid UTF-8 fixtures, and charlist interchange with an Erlang API. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Reports distinguish bytes, code points, and graphemes.
  • Invalid UTF-8 is rejected with byte-position evidence.
  • Charlist conversion round-trips supported names.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=getting-started/binaries-strings-and-charlists.md
ARTIFACT=unicode-display-name-audit-cli
CHECK 01 PASS :: Reports distinguish bytes, code points, and graphemes
CHECK 02 PASS :: Invalid UTF-8 is rejected with byte-position evidence
CHECK 03 PASS :: Charlist conversion round-trips supported names
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“What exactly is an Elixir string at the byte level, and which user-visible units require different APIs?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. UTF-8 encoding
    • Working rule: Make “UTF-8 encoding” an explicit rule at the String, :unicode, bitstring syntax boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "utf-8-encoding-positive", focus: "UTF-8 encoding", mode: :positive, expect: :observable} and %{id: "utf-8-encoding-negative", focus: "UTF-8 encoding", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Binaries, strings, and charlists
  2. code points and graphemes
    • Working rule: Make “code points and graphemes” an explicit rule at the String, :unicode, bitstring syntax boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "code-points-and-graphemes-positive", focus: "code points and graphemes", mode: :positive, expect: :observable} and %{id: "code-points-and-graphemes-negative", focus: "code points and graphemes", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Binaries, strings, and charlists
  3. binary and bitstring matching
    • Working rule: Make “binary and bitstring matching” an explicit rule at the String, :unicode, bitstring syntax boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "binary-and-bitstring-matching-positive", focus: "binary and bitstring matching", mode: :positive, expect: :observable} and %{id: "binary-and-bitstring-matching-negative", focus: "binary and bitstring matching", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Binaries, strings, and charlists
  4. charlist interoperability
    • Working rule: Make “charlist interoperability” an explicit rule at the String, :unicode, bitstring syntax boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "charlist-interoperability-positive", focus: "charlist interoperability", mode: :positive, expect: :observable} and %{id: "charlist-interoperability-negative", focus: "charlist interoperability", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Binaries, strings, and charlists

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “UTF-8 encoding” be enforced?
    • Which check catches the risk “Byte count is shown as character count”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Reports distinguish bytes, code points, and graphemes”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Binaries, strings, and charlists”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: UTF-8 encoding, code points and graphemes, binary and bitstring matching, charlist interoperability. Then trace the named counterexample “Byte count is shown as character count” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose UTF-8 encoding, and what does this project prove about it?”
  2. “What interaction between the concept ‘code points and graphemes’ and the concept ‘UTF-8 encoding’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘Byte count is shown as character count’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with utf-8-encoding-positive and byte-count-is-shown-as-character-count-counterexample. The first must make the concept “UTF-8 encoding” observable and establish “Reports distinguish bytes, code points, and graphemes”; the second must reproduce “Byte count is shown as character count”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for getting-started/binaries-strings-and-charlists.md
evaluate "UTF-8 encoding" through String, :unicode, bitstring syntax
compare actual evidence with "Reports distinguish bytes, code points, and graphemes"
run negative fixture for "Byte count is shown as character count"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Binaries, strings, and charlists Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
UTF-8 encoding Elixir in Action, 3rd Edition Ch. 2-4
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement utf-8-encoding-positive and prove “Reports distinguish bytes, code points, and graphemes”.
  3. Topic coverage: add fixtures for code points and graphemes, binary and bitstring matching, charlist interoperability.
  4. Failure campaign: reproduce each named risk: “Byte count is shown as character count”; “A binary pattern splits inside a code point”; “A charlist is accepted where a UTF-8 binary is required”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute utf-8-encoding-positive, code-points-and-graphemes-positive, binary-and-bitstring-matching-positive, charlist-interoperability-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute utf-8-encoding-negative, code-points-and-graphemes-negative, binary-and-bitstring-matching-negative, charlist-interoperability-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute byte-count-is-shown-as-character-count-counterexample, a-binary-pattern-splits-inside-a-code-point-counterexample, a-charlist-is-accepted-where-a-utf-8-binary-is-required-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real String, :unicode, bitstring syntax boundary from a clean shell.
  • Mutation check: violate “Reports distinguish bytes, code points, and graphemes” and prove the suite reports fixture utf-8-encoding-positive as failed.
  • Regression corpus: retain the risks “Byte count is shown as character count”; “A binary pattern splits inside a code point”; “A charlist is accepted where a UTF-8 binary is required” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “Byte count is shown as character count”

  • Why: This breaks one or more observable capabilities at the String, :unicode, bitstring syntax boundary while allowing the happy path to look correct.
  • Fix: Run byte-count-is-shown-as-character-count-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “A binary pattern splits inside a code point”

  • Why: This breaks one or more observable capabilities at the String, :unicode, bitstring syntax boundary while allowing the happy path to look correct.
  • Fix: Run a-binary-pattern-splits-inside-a-code-point-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “A charlist is accepted where a UTF-8 binary is required”

  • Why: This breaks one or more observable capabilities at the String, :unicode, bitstring syntax boundary while allowing the happy path to look correct.
  • Fix: Run a-charlist-is-accepted-where-a-utf-8-binary-is-required-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • Reports distinguish bytes, code points, and graphemes.
  • Invalid UTF-8 is rejected with byte-position evidence.
  • Charlist conversion round-trips supported names.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 12: Unicode Identifier Confusables CI Scanner

Official topic: Unicode syntax — Elixir v1.20.2

Source file: lib/elixir/pages/references/unicode-syntax.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Source Security / Unicode
  • Software or Tool: Unicode data, tokenizer fixtures
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build a source scanner that reports normalization, mixed-script, restricted-character, and confusable identifier findings with safe remediation evidence derived from UAX 31 and UTS 39 policies.

Why it teaches this official topic: The artifact makes NFC normalization, identifier grammar, confusable characters, mixed-script restrictions observable through one bounded build instead of isolated syntax examples.

Scope boundary: Remain a Unicode source-identity gate rather than a general compiler migration linter.

Core challenges you will face:

  • NFC normalization -> identify the accepted case, the counterexample, and the observable result at the Unicode data, tokenizer fixtures boundary
  • identifier grammar -> identify the accepted case, the counterexample, and the observable result at the Unicode data, tokenizer fixtures boundary
  • confusable characters -> identify the accepted case, the counterexample, and the observable result at the Unicode data, tokenizer fixtures boundary
  • mixed-script restrictions -> identify the accepted case, the counterexample, and the observable result at the Unicode data, tokenizer fixtures boundary

Real World Outcome

Build a source scanner that reports normalization, mixed-script, restricted-character, and confusable identifier findings with safe remediation evidence derived from UAX 31 and UTS 39 policies. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Equivalent identifiers normalize consistently.
  • Mixed-script findings include code points and scripts.
  • Restricted and confusable cases have deterministic remediation.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=references/unicode-syntax.md
ARTIFACT=unicode-identifier-confusables-ci-scanner
CHECK 01 PASS :: Equivalent identifiers normalize consistently
CHECK 02 PASS :: Mixed-script findings include code points and scripts
CHECK 03 PASS :: Restricted and confusable cases have deterministic remediation
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“How can visually similar Elixir identifiers be distinguished and governed before they become a source-review vulnerability?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. NFC normalization
    • Working rule: Make “NFC normalization” an explicit rule at the Unicode data, tokenizer fixtures boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "nfc-normalization-positive", focus: "NFC normalization", mode: :positive, expect: :observable} and %{id: "nfc-normalization-negative", focus: "NFC normalization", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Unicode syntax
  2. identifier grammar
    • Working rule: Make “identifier grammar” an explicit rule at the Unicode data, tokenizer fixtures boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "identifier-grammar-positive", focus: "identifier grammar", mode: :positive, expect: :observable} and %{id: "identifier-grammar-negative", focus: "identifier grammar", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Unicode syntax
  3. confusable characters
    • Working rule: Make “confusable characters” an explicit rule at the Unicode data, tokenizer fixtures boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "confusable-characters-positive", focus: "confusable characters", mode: :positive, expect: :observable} and %{id: "confusable-characters-negative", focus: "confusable characters", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Unicode syntax
  4. mixed-script restrictions
    • Working rule: Make “mixed-script restrictions” an explicit rule at the Unicode data, tokenizer fixtures boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "mixed-script-restrictions-positive", focus: "mixed-script restrictions", mode: :positive, expect: :observable} and %{id: "mixed-script-restrictions-negative", focus: "mixed-script restrictions", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Unicode syntax

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “NFC normalization” be enforced?
    • Which check catches the risk “Normalization is applied only after comparison”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Equivalent identifiers normalize consistently”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Unicode syntax”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: NFC normalization, identifier grammar, confusable characters, mixed-script restrictions. Then trace the named counterexample “Normalization is applied only after comparison” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose NFC normalization, and what does this project prove about it?”
  2. “What interaction between the concept ‘identifier grammar’ and the concept ‘NFC normalization’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘Normalization is applied only after comparison’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with nfc-normalization-positive and normalization-is-applied-only-after-comparison-counterexample. The first must make the concept “NFC normalization” observable and establish “Equivalent identifiers normalize consistently”; the second must reproduce “Normalization is applied only after comparison”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for references/unicode-syntax.md
evaluate "NFC normalization" through Unicode data, tokenizer fixtures
compare actual evidence with "Equivalent identifiers normalize consistently"
run negative fixture for "Normalization is applied only after comparison"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Unicode syntax Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
NFC normalization Elixir in Action, 3rd Edition Ch. 2-4
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement nfc-normalization-positive and prove “Equivalent identifiers normalize consistently”.
  3. Topic coverage: add fixtures for identifier grammar, confusable characters, mixed-script restrictions.
  4. Failure campaign: reproduce each named risk: “Normalization is applied only after comparison”; “Display glyphs hide distinct code points”; “Atoms and aliases are treated as identical identifier classes”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute nfc-normalization-positive, identifier-grammar-positive, confusable-characters-positive, mixed-script-restrictions-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute nfc-normalization-negative, identifier-grammar-negative, confusable-characters-negative, mixed-script-restrictions-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute normalization-is-applied-only-after-comparison-counterexample, display-glyphs-hide-distinct-code-points-counterexample, atoms-and-aliases-are-treated-as-identical-identifier-classes-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real Unicode data, tokenizer fixtures boundary from a clean shell.
  • Mutation check: violate “Equivalent identifiers normalize consistently” and prove the suite reports fixture nfc-normalization-positive as failed.
  • Regression corpus: retain the risks “Normalization is applied only after comparison”; “Display glyphs hide distinct code points”; “Atoms and aliases are treated as identical identifier classes” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “Normalization is applied only after comparison”

  • Why: This breaks one or more observable capabilities at the Unicode data, tokenizer fixtures boundary while allowing the happy path to look correct.
  • Fix: Run normalization-is-applied-only-after-comparison-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “Display glyphs hide distinct code points”

  • Why: This breaks one or more observable capabilities at the Unicode data, tokenizer fixtures boundary while allowing the happy path to look correct.
  • Fix: Run display-glyphs-hide-distinct-code-points-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “Atoms and aliases are treated as identical identifier classes”

  • Why: This breaks one or more observable capabilities at the Unicode data, tokenizer fixtures boundary while allowing the happy path to look correct.
  • Fix: Run atoms-and-aliases-are-treated-as-identical-identifier-classes-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • Equivalent identifiers normalize consistently.
  • Mixed-script findings include code points and scripts.
  • Restricted and confusable cases have deterministic remediation.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 13: Measurement Conversion Toolkit

Official topic: Modules and functions — Elixir v1.20.2

Source file: lib/elixir/pages/getting-started/modules-and-functions.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Module and API Design
  • Software or Tool: defmodule, def, defp
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build a namespaced conversion library and executable script with public functions, private normalization, guarded clauses, explicit function heads, defaults, and alias-aware module organization.

Why it teaches this official topic: The artifact makes module definition, public and private functions, multi-clause functions, default arguments and function heads observable through one bounded build instead of isolated syntax examples.

Scope boundary: Teach module and function contracts without adapters, processes, or persistence.

Core challenges you will face:

  • module definition -> identify the accepted case, the counterexample, and the observable result at the defmodule, def, defp boundary
  • public and private functions -> identify the accepted case, the counterexample, and the observable result at the defmodule, def, defp boundary
  • multi-clause functions -> identify the accepted case, the counterexample, and the observable result at the defmodule, def, defp boundary
  • default arguments and function heads -> identify the accepted case, the counterexample, and the observable result at the defmodule, def, defp boundary

Real World Outcome

Build a namespaced conversion library and executable script with public functions, private normalization, guarded clauses, explicit function heads, defaults, and alias-aware module organization. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • The public API is small and namespaced.
  • Defaults are declared once in a function head.
  • Unsupported units fail through an explicit clause.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=getting-started/modules-and-functions.md
ARTIFACT=measurement-conversion-toolkit
CHECK 01 PASS :: The public API is small and namespaced
CHECK 02 PASS :: Defaults are declared once in a function head
CHECK 03 PASS :: Unsupported units fail through an explicit clause
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“How should clauses, guards, visibility, and defaults combine into an honest small Elixir API?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. module definition
    • Working rule: Make “module definition” an explicit rule at the defmodule, def, defp boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "module-definition-positive", focus: "module definition", mode: :positive, expect: :observable} and %{id: "module-definition-negative", focus: "module definition", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Modules and functions
  2. public and private functions
    • Working rule: Make “public and private functions” an explicit rule at the defmodule, def, defp boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "public-and-private-functions-positive", focus: "public and private functions", mode: :positive, expect: :observable} and %{id: "public-and-private-functions-negative", focus: "public and private functions", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Modules and functions
  3. multi-clause functions
    • Working rule: Make “multi-clause functions” an explicit rule at the defmodule, def, defp boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "multi-clause-functions-positive", focus: "multi-clause functions", mode: :positive, expect: :observable} and %{id: "multi-clause-functions-negative", focus: "multi-clause functions", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Modules and functions
  4. default arguments and function heads
    • Working rule: Make “default arguments and function heads” an explicit rule at the defmodule, def, defp boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "default-arguments-and-function-heads-positive", focus: "default arguments and function heads", mode: :positive, expect: :observable} and %{id: "default-arguments-and-function-heads-negative", focus: "default arguments and function heads", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Modules and functions

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “module definition” be enforced?
    • Which check catches the risk “Default values conflict across clauses”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “The public API is small and namespaced”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Modules and functions”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: module definition, public and private functions, multi-clause functions, default arguments and function heads. Then trace the named counterexample “Default values conflict across clauses” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose module definition, and what does this project prove about it?”
  2. “What interaction between the concept ‘public and private functions’ and the concept ‘module definition’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘Default values conflict across clauses’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with module-definition-positive and default-values-conflict-across-clauses-counterexample. The first must make the concept “module definition” observable and establish “The public API is small and namespaced”; the second must reproduce “Default values conflict across clauses”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for getting-started/modules-and-functions.md
evaluate "module definition" through defmodule, def, defp
compare actual evidence with "The public API is small and namespaced"
run negative fixture for "Default values conflict across clauses"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Modules and functions Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
module definition Elixir in Action, 3rd Edition Ch. 2-4
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement module-definition-positive and prove “The public API is small and namespaced”.
  3. Topic coverage: add fixtures for public and private functions, multi-clause functions, default arguments and function heads.
  4. Failure campaign: reproduce each named risk: “Default values conflict across clauses”; “Private normalization leaks into callers”; “Nested module names imply an ownership relationship that does not exist”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute module-definition-positive, public-and-private-functions-positive, multi-clause-functions-positive, default-arguments-and-function-heads-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute module-definition-negative, public-and-private-functions-negative, multi-clause-functions-negative, default-arguments-and-function-heads-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute default-values-conflict-across-clauses-counterexample, private-normalization-leaks-into-callers-counterexample, nested-module-names-imply-an-ownership-relationship-that-does-not-exist-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real defmodule, def, defp boundary from a clean shell.
  • Mutation check: violate “The public API is small and namespaced” and prove the suite reports fixture module-definition-positive as failed.
  • Regression corpus: retain the risks “Default values conflict across clauses”; “Private normalization leaks into callers”; “Nested module names imply an ownership relationship that does not exist” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “Default values conflict across clauses”

  • Why: This breaks one or more observable capabilities at the defmodule, def, defp boundary while allowing the happy path to look correct.
  • Fix: Run default-values-conflict-across-clauses-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “Private normalization leaks into callers”

  • Why: This breaks one or more observable capabilities at the defmodule, def, defp boundary while allowing the happy path to look correct.
  • Fix: Run private-normalization-leaks-into-callers-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “Nested module names imply an ownership relationship that does not exist”

  • Why: This breaks one or more observable capabilities at the defmodule, def, defp boundary while allowing the happy path to look correct.
  • Fix: Run nested-module-names-imply-an-ownership-relationship-that-does-not-exist-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • The public API is small and namespaced.
  • Defaults are declared once in a function head.
  • Unsupported units fail through an explicit clause.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 14: Report Formatter Extension Kit

Official topic: alias, require, import, and use — Elixir v1.20.2

Source file: lib/elixir/pages/getting-started/alias-require-and-import.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Module Composition / Lexical Scope
  • Software or Tool: alias, require, import, use
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build several report modules that demonstrate scoped aliases and imports, one required guard macro, and a documented opt-in use extension with an expansion inventory.

Why it teaches this official topic: The artifact makes lexical directive scope, aliases, macro requirements, imports and use extension points observable through one bounded build instead of isolated syntax examples.

Scope boundary: Demonstrate directive scope and one tiny extension point; do not build a macro DSL.

Core challenges you will face:

  • lexical directive scope -> identify the accepted case, the counterexample, and the observable result at the alias, require, import, use boundary
  • aliases -> identify the accepted case, the counterexample, and the observable result at the alias, require, import, use boundary
  • macro requirements -> identify the accepted case, the counterexample, and the observable result at the alias, require, import, use boundary
  • imports and use extension points -> identify the accepted case, the counterexample, and the observable result at the alias, require, import, use boundary

Real World Outcome

Build several report modules that demonstrate scoped aliases and imports, one required guard macro, and a documented opt-in use extension with an expansion inventory. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Every directive has a minimal lexical scope.
  • Imported names are explicitly allow-listed.
  • The use extension documents injected imports, aliases, and callbacks.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=getting-started/alias-require-and-import.md
ARTIFACT=report-formatter-extension-kit
CHECK 01 PASS :: Every directive has a minimal lexical scope
CHECK 02 PASS :: Imported names are explicitly allow-listed
CHECK 03 PASS :: The use extension documents injected imports, aliases, and callbacks
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“What does each module directive change in the caller, and how can that change remain visible to reviewers?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. lexical directive scope
    • Working rule: Make “lexical directive scope” an explicit rule at the alias, require, import, use boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "lexical-directive-scope-positive", focus: "lexical directive scope", mode: :positive, expect: :observable} and %{id: "lexical-directive-scope-negative", focus: "lexical directive scope", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: alias, require, import, and use
  2. aliases
    • Working rule: Make “aliases” an explicit rule at the alias, require, import, use boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "aliases-positive", focus: "aliases", mode: :positive, expect: :observable} and %{id: "aliases-negative", focus: "aliases", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: alias, require, import, and use
  3. macro requirements
    • Working rule: Make “macro requirements” an explicit rule at the alias, require, import, use boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "macro-requirements-positive", focus: "macro requirements", mode: :positive, expect: :observable} and %{id: "macro-requirements-negative", focus: "macro requirements", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: alias, require, import, and use
  4. imports and use extension points
    • Working rule: Make “imports and use extension points” an explicit rule at the alias, require, import, use boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "imports-and-use-extension-points-positive", focus: "imports and use extension points", mode: :positive, expect: :observable} and %{id: "imports-and-use-extension-points-negative", focus: "imports and use extension points", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: alias, require, import, and use

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “lexical directive scope” be enforced?
    • Which check catches the risk “A broad import creates an ambiguous call”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Every directive has a minimal lexical scope”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “alias, require, import, and use”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: lexical directive scope, aliases, macro requirements, imports and use extension points. Then trace the named counterexample “A broad import creates an ambiguous call” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose lexical directive scope, and what does this project prove about it?”
  2. “What interaction between the concept ‘aliases’ and the concept ‘lexical directive scope’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘A broad import creates an ambiguous call’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with lexical-directive-scope-positive and a-broad-import-creates-an-ambiguous-call-counterexample. The first must make the concept “lexical directive scope” observable and establish “Every directive has a minimal lexical scope”; the second must reproduce “A broad import creates an ambiguous call”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for getting-started/alias-require-and-import.md
evaluate "lexical directive scope" through alias, require, import, use
compare actual evidence with "Every directive has a minimal lexical scope"
run negative fixture for "A broad import creates an ambiguous call"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
alias, require, import, and use Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
lexical directive scope Elixir in Action, 3rd Edition Ch. 2-4
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement lexical-directive-scope-positive and prove “Every directive has a minimal lexical scope”.
  3. Topic coverage: add fixtures for aliases, macro requirements, imports and use extension points.
  4. Failure campaign: reproduce each named risk: “A broad import creates an ambiguous call”; “A macro is invoked without require”; “Use injects surprising behavior into the caller”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute lexical-directive-scope-positive, aliases-positive, macro-requirements-positive, imports-and-use-extension-points-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute lexical-directive-scope-negative, aliases-negative, macro-requirements-negative, imports-and-use-extension-points-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute a-broad-import-creates-an-ambiguous-call-counterexample, a-macro-is-invoked-without-require-counterexample, use-injects-surprising-behavior-into-the-caller-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real alias, require, import, use boundary from a clean shell.
  • Mutation check: violate “Every directive has a minimal lexical scope” and prove the suite reports fixture lexical-directive-scope-positive as failed.
  • Regression corpus: retain the risks “A broad import creates an ambiguous call”; “A macro is invoked without require”; “Use injects surprising behavior into the caller” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “A broad import creates an ambiguous call”

  • Why: This breaks one or more observable capabilities at the alias, require, import, use boundary while allowing the happy path to look correct.
  • Fix: Run a-broad-import-creates-an-ambiguous-call-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “A macro is invoked without require”

  • Why: This breaks one or more observable capabilities at the alias, require, import, use boundary while allowing the happy path to look correct.
  • Fix: Run a-macro-is-invoked-without-require-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “Use injects surprising behavior into the caller”

  • Why: This breaks one or more observable capabilities at the alias, require, import, use boundary while allowing the happy path to look correct.
  • Fix: Run use-injects-surprising-behavior-into-the-caller-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • Every directive has a minimal lexical scope.
  • Imported names are explicitly allow-listed.
  • The use extension documents injected imports, aliases, and callbacks.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 15: Convention-Complete Key-Value API

Official topic: Naming conventions — Elixir v1.20.2

Source file: lib/elixir/pages/references/naming-conventions.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Public API Semantics
  • Software or Tool: ExUnit and ExDoc
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build and certify a tiny key-value API whose get, fetch, fetch!, compare, size, length, predicate, guard, and bang names imply behavior that the tests enforce.

Why it teaches this official topic: The artifact makes casing conventions, bang and predicate suffixes, get fetch and fetch! contracts, size versus length complexity, comparison function names observable through one bounded build instead of isolated syntax examples.

Scope boundary: Keep the domain deliberately tiny so naming, not storage or parsing, remains the lesson.

Core challenges you will face:

  • casing conventions -> identify the accepted case, the counterexample, and the observable result at the ExUnit and ExDoc boundary
  • bang and predicate suffixes -> identify the accepted case, the counterexample, and the observable result at the ExUnit and ExDoc boundary
  • get fetch and fetch! contracts -> identify the accepted case, the counterexample, and the observable result at the ExUnit and ExDoc boundary
  • size versus length complexity -> identify the accepted case, the counterexample, and the observable result at the ExUnit and ExDoc boundary
  • comparison function names -> identify the accepted case, the counterexample, and the observable result at the ExUnit and ExDoc boundary

Real World Outcome

Build and certify a tiny key-value API whose get, fetch, fetch!, compare, size, length, predicate, guard, and bang names imply behavior that the tests enforce. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Modules and aliases use CamelCase while functions and variables use snake_case.
  • Predicate names end in a question mark, is-prefix names identify guard-compatible predicates, and bang names signal raising semantics.
  • Get returns a value or default, fetch returns a tagged result, and fetch! raises for a missing key.
  • Size names constant-time retrieval while length names work proportional to the collection.
  • Compare returns :lt, :eq, or :gt instead of hiding ordering behind a boolean.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=references/naming-conventions.md
ARTIFACT=convention-complete-key-value-api
CHECK 01 PASS :: Modules and aliases use CamelCase while functions and variables use snake_case
CHECK 02 PASS :: Predicate names end in a question mark, is-prefix names identify guard-compatible predicates, and bang names signal raising semantics
CHECK 03 PASS :: Get returns a value or default, fetch returns a tagged result, and fetch! raises for a missing key
CHECK 04 PASS :: Size names constant-time retrieval while length names work proportional to the collection
CHECK 05 PASS :: Compare returns :lt, :eq, or :gt instead of hiding ordering behind a boolean
FAILURE_CASES=5 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“Can callers infer failure, return shape, and complexity from the public function names alone?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. casing conventions
    • Working rule: Make “casing conventions” an explicit rule at the ExUnit and ExDoc boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "casing-conventions-positive", focus: "casing conventions", mode: :positive, expect: :observable} and %{id: "casing-conventions-negative", focus: "casing conventions", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Naming conventions
  2. bang and predicate suffixes
    • Working rule: Make “bang and predicate suffixes” an explicit rule at the ExUnit and ExDoc boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "bang-and-predicate-suffixes-positive", focus: "bang and predicate suffixes", mode: :positive, expect: :observable} and %{id: "bang-and-predicate-suffixes-negative", focus: "bang and predicate suffixes", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Naming conventions
  3. get fetch and fetch! contracts
    • Working rule: Make “get fetch and fetch! contracts” an explicit rule at the ExUnit and ExDoc boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "get-fetch-and-fetch-contracts-positive", focus: "get fetch and fetch! contracts", mode: :positive, expect: :observable} and %{id: "get-fetch-and-fetch-contracts-negative", focus: "get fetch and fetch! contracts", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Naming conventions
  4. size versus length complexity
    • Working rule: Make “size versus length complexity” an explicit rule at the ExUnit and ExDoc boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "size-versus-length-complexity-positive", focus: "size versus length complexity", mode: :positive, expect: :observable} and %{id: "size-versus-length-complexity-negative", focus: "size versus length complexity", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Naming conventions
  5. comparison function names
    • Working rule: Make “comparison function names” an explicit rule at the ExUnit and ExDoc boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "comparison-function-names-positive", focus: "comparison function names", mode: :positive, expect: :observable} and %{id: "comparison-function-names-negative", focus: "comparison function names", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Naming conventions

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “casing conventions” be enforced?
    • Which check catches the risk “A public function uses camelCase or a module uses snake_case”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Modules and aliases use CamelCase while functions and variables use snake_case”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Naming conventions”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: casing conventions, bang and predicate suffixes, get fetch and fetch! contracts, size versus length complexity, comparison function names. Then trace the named counterexample “A public function uses camelCase or a module uses snake_case” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose casing conventions, and what does this project prove about it?”
  2. “What interaction between the concept ‘bang and predicate suffixes’ and the concept ‘casing conventions’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘A public function uses camelCase or a module uses snake_case’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with casing-conventions-positive and a-public-function-uses-camelcase-or-a-module-uses-snake-case-counterexample. The first must make the concept “casing conventions” observable and establish “Modules and aliases use CamelCase while functions and variables use snake_case”; the second must reproduce “A public function uses camelCase or a module uses snake_case”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for references/naming-conventions.md
evaluate "casing conventions" through ExUnit and ExDoc
compare actual evidence with "Modules and aliases use CamelCase while functions and variables use snake_case"
run negative fixture for "A public function uses camelCase or a module uses snake_case"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Naming conventions Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
casing conventions Elixir in Action, 3rd Edition Ch. 2-4
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement casing-conventions-positive and prove “Modules and aliases use CamelCase while functions and variables use snake_case”.
  3. Topic coverage: add fixtures for bang and predicate suffixes, get fetch and fetch! contracts, size versus length complexity, comparison function names.
  4. Failure campaign: reproduce each named risk: “A public function uses camelCase or a module uses snake_case”; “A bang API suppresses a semantic failure or an is-prefix predicate cannot be called in a guard”; “Get raises for a missing key or fetch discards its tagged absence”; “A linear traversal is named size or a constant-time field is named length”; “Compare returns true or false and loses three-way ordering”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute casing-conventions-positive, bang-and-predicate-suffixes-positive, get-fetch-and-fetch-contracts-positive, size-versus-length-complexity-positive, comparison-function-names-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute casing-conventions-negative, bang-and-predicate-suffixes-negative, get-fetch-and-fetch-contracts-negative, size-versus-length-complexity-negative, comparison-function-names-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute a-public-function-uses-camelcase-or-a-module-uses-snake-case-counterexample, a-bang-api-suppresses-a-semantic-failure-or-an-is-prefix-predicate-cannot-be-called-in-a-guard-counterexample, get-raises-for-a-missing-key-or-fetch-discards-its-tagged-absence-counterexample, a-linear-traversal-is-named-size-or-a-constant-time-field-is-named-length-counterexample, compare-returns-true-or-false-and-loses-three-way-ordering-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real ExUnit and ExDoc boundary from a clean shell.
  • Mutation check: violate “Modules and aliases use CamelCase while functions and variables use snake_case” and prove the suite reports fixture casing-conventions-positive as failed.
  • Regression corpus: retain the risks “A public function uses camelCase or a module uses snake_case”; “A bang API suppresses a semantic failure or an is-prefix predicate cannot be called in a guard”; “Get raises for a missing key or fetch discards its tagged absence”; “A linear traversal is named size or a constant-time field is named length”; “Compare returns true or false and loses three-way ordering” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “A public function uses camelCase or a module uses snake_case”

  • Why: This breaks one or more observable capabilities at the ExUnit and ExDoc boundary while allowing the happy path to look correct.
  • Fix: Run a-public-function-uses-camelcase-or-a-module-uses-snake-case-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “A bang API suppresses a semantic failure or an is-prefix predicate cannot be called in a guard”

  • Why: This breaks one or more observable capabilities at the ExUnit and ExDoc boundary while allowing the happy path to look correct.
  • Fix: Run a-bang-api-suppresses-a-semantic-failure-or-an-is-prefix-predicate-cannot-be-called-in-a-guard-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “Get raises for a missing key or fetch discards its tagged absence”

  • Why: This breaks one or more observable capabilities at the ExUnit and ExDoc boundary while allowing the happy path to look correct.
  • Fix: Run get-raises-for-a-missing-key-or-fetch-discards-its-tagged-absence-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 4: “A linear traversal is named size or a constant-time field is named length”

  • Why: This breaks one or more observable capabilities at the ExUnit and ExDoc boundary while allowing the happy path to look correct.
  • Fix: Run a-linear-traversal-is-named-size-or-a-constant-time-field-is-named-length-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 5: “Compare returns true or false and loses three-way ordering”

  • Why: This breaks one or more observable capabilities at the ExUnit and ExDoc boundary while allowing the happy path to look correct.
  • Fix: Run compare-returns-true-or-false-and-loses-three-way-ordering-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • Modules and aliases use CamelCase while functions and variables use snake_case.
  • Predicate names end in a question mark, is-prefix names identify guard-compatible predicates, and bang names signal raising semantics.
  • Get returns a value or default, fetch returns a tagged result, and fetch! raises for a missing key.
  • Size names constant-time retrieval while length names work proportional to the collection.
  • Compare returns :lt, :eq, or :gt instead of hiding ordering behind a boolean.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 16: Compile-Time Compliance Rule Catalog

Official topic: Module attributes — Elixir v1.20.2

Source file: lib/elixir/pages/getting-started/module-attributes.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Compile-Time Metadata
  • Software or Tool: module attributes and ExDoc
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build a small immutable country-rule catalog that uses accumulated annotations, compile-time constants, documentation/spec metadata, and one behaviour-backed validation API.

Why it teaches this official topic: The artifact makes documentation attributes, temporary compile-time storage, compile-time constants, accumulated annotations observable through one bounded build instead of isolated syntax examples.

Scope boundary: Stay declarative and small; exclude AST generation, policy DSLs, and general static analysis.

Core challenges you will face:

  • documentation attributes -> identify the accepted case, the counterexample, and the observable result at the module attributes and ExDoc boundary
  • temporary compile-time storage -> identify the accepted case, the counterexample, and the observable result at the module attributes and ExDoc boundary
  • compile-time constants -> identify the accepted case, the counterexample, and the observable result at the module attributes and ExDoc boundary
  • accumulated annotations -> identify the accepted case, the counterexample, and the observable result at the module attributes and ExDoc boundary

Real World Outcome

Build a small immutable country-rule catalog that uses accumulated annotations, compile-time constants, documentation/spec metadata, and one behaviour-backed validation API. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Rule annotations accumulate in declared order.
  • Constants are read once and exposed through functions.
  • Docs, specs, and behaviour metadata remain inspectable.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=getting-started/module-attributes.md
ARTIFACT=compile-time-compliance-rule-catalog
CHECK 01 PASS :: Rule annotations accumulate in declared order
CHECK 02 PASS :: Constants are read once and exposed through functions
CHECK 03 PASS :: Docs, specs, and behaviour metadata remain inspectable
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“When is a module attribute metadata, temporary compiler state, or a constant, and why does the distinction matter?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. documentation attributes
    • Working rule: Make “documentation attributes” an explicit rule at the module attributes and ExDoc boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "documentation-attributes-positive", focus: "documentation attributes", mode: :positive, expect: :observable} and %{id: "documentation-attributes-negative", focus: "documentation attributes", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Module attributes
  2. temporary compile-time storage
    • Working rule: Make “temporary compile-time storage” an explicit rule at the module attributes and ExDoc boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "temporary-compile-time-storage-positive", focus: "temporary compile-time storage", mode: :positive, expect: :observable} and %{id: "temporary-compile-time-storage-negative", focus: "temporary compile-time storage", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Module attributes
  3. compile-time constants
    • Working rule: Make “compile-time constants” an explicit rule at the module attributes and ExDoc boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "compile-time-constants-positive", focus: "compile-time constants", mode: :positive, expect: :observable} and %{id: "compile-time-constants-negative", focus: "compile-time constants", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Module attributes
  4. accumulated annotations
    • Working rule: Make “accumulated annotations” an explicit rule at the module attributes and ExDoc boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "accumulated-annotations-positive", focus: "accumulated annotations", mode: :positive, expect: :observable} and %{id: "accumulated-annotations-negative", focus: "accumulated annotations", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Module attributes

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “documentation attributes” be enforced?
    • Which check catches the risk “An attribute is read repeatedly and snapshots stale values”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Rule annotations accumulate in declared order”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Module attributes”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: documentation attributes, temporary compile-time storage, compile-time constants, accumulated annotations. Then trace the named counterexample “An attribute is read repeatedly and snapshots stale values” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose documentation attributes, and what does this project prove about it?”
  2. “What interaction between the concept ‘temporary compile-time storage’ and the concept ‘documentation attributes’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘An attribute is read repeatedly and snapshots stale values’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with documentation-attributes-positive and an-attribute-is-read-repeatedly-and-snapshots-stale-values-counterexample. The first must make the concept “documentation attributes” observable and establish “Rule annotations accumulate in declared order”; the second must reproduce “An attribute is read repeatedly and snapshots stale values”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for getting-started/module-attributes.md
evaluate "documentation attributes" through module attributes and ExDoc
compare actual evidence with "Rule annotations accumulate in declared order"
run negative fixture for "An attribute is read repeatedly and snapshots stale values"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Module attributes Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
documentation attributes Elixir in Action, 3rd Edition Ch. 2-4
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement documentation-attributes-positive and prove “Rule annotations accumulate in declared order”.
  3. Topic coverage: add fixtures for temporary compile-time storage, compile-time constants, accumulated annotations.
  4. Failure campaign: reproduce each named risk: “An attribute is read repeatedly and snapshots stale values”; “A large constant is inlined unexpectedly”; “Runtime-changing data is frozen at compile time”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute documentation-attributes-positive, temporary-compile-time-storage-positive, compile-time-constants-positive, accumulated-annotations-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute documentation-attributes-negative, temporary-compile-time-storage-negative, compile-time-constants-negative, accumulated-annotations-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute an-attribute-is-read-repeatedly-and-snapshots-stale-values-counterexample, a-large-constant-is-inlined-unexpectedly-counterexample, runtime-changing-data-is-frozen-at-compile-time-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real module attributes and ExDoc boundary from a clean shell.
  • Mutation check: violate “Rule annotations accumulate in declared order” and prove the suite reports fixture documentation-attributes-positive as failed.
  • Regression corpus: retain the risks “An attribute is read repeatedly and snapshots stale values”; “A large constant is inlined unexpectedly”; “Runtime-changing data is frozen at compile time” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “An attribute is read repeatedly and snapshots stale values”

  • Why: This breaks one or more observable capabilities at the module attributes and ExDoc boundary while allowing the happy path to look correct.
  • Fix: Run an-attribute-is-read-repeatedly-and-snapshots-stale-values-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “A large constant is inlined unexpectedly”

  • Why: This breaks one or more observable capabilities at the module attributes and ExDoc boundary while allowing the happy path to look correct.
  • Fix: Run a-large-constant-is-inlined-unexpectedly-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “Runtime-changing data is frozen at compile time”

  • Why: This breaks one or more observable capabilities at the module attributes and ExDoc boundary while allowing the happy path to look correct.
  • Fix: Run runtime-changing-data-is-frozen-at-compile-time-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • Rule annotations accumulate in declared order.
  • Constants are read once and exposed through functions.
  • Docs, specs, and behaviour metadata remain inspectable.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 17: Parcel Manifest Domain Model

Official topic: Structs — Elixir v1.20.2

Source file: lib/elixir/pages/getting-started/structs.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Domain Modeling / Data Integrity
  • Software or Tool: defstruct and struct!
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build pure parcel, address, and dimensions structs with required keys, defaults, safe construction, immutable updates, structural pattern checks, and malformed-field fixtures.

Why it teaches this official topic: The artifact makes struct definition, required keys and defaults, safe updates, struct and map relationship observable through one bounded build instead of isolated syntax examples.

Scope boundary: Keep all data in memory; do not introduce Ecto, Ash, CRUD, or persistence.

Core challenges you will face:

  • struct definition -> identify the accepted case, the counterexample, and the observable result at the defstruct and struct! boundary
  • required keys and defaults -> identify the accepted case, the counterexample, and the observable result at the defstruct and struct! boundary
  • safe updates -> identify the accepted case, the counterexample, and the observable result at the defstruct and struct! boundary
  • struct and map relationship -> identify the accepted case, the counterexample, and the observable result at the defstruct and struct! boundary

Real World Outcome

Build pure parcel, address, and dimensions structs with required keys, defaults, safe construction, immutable updates, structural pattern checks, and malformed-field fixtures. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Unknown keys fail at construction.
  • Updates preserve the struct type and unrelated fields.
  • Pattern checks distinguish each domain struct.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=getting-started/structs.md
ARTIFACT=parcel-manifest-domain-model
CHECK 01 PASS :: Unknown keys fail at construction
CHECK 02 PASS :: Updates preserve the struct type and unrelated fields
CHECK 03 PASS :: Pattern checks distinguish each domain struct
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“What integrity does an Elixir struct provide, and which domain validation remains your responsibility?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. struct definition
    • Working rule: Make “struct definition” an explicit rule at the defstruct and struct! boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "struct-definition-positive", focus: "struct definition", mode: :positive, expect: :observable} and %{id: "struct-definition-negative", focus: "struct definition", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Structs
  2. required keys and defaults
    • Working rule: Make “required keys and defaults” an explicit rule at the defstruct and struct! boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "required-keys-and-defaults-positive", focus: "required keys and defaults", mode: :positive, expect: :observable} and %{id: "required-keys-and-defaults-negative", focus: "required keys and defaults", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Structs
  3. safe updates
    • Working rule: Make “safe updates” an explicit rule at the defstruct and struct! boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "safe-updates-positive", focus: "safe updates", mode: :positive, expect: :observable} and %{id: "safe-updates-negative", focus: "safe updates", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Structs
  4. struct and map relationship
    • Working rule: Make “struct and map relationship” an explicit rule at the defstruct and struct! boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "struct-and-map-relationship-positive", focus: "struct and map relationship", mode: :positive, expect: :observable} and %{id: "struct-and-map-relationship-negative", focus: "struct and map relationship", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Structs

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “struct definition” be enforced?
    • Which check catches the risk “Enforce-keys is mistaken for runtime validation”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Unknown keys fail at construction”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Structs”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: struct definition, required keys and defaults, safe updates, struct and map relationship. Then trace the named counterexample “Enforce-keys is mistaken for runtime validation” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose struct definition, and what does this project prove about it?”
  2. “What interaction between the concept ‘required keys and defaults’ and the concept ‘struct definition’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘Enforce-keys is mistaken for runtime validation’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with struct-definition-positive and enforce-keys-is-mistaken-for-runtime-validation-counterexample. The first must make the concept “struct definition” observable and establish “Unknown keys fail at construction”; the second must reproduce “Enforce-keys is mistaken for runtime validation”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for getting-started/structs.md
evaluate "struct definition" through defstruct and struct!
compare actual evidence with "Unknown keys fail at construction"
run negative fixture for "Enforce-keys is mistaken for runtime validation"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Structs Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
struct definition Elixir in Action, 3rd Edition Ch. 2-4
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement struct-definition-positive and prove “Unknown keys fail at construction”.
  3. Topic coverage: add fixtures for required keys and defaults, safe updates, struct and map relationship.
  4. Failure campaign: reproduce each named risk: “Enforce-keys is mistaken for runtime validation”; “Map update syntax loses a struct invariant”; “A protocol is assumed to apply because the struct is backed by a map”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute struct-definition-positive, required-keys-and-defaults-positive, safe-updates-positive, struct-and-map-relationship-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute struct-definition-negative, required-keys-and-defaults-negative, safe-updates-negative, struct-and-map-relationship-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute enforce-keys-is-mistaken-for-runtime-validation-counterexample, map-update-syntax-loses-a-struct-invariant-counterexample, a-protocol-is-assumed-to-apply-because-the-struct-is-backed-by-a-map-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real defstruct and struct! boundary from a clean shell.
  • Mutation check: violate “Unknown keys fail at construction” and prove the suite reports fixture struct-definition-positive as failed.
  • Regression corpus: retain the risks “Enforce-keys is mistaken for runtime validation”; “Map update syntax loses a struct invariant”; “A protocol is assumed to apply because the struct is backed by a map” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “Enforce-keys is mistaken for runtime validation”

  • Why: This breaks one or more observable capabilities at the defstruct and struct! boundary while allowing the happy path to look correct.
  • Fix: Run enforce-keys-is-mistaken-for-runtime-validation-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “Map update syntax loses a struct invariant”

  • Why: This breaks one or more observable capabilities at the defstruct and struct! boundary while allowing the happy path to look correct.
  • Fix: Run map-update-syntax-loses-a-struct-invariant-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “A protocol is assumed to apply because the struct is backed by a map”

  • Why: This breaks one or more observable capabilities at the defstruct and struct! boundary while allowing the happy path to look correct.
  • Fix: Run a-protocol-is-assumed-to-apply-because-the-struct-is-backed-by-a-map-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • Unknown keys fail at construction.
  • Updates preserve the struct type and unrelated fields.
  • Pattern checks distinguish each domain struct.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 18: Nested Bill-of-Materials Flattener

Official topic: Recursion — Elixir v1.20.2

Source file: lib/elixir/pages/getting-started/recursion.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Algorithms / Immutable Traversal
  • Software or Tool: recursion and tail calls
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build a recursive component-tree flattener that totals quantities with an accumulator, has explicit termination and malformed-node clauses, and compares its result with a reduce-based oracle.

Why it teaches this official topic: The artifact makes recursive looping, termination clauses, head-tail traversal, accumulators and tail calls observable through one bounded build instead of isolated syntax examples.

Scope boundary: Recursion itself must be the primary implementation; Enum may serve only as an oracle.

Core challenges you will face:

  • recursive looping -> identify the accepted case, the counterexample, and the observable result at the recursion and tail calls boundary
  • termination clauses -> identify the accepted case, the counterexample, and the observable result at the recursion and tail calls boundary
  • head-tail traversal -> identify the accepted case, the counterexample, and the observable result at the recursion and tail calls boundary
  • accumulators and tail calls -> identify the accepted case, the counterexample, and the observable result at the recursion and tail calls boundary

Real World Outcome

Build a recursive component-tree flattener that totals quantities with an accumulator, has explicit termination and malformed-node clauses, and compares its result with a reduce-based oracle. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Every finite fixture reaches an explicit base clause.
  • Quantities are accumulated without rebuilding the result quadratically.
  • Malformed recursive nodes return a tagged failure.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=getting-started/recursion.md
ARTIFACT=nested-bill-of-materials-flattener
CHECK 01 PASS :: Every finite fixture reaches an explicit base clause
CHECK 02 PASS :: Quantities are accumulated without rebuilding the result quadratically
CHECK 03 PASS :: Malformed recursive nodes return a tagged failure
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“How does immutable recursion replace a loop while preserving termination, order, and bounded stack usage?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. recursive looping
    • Working rule: Make “recursive looping” an explicit rule at the recursion and tail calls boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "recursive-looping-positive", focus: "recursive looping", mode: :positive, expect: :observable} and %{id: "recursive-looping-negative", focus: "recursive looping", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Recursion
  2. termination clauses
    • Working rule: Make “termination clauses” an explicit rule at the recursion and tail calls boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "termination-clauses-positive", focus: "termination clauses", mode: :positive, expect: :observable} and %{id: "termination-clauses-negative", focus: "termination clauses", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Recursion
  3. head-tail traversal
    • Working rule: Make “head-tail traversal” an explicit rule at the recursion and tail calls boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "head-tail-traversal-positive", focus: "head-tail traversal", mode: :positive, expect: :observable} and %{id: "head-tail-traversal-negative", focus: "head-tail traversal", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Recursion
  4. accumulators and tail calls
    • Working rule: Make “accumulators and tail calls” an explicit rule at the recursion and tail calls boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "accumulators-and-tail-calls-positive", focus: "accumulators and tail calls", mode: :positive, expect: :observable} and %{id: "accumulators-and-tail-calls-negative", focus: "accumulators and tail calls", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Recursion

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “recursive looping” be enforced?
    • Which check catches the risk “A missing base case causes non-termination”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Every finite fixture reaches an explicit base clause”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Recursion”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: recursive looping, termination clauses, head-tail traversal, accumulators and tail calls. Then trace the named counterexample “A missing base case causes non-termination” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose recursive looping, and what does this project prove about it?”
  2. “What interaction between the concept ‘termination clauses’ and the concept ‘recursive looping’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘A missing base case causes non-termination’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with recursive-looping-positive and a-missing-base-case-causes-non-termination-counterexample. The first must make the concept “recursive looping” observable and establish “Every finite fixture reaches an explicit base clause”; the second must reproduce “A missing base case causes non-termination”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for getting-started/recursion.md
evaluate "recursive looping" through recursion and tail calls
compare actual evidence with "Every finite fixture reaches an explicit base clause"
run negative fixture for "A missing base case causes non-termination"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Recursion Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
recursive looping Elixir in Action, 3rd Edition Ch. 2-4
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement recursive-looping-positive and prove “Every finite fixture reaches an explicit base clause”.
  3. Topic coverage: add fixtures for termination clauses, head-tail traversal, accumulators and tail calls.
  4. Failure campaign: reproduce each named risk: “A missing base case causes non-termination”; “Work after the recursive call defeats tail position”; “The accumulator reverses order without correction”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute recursive-looping-positive, termination-clauses-positive, head-tail-traversal-positive, accumulators-and-tail-calls-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute recursive-looping-negative, termination-clauses-negative, head-tail-traversal-negative, accumulators-and-tail-calls-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute a-missing-base-case-causes-non-termination-counterexample, work-after-the-recursive-call-defeats-tail-position-counterexample, the-accumulator-reverses-order-without-correction-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real recursion and tail calls boundary from a clean shell.
  • Mutation check: violate “Every finite fixture reaches an explicit base clause” and prove the suite reports fixture recursive-looping-positive as failed.
  • Regression corpus: retain the risks “A missing base case causes non-termination”; “Work after the recursive call defeats tail position”; “The accumulator reverses order without correction” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “A missing base case causes non-termination”

  • Why: This breaks one or more observable capabilities at the recursion and tail calls boundary while allowing the happy path to look correct.
  • Fix: Run a-missing-base-case-causes-non-termination-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “Work after the recursive call defeats tail position”

  • Why: This breaks one or more observable capabilities at the recursion and tail calls boundary while allowing the happy path to look correct.
  • Fix: Run work-after-the-recursive-call-defeats-tail-position-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “The accumulator reverses order without correction”

  • Why: This breaks one or more observable capabilities at the recursion and tail calls boundary while allowing the happy path to look correct.
  • Fix: Run the-accumulator-reverses-order-without-correction-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • Every finite fixture reaches an explicit base clause.
  • Quantities are accumulated without rebuilding the result quadratically.
  • Malformed recursive nodes return a tagged failure.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 19: Erlang Calculator REPL

Source: ERL-P1. Build a calculator shell that pattern matches operands and reports bad input without crashing.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Erlang
  • Alternative Programming Languages: Prolog, Haskell, Standard ML
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Language Syntax / REPL Design
  • Software or Tool: Erlang Shell (erl)
  • Main Book: “Learn You Some Erlang for Great Good!” by Fred Hébert

What you will build: Build a calculator shell that pattern matches operands and reports bad input without crashing.

Why it teaches the BEAM ecosystem: It makes you prove that recursive command handling and tagged results stay predictable across malformed expressions.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Build a calculator shell that pattern matches operands and reports bad input without crashing.

Build an interactive Erlang calculator that tokenizes and parses expressions with precedence, returns tagged errors for malformed input, and keeps the tail-recursive command loop alive after expected failures.

$ rebar3 shell
1> calc:start().
calc> 3 + 4 * 2
11
calc> 7 / 0
{error,division_by_zero}
calc> 2 +
{error,{unexpected_end,column=4}}
calc> quit
bye

The Core Question You Are Answering

“How can Erlang Calculator REPL deliver its observable outcome while proving that recursive command handling and tagged results stay predictable across malformed expressions.”

Concepts You Must Understand First

  • Tokenizing input (splitting "3+4*2" into [{num,3},{op,add},{num,4},{op,mul},{num,2}]) → maps to Erlang string/list handling
  • Recursive descent parsing with precedence → maps to pattern matching on lists
  • REPL loop (read -> eval -> print -> loop) → maps to tail recursion
  • Error handling (invalid input shouldn’t crash) → maps to Erlang try/catch

Questions to Guide Your Design

  1. Which input and output contracts must remain stable across refactoring?
  2. Where should validation happen, and how will expected failures be represented?
  3. Which component owns mutable state or external effects, and what happens when it dies?
  4. What independent evidence proves this mastery condition: recursive command handling and tagged results stay predictable across malformed expressions.

Thinking Exercise

Draw Erlang Calculator REPL as an input → decision/state → effect → evidence pipeline.

Mark every failure boundary, retry boundary, and durable state transition. Then inject one failure at each boundary and predict the observable result before implementing it.

The Interview Questions They Will Ask

  1. “What is the hardest invariant in Erlang Calculator REPL, and where is it enforced?”
  2. “Which parts should be pure transformations and which require BEAM processes?”
  3. “How does the design behave under malformed input, process failure, or retry?”
  4. “What test or runtime evidence proves: recursive command handling and tagged results stay predictable across malformed expressions.”

Hints in Layers

Your REPL module will look something like: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Note the Erlang conventions:

  • Module name matches filename (calc.erl)
  • Export list explicitly declares public functions
  • io:get_line/1 returns string with newline
  • io:format/2 uses ~p for pretty-print, ~n for newline
  • The . ends the function, ; would separate clauses, , separates expressions

Hint 1: Starting Point Implement the narrowest happy path for: Build a calculator shell that pattern matches operands and reports bad input without crashing.

Hint 2: Next Level Separate parsing, validation, and transition decisions from effects so each can be tested directly.

Hint 3: Technical Details Represent expected failures as tagged outcomes and keep state ownership explicit; write only structural pseudocode before implementation.

Hint 4: Tools and Debugging Inject one failure at a time, correlate it with bounded telemetry, and save a deterministic transcript as evidence.

Books That Will Help

  • Main Book: “Learn You Some Erlang for Great Good!” by Fred Hébert

Implementation Milestones

  1. REPL loops and prints → You understand basic Erlang I/O
  2. Tokenizer handles all operators → You understand list processing in Erlang
  3. Precedence works correctly → You’ve mastered recursive pattern matching

Testing Strategy

  • Unit checks: pure parsing, validation, transition, and formatting decisions.
  • Integration checks: the real process, database, socket, notebook, or framework boundary.
  • Failure checks: malformed input plus at least one crash, timeout, duplicate, overload, or partition scenario.
  • Acceptance check: independently demonstrate that recursive command handling and tagged results stay predictable across malformed expressions.
  • Avoid arbitrary sleeps; use messages, monitors, deterministic clocks, fixtures, and deadlines where applicable.

Common Pitfalls and Debugging

Problem 1: Happy-path output looks correct but failures disappear

  • Why: validation, effects, and reporting share one opaque step.
  • Fix: preserve tagged errors and source identity through every stage.
  • Quick test: inject one invalid record or failed dependency and verify an explicit result.

Problem 2: Tests merely repeat the implementation

  • Why: assertions reuse the same transformation or state assumptions.
  • Fix: check external invariants, golden fixtures, and observable failure behavior.
  • Quick test: introduce a deliberate ordering or boundary bug and confirm the test fails.

Definition of Done

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • recursive command handling and tagged results stay predictable across malformed expressions.

Project 20: Memory-Bounded Access-Log Window Processor

Official topic: Enumerables and Streams — Elixir v1.20.2

Source file: lib/elixir/pages/getting-started/enumerable-and-streams.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Lazy Data Processing
  • Software or Tool: Enum, Stream, Stream.resource
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build eager and lazy pipelines over a large synthetic access log, including a Stream.resource input, bounded windows, cleanup evidence, and measured intermediate-allocation differences.

Why it teaches this official topic: The artifact makes Enumerable protocol, eager versus lazy evaluation, pipe composition, resource-backed streams observable through one bounded build instead of isolated syntax examples.

Scope boundary: Use core Enum and Stream only; exclude Explorer, Parquet, production tracing, and distributed pipelines.

Core challenges you will face:

  • Enumerable protocol -> identify the accepted case, the counterexample, and the observable result at the Enum, Stream, Stream.resource boundary
  • eager versus lazy evaluation -> identify the accepted case, the counterexample, and the observable result at the Enum, Stream, Stream.resource boundary
  • pipe composition -> identify the accepted case, the counterexample, and the observable result at the Enum, Stream, Stream.resource boundary
  • resource-backed streams -> identify the accepted case, the counterexample, and the observable result at the Enum, Stream, Stream.resource boundary

Real World Outcome

Build eager and lazy pipelines over a large synthetic access log, including a Stream.resource input, bounded windows, cleanup evidence, and measured intermediate-allocation differences. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Eager and lazy pipelines produce identical final summaries.
  • The lazy path stays within a declared memory envelope.
  • Resource cleanup runs on completion and early halt.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=getting-started/enumerable-and-streams.md
ARTIFACT=memory-bounded-access-log-window-processor
CHECK 01 PASS :: Eager and lazy pipelines produce identical final summaries
CHECK 02 PASS :: The lazy path stays within a declared memory envelope
CHECK 03 PASS :: Resource cleanup runs on completion and early halt
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“When does laziness change resource usage without changing the functional result?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. Enumerable protocol
    • Working rule: Make “Enumerable protocol” an explicit rule at the Enum, Stream, Stream.resource boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "enumerable-protocol-positive", focus: "Enumerable protocol", mode: :positive, expect: :observable} and %{id: "enumerable-protocol-negative", focus: "Enumerable protocol", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Enumerables and Streams
  2. eager versus lazy evaluation
    • Working rule: Make “eager versus lazy evaluation” an explicit rule at the Enum, Stream, Stream.resource boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "eager-versus-lazy-evaluation-positive", focus: "eager versus lazy evaluation", mode: :positive, expect: :observable} and %{id: "eager-versus-lazy-evaluation-negative", focus: "eager versus lazy evaluation", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Enumerables and Streams
  3. pipe composition
    • Working rule: Make “pipe composition” an explicit rule at the Enum, Stream, Stream.resource boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "pipe-composition-positive", focus: "pipe composition", mode: :positive, expect: :observable} and %{id: "pipe-composition-negative", focus: "pipe composition", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Enumerables and Streams
  4. resource-backed streams
    • Working rule: Make “resource-backed streams” an explicit rule at the Enum, Stream, Stream.resource boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "resource-backed-streams-positive", focus: "resource-backed streams", mode: :positive, expect: :observable} and %{id: "resource-backed-streams-negative", focus: "resource-backed streams", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Enumerables and Streams

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “Enumerable protocol” be enforced?
    • Which check catches the risk “A stream is built but eagerly consumed too early”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Eager and lazy pipelines produce identical final summaries”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Enumerables and Streams”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: Enumerable protocol, eager versus lazy evaluation, pipe composition, resource-backed streams. Then trace the named counterexample “A stream is built but eagerly consumed too early” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose Enumerable protocol, and what does this project prove about it?”
  2. “What interaction between the concept ‘eager versus lazy evaluation’ and the concept ‘Enumerable protocol’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘A stream is built but eagerly consumed too early’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with enumerable-protocol-positive and a-stream-is-built-but-eagerly-consumed-too-early-counterexample. The first must make the concept “Enumerable protocol” observable and establish “Eager and lazy pipelines produce identical final summaries”; the second must reproduce “A stream is built but eagerly consumed too early”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for getting-started/enumerable-and-streams.md
evaluate "Enumerable protocol" through Enum, Stream, Stream.resource
compare actual evidence with "Eager and lazy pipelines produce identical final summaries"
run negative fixture for "A stream is built but eagerly consumed too early"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Enumerables and Streams Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
Enumerable protocol Elixir in Action, 3rd Edition Ch. 2-4
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement enumerable-protocol-positive and prove “Eager and lazy pipelines produce identical final summaries”.
  3. Topic coverage: add fixtures for eager versus lazy evaluation, pipe composition, resource-backed streams.
  4. Failure campaign: reproduce each named risk: “A stream is built but eagerly consumed too early”; “An infinite stream lacks a take boundary”; “Resource cleanup is skipped on failure”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute enumerable-protocol-positive, eager-versus-lazy-evaluation-positive, pipe-composition-positive, resource-backed-streams-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute enumerable-protocol-negative, eager-versus-lazy-evaluation-negative, pipe-composition-negative, resource-backed-streams-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute a-stream-is-built-but-eagerly-consumed-too-early-counterexample, an-infinite-stream-lacks-a-take-boundary-counterexample, resource-cleanup-is-skipped-on-failure-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real Enum, Stream, Stream.resource boundary from a clean shell.
  • Mutation check: violate “Eager and lazy pipelines produce identical final summaries” and prove the suite reports fixture enumerable-protocol-positive as failed.
  • Regression corpus: retain the risks “A stream is built but eagerly consumed too early”; “An infinite stream lacks a take boundary”; “Resource cleanup is skipped on failure” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “A stream is built but eagerly consumed too early”

  • Why: This breaks one or more observable capabilities at the Enum, Stream, Stream.resource boundary while allowing the happy path to look correct.
  • Fix: Run a-stream-is-built-but-eagerly-consumed-too-early-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “An infinite stream lacks a take boundary”

  • Why: This breaks one or more observable capabilities at the Enum, Stream, Stream.resource boundary while allowing the happy path to look correct.
  • Fix: Run an-infinite-stream-lacks-a-take-boundary-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “Resource cleanup is skipped on failure”

  • Why: This breaks one or more observable capabilities at the Enum, Stream, Stream.resource boundary while allowing the happy path to look correct.
  • Fix: Run resource-cleanup-is-skipped-on-failure-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • Eager and lazy pipelines produce identical final summaries.
  • The lazy path stays within a declared memory envelope.
  • Resource cleanup runs on completion and early halt.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 21: Inventory Analytics Command Workbench

Official topic: Enum cheatsheet — Elixir v1.20.2

Source file: lib/elixir/pages/cheatsheets/enum-cheat.cheatmd

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Collection Algorithms
  • Software or Tool: Enum and Collectable
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build an in-memory inventory workbench supporting predicates, filtering, ranking, grouping, deduplication, pagination, sampling, batching, chunking, zipping, and early-halting reconciliation.

Why it teaches this official topic: The artifact makes selection and transformation, accumulation and early halt, grouping and ordering, chunking and zipping observable through one bounded build instead of isolated syntax examples.

Scope boundary: Use one in-memory fixture and core Enum; exclude databases, Explorer, and financial reconciliation.

Core challenges you will face:

  • selection and transformation -> identify the accepted case, the counterexample, and the observable result at the Enum and Collectable boundary
  • accumulation and early halt -> identify the accepted case, the counterexample, and the observable result at the Enum and Collectable boundary
  • grouping and ordering -> identify the accepted case, the counterexample, and the observable result at the Enum and Collectable boundary
  • chunking and zipping -> identify the accepted case, the counterexample, and the observable result at the Enum and Collectable boundary

Real World Outcome

Build an in-memory inventory workbench supporting predicates, filtering, ranking, grouping, deduplication, pagination, sampling, batching, chunking, zipping, and early-halting reconciliation. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Every command documents empty-enumerable behavior.
  • Index-dependent operations reject unordered inputs.
  • Random operations accept a deterministic test seed.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=cheatsheets/enum-cheat.cheatmd
ARTIFACT=inventory-analytics-command-workbench
CHECK 01 PASS :: Every command documents empty-enumerable behavior
CHECK 02 PASS :: Index-dependent operations reject unordered inputs
CHECK 03 PASS :: Random operations accept a deterministic test seed
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“How do you select the Enum operation whose semantics, cost, and empty-input behavior match the problem?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. selection and transformation
    • Working rule: Make “selection and transformation” an explicit rule at the Enum and Collectable boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "selection-and-transformation-positive", focus: "selection and transformation", mode: :positive, expect: :observable} and %{id: "selection-and-transformation-negative", focus: "selection and transformation", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Enum cheatsheet
  2. accumulation and early halt
    • Working rule: Make “accumulation and early halt” an explicit rule at the Enum and Collectable boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "accumulation-and-early-halt-positive", focus: "accumulation and early halt", mode: :positive, expect: :observable} and %{id: "accumulation-and-early-halt-negative", focus: "accumulation and early halt", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Enum cheatsheet
  3. grouping and ordering
    • Working rule: Make “grouping and ordering” an explicit rule at the Enum and Collectable boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "grouping-and-ordering-positive", focus: "grouping and ordering", mode: :positive, expect: :observable} and %{id: "grouping-and-ordering-negative", focus: "grouping and ordering", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Enum cheatsheet
  4. chunking and zipping
    • Working rule: Make “chunking and zipping” an explicit rule at the Enum and Collectable boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "chunking-and-zipping-positive", focus: "chunking and zipping", mode: :positive, expect: :observable} and %{id: "chunking-and-zipping-negative", focus: "chunking and zipping", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Enum cheatsheet

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “selection and transformation” be enforced?
    • Which check catches the risk “All? on an empty collection is expected to be false”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Every command documents empty-enumerable behavior”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Enum cheatsheet”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: selection and transformation, accumulation and early halt, grouping and ordering, chunking and zipping. Then trace the named counterexample “All? on an empty collection is expected to be false” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose selection and transformation, and what does this project prove about it?”
  2. “What interaction between the concept ‘accumulation and early halt’ and the concept ‘selection and transformation’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘All? on an empty collection is expected to be false’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with selection-and-transformation-positive and all-on-an-empty-collection-is-expected-to-be-false-counterexample. The first must make the concept “selection and transformation” observable and establish “Every command documents empty-enumerable behavior”; the second must reproduce “All? on an empty collection is expected to be false”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for cheatsheets/enum-cheat.cheatmd
evaluate "selection and transformation" through Enum and Collectable
compare actual evidence with "Every command documents empty-enumerable behavior"
run negative fixture for "All? on an empty collection is expected to be false"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Enum cheatsheet Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
selection and transformation Elixir in Action, 3rd Edition Ch. 2-4
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement selection-and-transformation-positive and prove “Every command documents empty-enumerable behavior”.
  3. Topic coverage: add fixtures for accumulation and early halt, grouping and ordering, chunking and zipping.
  4. Failure campaign: reproduce each named risk: “All? on an empty collection is expected to be false”; “At is used as if list access were constant time”; “Uniq and dedup are treated as interchangeable”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute selection-and-transformation-positive, accumulation-and-early-halt-positive, grouping-and-ordering-positive, chunking-and-zipping-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute selection-and-transformation-negative, accumulation-and-early-halt-negative, grouping-and-ordering-negative, chunking-and-zipping-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute all-on-an-empty-collection-is-expected-to-be-false-counterexample, at-is-used-as-if-list-access-were-constant-time-counterexample, uniq-and-dedup-are-treated-as-interchangeable-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real Enum and Collectable boundary from a clean shell.
  • Mutation check: violate “Every command documents empty-enumerable behavior” and prove the suite reports fixture selection-and-transformation-positive as failed.
  • Regression corpus: retain the risks “All? on an empty collection is expected to be false”; “At is used as if list access were constant time”; “Uniq and dedup are treated as interchangeable” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “All? on an empty collection is expected to be false”

  • Why: This breaks one or more observable capabilities at the Enum and Collectable boundary while allowing the happy path to look correct.
  • Fix: Run all-on-an-empty-collection-is-expected-to-be-false-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “At is used as if list access were constant time”

  • Why: This breaks one or more observable capabilities at the Enum and Collectable boundary while allowing the happy path to look correct.
  • Fix: Run at-is-used-as-if-list-access-were-constant-time-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “Uniq and dedup are treated as interchangeable”

  • Why: This breaks one or more observable capabilities at the Enum and Collectable boundary while allowing the happy path to look correct.
  • Fix: Run uniq-and-dedup-are-treated-as-interchangeable-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • Every command documents empty-enumerable behavior.
  • Index-dependent operations reject unordered inputs.
  • Random operations accept a deterministic test seed.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 22: RGB Binary Thumbnail Transcoder

Official topic: Comprehensions — Elixir v1.20.2

Source file: lib/elixir/pages/getting-started/comprehensions.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Binary Transformation / Collectables
  • Software or Tool: for comprehensions and bitstrings
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build a pure packed-RGB transcoder using bitstring generators, filters, into targets, reduce accumulation, uniqueness policy, and deterministic binary plus frequency-map outputs.

Why it teaches this official topic: The artifact makes generators and filters, multiple generators, bitstring generators, into and reduce options observable through one bounded build instead of isolated syntax examples.

Scope boundary: Remain a pure byte transformation; exclude image ML and NIF acceleration.

Core challenges you will face:

  • generators and filters -> identify the accepted case, the counterexample, and the observable result at the for comprehensions and bitstrings boundary
  • multiple generators -> identify the accepted case, the counterexample, and the observable result at the for comprehensions and bitstrings boundary
  • bitstring generators -> identify the accepted case, the counterexample, and the observable result at the for comprehensions and bitstrings boundary
  • into and reduce options -> identify the accepted case, the counterexample, and the observable result at the for comprehensions and bitstrings boundary

Real World Outcome

Build a pure packed-RGB transcoder using bitstring generators, filters, into targets, reduce accumulation, uniqueness policy, and deterministic binary plus frequency-map outputs. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Every complete RGB triple is transformed exactly once.
  • Truncated trailing bytes are reported.
  • Binary output and color frequencies agree.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=getting-started/comprehensions.md
ARTIFACT=rgb-binary-thumbnail-transcoder
CHECK 01 PASS :: Every complete RGB triple is transformed exactly once
CHECK 02 PASS :: Truncated trailing bytes are reported
CHECK 03 PASS :: Binary output and color frequencies agree
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“When does a comprehension express generation and filtering more clearly than nested Enum pipelines?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. generators and filters
    • Working rule: Make “generators and filters” an explicit rule at the for comprehensions and bitstrings boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "generators-and-filters-positive", focus: "generators and filters", mode: :positive, expect: :observable} and %{id: "generators-and-filters-negative", focus: "generators and filters", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Comprehensions
  2. multiple generators
    • Working rule: Make “multiple generators” an explicit rule at the for comprehensions and bitstrings boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "multiple-generators-positive", focus: "multiple generators", mode: :positive, expect: :observable} and %{id: "multiple-generators-negative", focus: "multiple generators", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Comprehensions
  3. bitstring generators
    • Working rule: Make “bitstring generators” an explicit rule at the for comprehensions and bitstrings boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "bitstring-generators-positive", focus: "bitstring generators", mode: :positive, expect: :observable} and %{id: "bitstring-generators-negative", focus: "bitstring generators", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Comprehensions
  4. into and reduce options
    • Working rule: Make “into and reduce options” an explicit rule at the for comprehensions and bitstrings boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "into-and-reduce-options-positive", focus: "into and reduce options", mode: :positive, expect: :observable} and %{id: "into-and-reduce-options-negative", focus: "into and reduce options", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Comprehensions

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “generators and filters” be enforced?
    • Which check catches the risk “A generator pattern silently drops malformed items”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Every complete RGB triple is transformed exactly once”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Comprehensions”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: generators and filters, multiple generators, bitstring generators, into and reduce options. Then trace the named counterexample “A generator pattern silently drops malformed items” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose generators and filters, and what does this project prove about it?”
  2. “What interaction between the concept ‘multiple generators’ and the concept ‘generators and filters’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘A generator pattern silently drops malformed items’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with generators-and-filters-positive and a-generator-pattern-silently-drops-malformed-items-counterexample. The first must make the concept “generators and filters” observable and establish “Every complete RGB triple is transformed exactly once”; the second must reproduce “A generator pattern silently drops malformed items”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for getting-started/comprehensions.md
evaluate "generators and filters" through for comprehensions and bitstrings
compare actual evidence with "Every complete RGB triple is transformed exactly once"
run negative fixture for "A generator pattern silently drops malformed items"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Comprehensions Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
generators and filters Elixir in Action, 3rd Edition Ch. 2-4
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement generators-and-filters-positive and prove “Every complete RGB triple is transformed exactly once”.
  3. Topic coverage: add fixtures for multiple generators, bitstring generators, into and reduce options.
  4. Failure campaign: reproduce each named risk: “A generator pattern silently drops malformed items”; “A Cartesian product grows unexpectedly”; “The into target uses an incompatible Collectable”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute generators-and-filters-positive, multiple-generators-positive, bitstring-generators-positive, into-and-reduce-options-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute generators-and-filters-negative, multiple-generators-negative, bitstring-generators-negative, into-and-reduce-options-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute a-generator-pattern-silently-drops-malformed-items-counterexample, a-cartesian-product-grows-unexpectedly-counterexample, the-into-target-uses-an-incompatible-collectable-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real for comprehensions and bitstrings boundary from a clean shell.
  • Mutation check: violate “Every complete RGB triple is transformed exactly once” and prove the suite reports fixture generators-and-filters-positive as failed.
  • Regression corpus: retain the risks “A generator pattern silently drops malformed items”; “A Cartesian product grows unexpectedly”; “The into target uses an incompatible Collectable” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “A generator pattern silently drops malformed items”

  • Why: This breaks one or more observable capabilities at the for comprehensions and bitstrings boundary while allowing the happy path to look correct.
  • Fix: Run a-generator-pattern-silently-drops-malformed-items-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “A Cartesian product grows unexpectedly”

  • Why: This breaks one or more observable capabilities at the for comprehensions and bitstrings boundary while allowing the happy path to look correct.
  • Fix: Run a-cartesian-product-grows-unexpectedly-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “The into target uses an incompatible Collectable”

  • Why: This breaks one or more observable capabilities at the for comprehensions and bitstrings boundary while allowing the happy path to look correct.
  • Fix: Run the-into-target-uses-an-incompatible-collectable-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • Every complete RGB triple is transformed exactly once.
  • Truncated trailing bytes are reported.
  • Binary output and color frequencies agree.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 23: Multi-Carrier Label Renderer

Official topic: Protocols — Elixir v1.20.2

Source file: lib/elixir/pages/getting-started/protocols.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Open Polymorphism
  • Software or Tool: defprotocol and defimpl
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build a label-rendering protocol implemented by several carrier structs, with unsupported-type evidence, Any fallback and derivation experiments, plus custom String.Chars and Inspect behavior.

Why it teaches this official topic: The artifact makes protocol dispatch, struct implementations, Any fallback, deriving and built-in protocols observable through one bounded build instead of isolated syntax examples.

Scope boundary: Use data-driven protocol dispatch, not behaviour plugins, API adapters, or processes.

Core challenges you will face:

  • protocol dispatch -> identify the accepted case, the counterexample, and the observable result at the defprotocol and defimpl boundary
  • struct implementations -> identify the accepted case, the counterexample, and the observable result at the defprotocol and defimpl boundary
  • Any fallback -> identify the accepted case, the counterexample, and the observable result at the defprotocol and defimpl boundary
  • deriving and built-in protocols -> identify the accepted case, the counterexample, and the observable result at the defprotocol and defimpl boundary

Real World Outcome

Build a label-rendering protocol implemented by several carrier structs, with unsupported-type evidence, Any fallback and derivation experiments, plus custom String.Chars and Inspect behavior. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Every supported carrier dispatches by data type.
  • Unsupported values fail with the documented protocol error.
  • Fallback and derive choices are compared explicitly.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=getting-started/protocols.md
ARTIFACT=multi-carrier-label-renderer
CHECK 01 PASS :: Every supported carrier dispatches by data type
CHECK 02 PASS :: Unsupported values fail with the documented protocol error
CHECK 03 PASS :: Fallback and derive choices are compared explicitly
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“How do protocols extend behavior for data types you do not own without centralizing every case?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. protocol dispatch
    • Working rule: Make “protocol dispatch” an explicit rule at the defprotocol and defimpl boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "protocol-dispatch-positive", focus: "protocol dispatch", mode: :positive, expect: :observable} and %{id: "protocol-dispatch-negative", focus: "protocol dispatch", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Protocols
  2. struct implementations
    • Working rule: Make “struct implementations” an explicit rule at the defprotocol and defimpl boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "struct-implementations-positive", focus: "struct implementations", mode: :positive, expect: :observable} and %{id: "struct-implementations-negative", focus: "struct implementations", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Protocols
  3. Any fallback
    • Working rule: Make “Any fallback” an explicit rule at the defprotocol and defimpl boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "any-fallback-positive", focus: "Any fallback", mode: :positive, expect: :observable} and %{id: "any-fallback-negative", focus: "Any fallback", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Protocols
  4. deriving and built-in protocols
    • Working rule: Make “deriving and built-in protocols” an explicit rule at the defprotocol and defimpl boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "deriving-and-built-in-protocols-positive", focus: "deriving and built-in protocols", mode: :positive, expect: :observable} and %{id: "deriving-and-built-in-protocols-negative", focus: "deriving and built-in protocols", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Protocols

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “protocol dispatch” be enforced?
    • Which check catches the risk “A protocol is used for multi-argument dispatch”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Every supported carrier dispatches by data type”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Protocols”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: protocol dispatch, struct implementations, Any fallback, deriving and built-in protocols. Then trace the named counterexample “A protocol is used for multi-argument dispatch” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose protocol dispatch, and what does this project prove about it?”
  2. “What interaction between the concept ‘struct implementations’ and the concept ‘protocol dispatch’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘A protocol is used for multi-argument dispatch’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with protocol-dispatch-positive and a-protocol-is-used-for-multi-argument-dispatch-counterexample. The first must make the concept “protocol dispatch” observable and establish “Every supported carrier dispatches by data type”; the second must reproduce “A protocol is used for multi-argument dispatch”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for getting-started/protocols.md
evaluate "protocol dispatch" through defprotocol and defimpl
compare actual evidence with "Every supported carrier dispatches by data type"
run negative fixture for "A protocol is used for multi-argument dispatch"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Protocols Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
protocol dispatch Elixir in Action, 3rd Edition Ch. 2-4
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement protocol-dispatch-positive and prove “Every supported carrier dispatches by data type”.
  3. Topic coverage: add fixtures for struct implementations, Any fallback, deriving and built-in protocols.
  4. Failure campaign: reproduce each named risk: “A protocol is used for multi-argument dispatch”; “Any fallback hides a missing implementation”; “Consolidation timing invalidates a dynamic implementation assumption”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute protocol-dispatch-positive, struct-implementations-positive, any-fallback-positive, deriving-and-built-in-protocols-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute protocol-dispatch-negative, struct-implementations-negative, any-fallback-negative, deriving-and-built-in-protocols-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute a-protocol-is-used-for-multi-argument-dispatch-counterexample, any-fallback-hides-a-missing-implementation-counterexample, consolidation-timing-invalidates-a-dynamic-implementation-assumption-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real defprotocol and defimpl boundary from a clean shell.
  • Mutation check: violate “Every supported carrier dispatches by data type” and prove the suite reports fixture protocol-dispatch-positive as failed.
  • Regression corpus: retain the risks “A protocol is used for multi-argument dispatch”; “Any fallback hides a missing implementation”; “Consolidation timing invalidates a dynamic implementation assumption” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “A protocol is used for multi-argument dispatch”

  • Why: This breaks one or more observable capabilities at the defprotocol and defimpl boundary while allowing the happy path to look correct.
  • Fix: Run a-protocol-is-used-for-multi-argument-dispatch-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “Any fallback hides a missing implementation”

  • Why: This breaks one or more observable capabilities at the defprotocol and defimpl boundary while allowing the happy path to look correct.
  • Fix: Run any-fallback-hides-a-missing-implementation-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “Consolidation timing invalidates a dynamic implementation assumption”

  • Why: This breaks one or more observable capabilities at the defprotocol and defimpl boundary while allowing the happy path to look correct.
  • Fix: Run consolidation-timing-invalidates-a-dynamic-implementation-assumption-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • Every supported carrier dispatches by data type.
  • Unsupported values fail with the documented protocol error.
  • Fallback and derive choices are compared explicitly.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 24: Validated Log-Query Sigil Toolkit

Official topic: Sigils — Elixir v1.20.2

Source file: lib/elixir/pages/getting-started/sigils.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Language Literals / Parsing
  • Software or Tool: sigils and Regex
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build a custom textual log-query sigil that produces a validated search structure alongside regex, word-list, interpolation, escaping, delimiter, modifier, and calendar-sigil fixtures.

Why it teaches this official topic: The artifact makes built-in sigils, interpolation and escaping, delimiter and modifier behavior, custom sigil functions observable through one bounded build instead of isolated syntax examples.

Scope boundary: Restrict the project to textual literal parsing; do not grow it into a macro policy DSL.

Core challenges you will face:

  • built-in sigils -> identify the accepted case, the counterexample, and the observable result at the sigils and Regex boundary
  • interpolation and escaping -> identify the accepted case, the counterexample, and the observable result at the sigils and Regex boundary
  • delimiter and modifier behavior -> identify the accepted case, the counterexample, and the observable result at the sigils and Regex boundary
  • custom sigil functions -> identify the accepted case, the counterexample, and the observable result at the sigils and Regex boundary

Real World Outcome

Build a custom textual log-query sigil that produces a validated search structure alongside regex, word-list, interpolation, escaping, delimiter, modifier, and calendar-sigil fixtures. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Lowercase and uppercase interpolation differences are proven.
  • Invalid custom query syntax fails at its declared boundary.
  • Modifiers have a finite documented vocabulary.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=getting-started/sigils.md
ARTIFACT=validated-log-query-sigil-toolkit
CHECK 01 PASS :: Lowercase and uppercase interpolation differences are proven
CHECK 02 PASS :: Invalid custom query syntax fails at its declared boundary
CHECK 03 PASS :: Modifiers have a finite documented vocabulary
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“When does a sigil make a literal safer and clearer, and when does it merely hide a parser?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. built-in sigils
    • Working rule: Make “built-in sigils” an explicit rule at the sigils and Regex boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "built-in-sigils-positive", focus: "built-in sigils", mode: :positive, expect: :observable} and %{id: "built-in-sigils-negative", focus: "built-in sigils", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Sigils
  2. interpolation and escaping
    • Working rule: Make “interpolation and escaping” an explicit rule at the sigils and Regex boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "interpolation-and-escaping-positive", focus: "interpolation and escaping", mode: :positive, expect: :observable} and %{id: "interpolation-and-escaping-negative", focus: "interpolation and escaping", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Sigils
  3. delimiter and modifier behavior
    • Working rule: Make “delimiter and modifier behavior” an explicit rule at the sigils and Regex boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "delimiter-and-modifier-behavior-positive", focus: "delimiter and modifier behavior", mode: :positive, expect: :observable} and %{id: "delimiter-and-modifier-behavior-negative", focus: "delimiter and modifier behavior", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Sigils
  4. custom sigil functions
    • Working rule: Make “custom sigil functions” an explicit rule at the sigils and Regex boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "custom-sigil-functions-positive", focus: "custom sigil functions", mode: :positive, expect: :observable} and %{id: "custom-sigil-functions-negative", focus: "custom sigil functions", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Sigils

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “built-in sigils” be enforced?
    • Which check catches the risk “A custom sigil performs excessive compile-time work”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Lowercase and uppercase interpolation differences are proven”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Sigils”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: built-in sigils, interpolation and escaping, delimiter and modifier behavior, custom sigil functions. Then trace the named counterexample “A custom sigil performs excessive compile-time work” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose built-in sigils, and what does this project prove about it?”
  2. “What interaction between the concept ‘interpolation and escaping’ and the concept ‘built-in sigils’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘A custom sigil performs excessive compile-time work’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with built-in-sigils-positive and a-custom-sigil-performs-excessive-compile-time-work-counterexample. The first must make the concept “built-in sigils” observable and establish “Lowercase and uppercase interpolation differences are proven”; the second must reproduce “A custom sigil performs excessive compile-time work”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for getting-started/sigils.md
evaluate "built-in sigils" through sigils and Regex
compare actual evidence with "Lowercase and uppercase interpolation differences are proven"
run negative fixture for "A custom sigil performs excessive compile-time work"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Sigils Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
built-in sigils Elixir in Action, 3rd Edition Ch. 2-4
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement built-in-sigils-positive and prove “Lowercase and uppercase interpolation differences are proven”.
  3. Topic coverage: add fixtures for interpolation and escaping, delimiter and modifier behavior, custom sigil functions.
  4. Failure campaign: reproduce each named risk: “A custom sigil performs excessive compile-time work”; “Escaping differs across delimiters”; “User input is interpolated into a regex unsafely”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute built-in-sigils-positive, interpolation-and-escaping-positive, delimiter-and-modifier-behavior-positive, custom-sigil-functions-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute built-in-sigils-negative, interpolation-and-escaping-negative, delimiter-and-modifier-behavior-negative, custom-sigil-functions-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute a-custom-sigil-performs-excessive-compile-time-work-counterexample, escaping-differs-across-delimiters-counterexample, user-input-is-interpolated-into-a-regex-unsafely-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real sigils and Regex boundary from a clean shell.
  • Mutation check: violate “Lowercase and uppercase interpolation differences are proven” and prove the suite reports fixture built-in-sigils-positive as failed.
  • Regression corpus: retain the risks “A custom sigil performs excessive compile-time work”; “Escaping differs across delimiters”; “User input is interpolated into a regex unsafely” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “A custom sigil performs excessive compile-time work”

  • Why: This breaks one or more observable capabilities at the sigils and Regex boundary while allowing the happy path to look correct.
  • Fix: Run a-custom-sigil-performs-excessive-compile-time-work-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “Escaping differs across delimiters”

  • Why: This breaks one or more observable capabilities at the sigils and Regex boundary while allowing the happy path to look correct.
  • Fix: Run escaping-differs-across-delimiters-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “User input is interpolated into a regex unsafely”

  • Why: This breaks one or more observable capabilities at the sigils and Regex boundary while allowing the happy path to look correct.
  • Fix: Run user-input-is-interpolated-into-a-regex-unsafely-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • Lowercase and uppercase interpolation differences are proven.
  • Invalid custom query syntax fails at its declared boundary.
  • Modifiers have a finite documented vocabulary.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 25: Partner API Failure Boundary Simulator

Official topic: try, catch, and rescue — Elixir v1.20.2

Source file: lib/elixir/pages/getting-started/try-catch-and-rescue.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Failure Semantics
  • Software or Tool: exceptions, throw/catch, exits
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build a simulated adapter that returns tagged expected failures, raises unexpected defects, preserves stacktraces on reraise, observes exits, and records after-cleanup behavior.

Why it teaches this official topic: The artifact makes exceptions and rescue, tagged results and bang APIs, throw and catch, exits and after cleanup observable through one bounded build instead of isolated syntax examples.

Scope boundary: Use a deterministic simulation; exclude real webhooks, retries, jobs, and durable workflows.

Core challenges you will face:

  • exceptions and rescue -> identify the accepted case, the counterexample, and the observable result at the exceptions, throw/catch, exits boundary
  • tagged results and bang APIs -> identify the accepted case, the counterexample, and the observable result at the exceptions, throw/catch, exits boundary
  • throw and catch -> identify the accepted case, the counterexample, and the observable result at the exceptions, throw/catch, exits boundary
  • exits and after cleanup -> identify the accepted case, the counterexample, and the observable result at the exceptions, throw/catch, exits boundary

Real World Outcome

Build a simulated adapter that returns tagged expected failures, raises unexpected defects, preserves stacktraces on reraise, observes exits, and records after-cleanup behavior. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Expected partner failures remain tagged data.
  • Unexpected defects retain their original stacktrace.
  • Cleanup evidence is recorded for every path.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=getting-started/try-catch-and-rescue.md
ARTIFACT=partner-api-failure-boundary-simulator
CHECK 01 PASS :: Expected partner failures remain tagged data
CHECK 02 PASS :: Unexpected defects retain their original stacktrace
CHECK 03 PASS :: Cleanup evidence is recorded for every path
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“Which failures belong in return values, which should raise, and which process exits should propagate?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. exceptions and rescue
    • Working rule: Make “exceptions and rescue” an explicit rule at the exceptions, throw/catch, exits boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "exceptions-and-rescue-positive", focus: "exceptions and rescue", mode: :positive, expect: :observable} and %{id: "exceptions-and-rescue-negative", focus: "exceptions and rescue", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: try, catch, and rescue
  2. tagged results and bang APIs
    • Working rule: Make “tagged results and bang APIs” an explicit rule at the exceptions, throw/catch, exits boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "tagged-results-and-bang-apis-positive", focus: "tagged results and bang APIs", mode: :positive, expect: :observable} and %{id: "tagged-results-and-bang-apis-negative", focus: "tagged results and bang APIs", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: try, catch, and rescue
  3. throw and catch
    • Working rule: Make “throw and catch” an explicit rule at the exceptions, throw/catch, exits boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "throw-and-catch-positive", focus: "throw and catch", mode: :positive, expect: :observable} and %{id: "throw-and-catch-negative", focus: "throw and catch", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: try, catch, and rescue
  4. exits and after cleanup
    • Working rule: Make “exits and after cleanup” an explicit rule at the exceptions, throw/catch, exits boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "exits-and-after-cleanup-positive", focus: "exits and after cleanup", mode: :positive, expect: :observable} and %{id: "exits-and-after-cleanup-negative", focus: "exits and after cleanup", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: try, catch, and rescue

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “exceptions and rescue” be enforced?
    • Which check catches the risk “Rescue catches an overly broad exception”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Expected partner failures remain tagged data”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “try, catch, and rescue”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: exceptions and rescue, tagged results and bang APIs, throw and catch, exits and after cleanup. Then trace the named counterexample “Rescue catches an overly broad exception” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose exceptions and rescue, and what does this project prove about it?”
  2. “What interaction between the concept ‘tagged results and bang APIs’ and the concept ‘exceptions and rescue’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘Rescue catches an overly broad exception’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with exceptions-and-rescue-positive and rescue-catches-an-overly-broad-exception-counterexample. The first must make the concept “exceptions and rescue” observable and establish “Expected partner failures remain tagged data”; the second must reproduce “Rescue catches an overly broad exception”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for getting-started/try-catch-and-rescue.md
evaluate "exceptions and rescue" through exceptions, throw/catch, exits
compare actual evidence with "Expected partner failures remain tagged data"
run negative fixture for "Rescue catches an overly broad exception"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
try, catch, and rescue Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
exceptions and rescue Elixir in Action, 3rd Edition Ch. 2-4
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement exceptions-and-rescue-positive and prove “Expected partner failures remain tagged data”.
  3. Topic coverage: add fixtures for tagged results and bang APIs, throw and catch, exits and after cleanup.
  4. Failure campaign: reproduce each named risk: “Rescue catches an overly broad exception”; “Throw is used for ordinary API control flow”; “After is assumed to guarantee successful cleanup”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute exceptions-and-rescue-positive, tagged-results-and-bang-apis-positive, throw-and-catch-positive, exits-and-after-cleanup-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute exceptions-and-rescue-negative, tagged-results-and-bang-apis-negative, throw-and-catch-negative, exits-and-after-cleanup-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute rescue-catches-an-overly-broad-exception-counterexample, throw-is-used-for-ordinary-api-control-flow-counterexample, after-is-assumed-to-guarantee-successful-cleanup-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real exceptions, throw/catch, exits boundary from a clean shell.
  • Mutation check: violate “Expected partner failures remain tagged data” and prove the suite reports fixture exceptions-and-rescue-positive as failed.
  • Regression corpus: retain the risks “Rescue catches an overly broad exception”; “Throw is used for ordinary API control flow”; “After is assumed to guarantee successful cleanup” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “Rescue catches an overly broad exception”

  • Why: This breaks one or more observable capabilities at the exceptions, throw/catch, exits boundary while allowing the happy path to look correct.
  • Fix: Run rescue-catches-an-overly-broad-exception-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “Throw is used for ordinary API control flow”

  • Why: This breaks one or more observable capabilities at the exceptions, throw/catch, exits boundary while allowing the happy path to look correct.
  • Fix: Run throw-is-used-for-ordinary-api-control-flow-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “After is assumed to guarantee successful cleanup”

  • Why: This breaks one or more observable capabilities at the exceptions, throw/catch, exits boundary while allowing the happy path to look correct.
  • Fix: Run after-is-assumed-to-guarantee-successful-cleanup-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • Expected partner failures remain tagged data.
  • Unexpected defects retain their original stacktrace.
  • Cleanup evidence is recorded for every path.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 26: Streaming CSV Export Writer with Iodata

Official topic: IO and the file system — Elixir v1.20.2

Source file: lib/elixir/pages/getting-started/io-and-the-file-system.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: File I/O / Efficient Output
  • Software or Tool: IO, File, Path, iodata
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build one iodata-producing export path that writes a large report to stdout, stderr, and files, uses portable Path operations, and exposes tagged versus bang file failures.

Why it teaches this official topic: The artifact makes IO devices, File result contracts, portable paths, iodata and chardata observable through one bounded build instead of isolated syntax examples.

Scope boundary: Teach device abstraction and output efficiency; exclude configuration parsing and duplicate-file workflows.

Core challenges you will face:

  • IO devices -> identify the accepted case, the counterexample, and the observable result at the IO, File, Path, iodata boundary
  • File result contracts -> identify the accepted case, the counterexample, and the observable result at the IO, File, Path, iodata boundary
  • portable paths -> identify the accepted case, the counterexample, and the observable result at the IO, File, Path, iodata boundary
  • iodata and chardata -> identify the accepted case, the counterexample, and the observable result at the IO, File, Path, iodata boundary

Real World Outcome

Build one iodata-producing export path that writes a large report to stdout, stderr, and files, uses portable Path operations, and exposes tagged versus bang file failures. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • The same iodata producer targets multiple devices.
  • Paths remain portable and confined to a fixture root.
  • Tagged and bang APIs are exercised deliberately.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=getting-started/io-and-the-file-system.md
ARTIFACT=streaming-csv-export-writer-with-iodata
CHECK 01 PASS :: The same iodata producer targets multiple devices
CHECK 02 PASS :: Paths remain portable and confined to a fixture root
CHECK 03 PASS :: Tagged and bang APIs are exercised deliberately
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“How can one output representation serve terminals and files efficiently while keeping filesystem failure explicit?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. IO devices
    • Working rule: Make “IO devices” an explicit rule at the IO, File, Path, iodata boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "io-devices-positive", focus: "IO devices", mode: :positive, expect: :observable} and %{id: "io-devices-negative", focus: "IO devices", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: IO and the file system
  2. File result contracts
    • Working rule: Make “File result contracts” an explicit rule at the IO, File, Path, iodata boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "file-result-contracts-positive", focus: "File result contracts", mode: :positive, expect: :observable} and %{id: "file-result-contracts-negative", focus: "File result contracts", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: IO and the file system
  3. portable paths
    • Working rule: Make “portable paths” an explicit rule at the IO, File, Path, iodata boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "portable-paths-positive", focus: "portable paths", mode: :positive, expect: :observable} and %{id: "portable-paths-negative", focus: "portable paths", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: IO and the file system
  4. iodata and chardata
    • Working rule: Make “iodata and chardata” an explicit rule at the IO, File, Path, iodata boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "iodata-and-chardata-positive", focus: "iodata and chardata", mode: :positive, expect: :observable} and %{id: "iodata-and-chardata-negative", focus: "iodata and chardata", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: IO and the file system

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “IO devices” be enforced?
    • Which check catches the risk “String concatenation causes unnecessary copying”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “The same iodata producer targets multiple devices”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “IO and the file system”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: IO devices, File result contracts, portable paths, iodata and chardata. Then trace the named counterexample “String concatenation causes unnecessary copying” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose IO devices, and what does this project prove about it?”
  2. “What interaction between the concept ‘File result contracts’ and the concept ‘IO devices’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘String concatenation causes unnecessary copying’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with io-devices-positive and string-concatenation-causes-unnecessary-copying-counterexample. The first must make the concept “IO devices” observable and establish “The same iodata producer targets multiple devices”; the second must reproduce “String concatenation causes unnecessary copying”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for getting-started/io-and-the-file-system.md
evaluate "IO devices" through IO, File, Path, iodata
compare actual evidence with "The same iodata producer targets multiple devices"
run negative fixture for "String concatenation causes unnecessary copying"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
IO and the file system Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
IO devices Elixir in Action, 3rd Edition Ch. 2-4
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement io-devices-positive and prove “The same iodata producer targets multiple devices”.
  3. Topic coverage: add fixtures for File result contracts, portable paths, iodata and chardata.
  4. Failure campaign: reproduce each named risk: “String concatenation causes unnecessary copying”; “A device is confused with its owning process”; “A relative path escapes the fixture root”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute io-devices-positive, file-result-contracts-positive, portable-paths-positive, iodata-and-chardata-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute io-devices-negative, file-result-contracts-negative, portable-paths-negative, iodata-and-chardata-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute string-concatenation-causes-unnecessary-copying-counterexample, a-device-is-confused-with-its-owning-process-counterexample, a-relative-path-escapes-the-fixture-root-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real IO, File, Path, iodata boundary from a clean shell.
  • Mutation check: violate “The same iodata producer targets multiple devices” and prove the suite reports fixture io-devices-positive as failed.
  • Regression corpus: retain the risks “String concatenation causes unnecessary copying”; “A device is confused with its owning process”; “A relative path escapes the fixture root” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “String concatenation causes unnecessary copying”

  • Why: This breaks one or more observable capabilities at the IO, File, Path, iodata boundary while allowing the happy path to look correct.
  • Fix: Run string-concatenation-causes-unnecessary-copying-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “A device is confused with its owning process”

  • Why: This breaks one or more observable capabilities at the IO, File, Path, iodata boundary while allowing the happy path to look correct.
  • Fix: Run a-device-is-confused-with-its-owning-process-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “A relative path escapes the fixture root”

  • Why: This breaks one or more observable capabilities at the IO, File, Path, iodata boundary while allowing the happy path to look correct.
  • Fix: Run a-relative-path-escapes-the-fixture-root-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • The same iodata producer targets multiple devices.
  • Paths remain portable and confined to a fixture root.
  • Tagged and bang APIs are exercised deliberately.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 27: Documented Address Validation SDK

Official topic: Writing documentation — Elixir v1.20.2

Source file: lib/elixir/pages/getting-started/writing-documentation.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Documentation / API Contracts
  • Software or Tool: ExDoc, doctest, Code.fetch_docs
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build a tiny public library whose primary artifact is its moduledoc, doc and typedoc contract, argument names, since/deprecated/group metadata, doctests, hidden internals, and Code.fetch_docs inspection.

Why it teaches this official topic: The artifact makes documentation attributes, documentation metadata, doctests, BEAM documentation chunks observable through one bounded build instead of isolated syntax examples.

Scope boundary: Validate documentation contracts only; exclude general bytecode inspection and adapter design.

Core challenges you will face:

  • documentation attributes -> identify the accepted case, the counterexample, and the observable result at the ExDoc, doctest, Code.fetch_docs boundary
  • documentation metadata -> identify the accepted case, the counterexample, and the observable result at the ExDoc, doctest, Code.fetch_docs boundary
  • doctests -> identify the accepted case, the counterexample, and the observable result at the ExDoc, doctest, Code.fetch_docs boundary
  • BEAM documentation chunks -> identify the accepted case, the counterexample, and the observable result at the ExDoc, doctest, Code.fetch_docs boundary

Real World Outcome

Build a tiny public library whose primary artifact is its moduledoc, doc and typedoc contract, argument names, since/deprecated/group metadata, doctests, hidden internals, and Code.fetch_docs inspection. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Every public function has an example and result contract.
  • Doctests execute the published examples.
  • Hidden internals are absent from the generated public surface.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=getting-started/writing-documentation.md
ARTIFACT=documented-address-validation-sdk
CHECK 01 PASS :: Every public function has an example and result contract
CHECK 02 PASS :: Doctests execute the published examples
CHECK 03 PASS :: Hidden internals are absent from the generated public surface
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“How can documentation become an executable, versioned part of a library contract?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. documentation attributes
    • Working rule: Make “documentation attributes” an explicit rule at the ExDoc, doctest, Code.fetch_docs boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "documentation-attributes-positive", focus: "documentation attributes", mode: :positive, expect: :observable} and %{id: "documentation-attributes-negative", focus: "documentation attributes", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Writing documentation
  2. documentation metadata
    • Working rule: Make “documentation metadata” an explicit rule at the ExDoc, doctest, Code.fetch_docs boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "documentation-metadata-positive", focus: "documentation metadata", mode: :positive, expect: :observable} and %{id: "documentation-metadata-negative", focus: "documentation metadata", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Writing documentation
  3. doctests
    • Working rule: Make “doctests” an explicit rule at the ExDoc, doctest, Code.fetch_docs boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "doctests-positive", focus: "doctests", mode: :positive, expect: :observable} and %{id: "doctests-negative", focus: "doctests", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Writing documentation
  4. BEAM documentation chunks
    • Working rule: Make “BEAM documentation chunks” an explicit rule at the ExDoc, doctest, Code.fetch_docs boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "beam-documentation-chunks-positive", focus: "BEAM documentation chunks", mode: :positive, expect: :observable} and %{id: "beam-documentation-chunks-negative", focus: "BEAM documentation chunks", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Writing documentation

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “documentation attributes” be enforced?
    • Which check catches the risk “Documentation repeats comments without explaining the API”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Every public function has an example and result contract”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Writing documentation”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: documentation attributes, documentation metadata, doctests, BEAM documentation chunks. Then trace the named counterexample “Documentation repeats comments without explaining the API” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose documentation attributes, and what does this project prove about it?”
  2. “What interaction between the concept ‘documentation metadata’ and the concept ‘documentation attributes’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘Documentation repeats comments without explaining the API’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with documentation-attributes-positive and documentation-repeats-comments-without-explaining-the-api-counterexample. The first must make the concept “documentation attributes” observable and establish “Every public function has an example and result contract”; the second must reproduce “Documentation repeats comments without explaining the API”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for getting-started/writing-documentation.md
evaluate "documentation attributes" through ExDoc, doctest, Code.fetch_docs
compare actual evidence with "Every public function has an example and result contract"
run negative fixture for "Documentation repeats comments without explaining the API"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Writing documentation Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
documentation attributes Elixir in Action, 3rd Edition Ch. 2-4
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement documentation-attributes-positive and prove “Every public function has an example and result contract”.
  3. Topic coverage: add fixtures for documentation metadata, doctests, BEAM documentation chunks.
  4. Failure campaign: reproduce each named risk: “Documentation repeats comments without explaining the API”; “A doctest depends on unstable output”; “Deprecated metadata lacks a migration path”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute documentation-attributes-positive, documentation-metadata-positive, doctests-positive, beam-documentation-chunks-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute documentation-attributes-negative, documentation-metadata-negative, doctests-negative, beam-documentation-chunks-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute documentation-repeats-comments-without-explaining-the-api-counterexample, a-doctest-depends-on-unstable-output-counterexample, deprecated-metadata-lacks-a-migration-path-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real ExDoc, doctest, Code.fetch_docs boundary from a clean shell.
  • Mutation check: violate “Every public function has an example and result contract” and prove the suite reports fixture documentation-attributes-positive as failed.
  • Regression corpus: retain the risks “Documentation repeats comments without explaining the API”; “A doctest depends on unstable output”; “Deprecated metadata lacks a migration path” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “Documentation repeats comments without explaining the API”

  • Why: This breaks one or more observable capabilities at the ExDoc, doctest, Code.fetch_docs boundary while allowing the happy path to look correct.
  • Fix: Run documentation-repeats-comments-without-explaining-the-api-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “A doctest depends on unstable output”

  • Why: This breaks one or more observable capabilities at the ExDoc, doctest, Code.fetch_docs boundary while allowing the happy path to look correct.
  • Fix: Run a-doctest-depends-on-unstable-output-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “Deprecated metadata lacks a migration path”

  • Why: This breaks one or more observable capabilities at the ExDoc, doctest, Code.fetch_docs boundary while allowing the happy path to look correct.
  • Fix: Run deprecated-metadata-lacks-a-migration-path-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • Every public function has an example and result contract.
  • Doctests execute the published examples.
  • Hidden internals are absent from the generated public surface.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 28: Formatter-Backed Team Syntax Fixture

Official topic: Optional syntax sheet — Elixir v1.20.2

Source file: lib/elixir/pages/getting-started/optional-syntax.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Syntax / Formatting
  • Software or Tool: mix format
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build a golden onboarding corpus showing parenthesized, parenthesis-free, bracketed keyword, and do-end forms that are semantically equivalent and converge under mix format.

Why it teaches this official topic: The artifact makes optional parentheses, do-end keyword expansion, omitted keyword brackets, canonical formatting observable through one bounded build instead of isolated syntax examples.

Scope boundary: Use paired fixtures and the formatter only; exclude compiler linting and custom formatting rules.

Core challenges you will face:

  • optional parentheses -> identify the accepted case, the counterexample, and the observable result at the mix format boundary
  • do-end keyword expansion -> identify the accepted case, the counterexample, and the observable result at the mix format boundary
  • omitted keyword brackets -> identify the accepted case, the counterexample, and the observable result at the mix format boundary
  • canonical formatting -> identify the accepted case, the counterexample, and the observable result at the mix format boundary

Real World Outcome

Build a golden onboarding corpus showing parenthesized, parenthesis-free, bracketed keyword, and do-end forms that are semantically equivalent and converge under mix format. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Each equivalence group parses to the same normalized AST.
  • The formatter produces one checked-in canonical form.
  • Ambiguous-looking cases are rejected from the style guide.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=getting-started/optional-syntax.md
ARTIFACT=formatter-backed-team-syntax-fixture
CHECK 01 PASS :: Each equivalence group parses to the same normalized AST
CHECK 02 PASS :: The formatter produces one checked-in canonical form
CHECK 03 PASS :: Ambiguous-looking cases are rejected from the style guide
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“Which syntax may be omitted safely, and how does the formatter prevent teams from debating equivalent forms?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. optional parentheses
    • Working rule: Make “optional parentheses” an explicit rule at the mix format boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "optional-parentheses-positive", focus: "optional parentheses", mode: :positive, expect: :observable} and %{id: "optional-parentheses-negative", focus: "optional parentheses", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Optional syntax sheet
  2. do-end keyword expansion
    • Working rule: Make “do-end keyword expansion” an explicit rule at the mix format boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "do-end-keyword-expansion-positive", focus: "do-end keyword expansion", mode: :positive, expect: :observable} and %{id: "do-end-keyword-expansion-negative", focus: "do-end keyword expansion", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Optional syntax sheet
  3. omitted keyword brackets
    • Working rule: Make “omitted keyword brackets” an explicit rule at the mix format boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "omitted-keyword-brackets-positive", focus: "omitted keyword brackets", mode: :positive, expect: :observable} and %{id: "omitted-keyword-brackets-negative", focus: "omitted keyword brackets", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Optional syntax sheet
  4. canonical formatting
    • Working rule: Make “canonical formatting” an explicit rule at the mix format boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "canonical-formatting-positive", focus: "canonical formatting", mode: :positive, expect: :observable} and %{id: "canonical-formatting-negative", focus: "canonical formatting", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Optional syntax sheet

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “optional parentheses” be enforced?
    • Which check catches the risk “AST metadata makes equivalent forms look different”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Each equivalence group parses to the same normalized AST”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Optional syntax sheet”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: optional parentheses, do-end keyword expansion, omitted keyword brackets, canonical formatting. Then trace the named counterexample “AST metadata makes equivalent forms look different” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose optional parentheses, and what does this project prove about it?”
  2. “What interaction between the concept ‘do-end keyword expansion’ and the concept ‘optional parentheses’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘AST metadata makes equivalent forms look different’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with optional-parentheses-positive and ast-metadata-makes-equivalent-forms-look-different-counterexample. The first must make the concept “optional parentheses” observable and establish “Each equivalence group parses to the same normalized AST”; the second must reproduce “AST metadata makes equivalent forms look different”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for getting-started/optional-syntax.md
evaluate "optional parentheses" through mix format
compare actual evidence with "Each equivalence group parses to the same normalized AST"
run negative fixture for "AST metadata makes equivalent forms look different"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Optional syntax sheet Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
optional parentheses Elixir in Action, 3rd Edition Ch. 2-4
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement optional-parentheses-positive and prove “Each equivalence group parses to the same normalized AST”.
  3. Topic coverage: add fixtures for do-end keyword expansion, omitted keyword brackets, canonical formatting.
  4. Failure campaign: reproduce each named risk: “AST metadata makes equivalent forms look different”; “Optional syntax changes call association”; “A style rule fights the official formatter”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute optional-parentheses-positive, do-end-keyword-expansion-positive, omitted-keyword-brackets-positive, canonical-formatting-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute optional-parentheses-negative, do-end-keyword-expansion-negative, omitted-keyword-brackets-negative, canonical-formatting-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute ast-metadata-makes-equivalent-forms-look-different-counterexample, optional-syntax-changes-call-association-counterexample, a-style-rule-fights-the-official-formatter-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real mix format boundary from a clean shell.
  • Mutation check: violate “Each equivalence group parses to the same normalized AST” and prove the suite reports fixture optional-parentheses-positive as failed.
  • Regression corpus: retain the risks “AST metadata makes equivalent forms look different”; “Optional syntax changes call association”; “A style rule fights the official formatter” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “AST metadata makes equivalent forms look different”

  • Why: This breaks one or more observable capabilities at the mix format boundary while allowing the happy path to look correct.
  • Fix: Run ast-metadata-makes-equivalent-forms-look-different-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “Optional syntax changes call association”

  • Why: This breaks one or more observable capabilities at the mix format boundary while allowing the happy path to look correct.
  • Fix: Run optional-syntax-changes-call-association-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “A style rule fights the official formatter”

  • Why: This breaks one or more observable capabilities at the mix format boundary while allowing the happy path to look correct.
  • Fix: Run a-style-rule-fights-the-official-formatter-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • Each equivalence group parses to the same normalized AST.
  • The formatter produces one checked-in canonical form.
  • Ambiguous-looking cases are rejected from the style guide.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 29: Offline Incident Bundle Analyzer

Official topic: Erlang libraries — Elixir v1.20.2

Source file: lib/elixir/pages/getting-started/erlang-libraries.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Erlang Interoperability
  • Software or Tool: :zip, :crypto, :digraph, :ets, :queue, :io_lib
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build an offline analyzer that opens ZIP evidence, hashes entries, indexes metadata in ETS, builds a dependency graph, queues findings, uses deterministic random sampling, and emits an iolist report.

Why it teaches this official topic: The artifact makes direct Erlang module calls, OTP application dependencies, mutable Erlang libraries, iolist interoperability observable through one bounded build instead of isolated syntax examples.

Scope boundary: Analyze offline evidence; do not audit Mix dependencies or inspect BEAM artifacts.

Core challenges you will face:

  • direct Erlang module calls -> identify the accepted case, the counterexample, and the observable result at the :zip, :crypto, :digraph, :ets, :queue, :io_lib boundary
  • OTP application dependencies -> identify the accepted case, the counterexample, and the observable result at the :zip, :crypto, :digraph, :ets, :queue, :io_lib boundary
  • mutable Erlang libraries -> identify the accepted case, the counterexample, and the observable result at the :zip, :crypto, :digraph, :ets, :queue, :io_lib boundary
  • iolist interoperability -> identify the accepted case, the counterexample, and the observable result at the :zip, :crypto, :digraph, :ets, :queue, :io_lib boundary

Real World Outcome

Build an offline analyzer that opens ZIP evidence, hashes entries, indexes metadata in ETS, builds a dependency graph, queues findings, uses deterministic random sampling, and emits an iolist report. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Each selected Erlang library has one justified responsibility.
  • Crypto startup and dependency requirements are explicit.
  • Mutable ETS and graph state are cleaned after analysis.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=getting-started/erlang-libraries.md
ARTIFACT=offline-incident-bundle-analyzer
CHECK 01 PASS :: Each selected Erlang library has one justified responsibility
CHECK 02 PASS :: Crypto startup and dependency requirements are explicit
CHECK 03 PASS :: Mutable ETS and graph state are cleaned after analysis
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“How can Elixir use Erlang libraries directly while making their return conventions and side effects explicit?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. direct Erlang module calls
    • Working rule: Make “direct Erlang module calls” an explicit rule at the :zip, :crypto, :digraph, :ets, :queue, :io_lib boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "direct-erlang-module-calls-positive", focus: "direct Erlang module calls", mode: :positive, expect: :observable} and %{id: "direct-erlang-module-calls-negative", focus: "direct Erlang module calls", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Erlang libraries
  2. OTP application dependencies
    • Working rule: Make “OTP application dependencies” an explicit rule at the :zip, :crypto, :digraph, :ets, :queue, :io_lib boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "otp-application-dependencies-positive", focus: "OTP application dependencies", mode: :positive, expect: :observable} and %{id: "otp-application-dependencies-negative", focus: "OTP application dependencies", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Erlang libraries
  3. mutable Erlang libraries
    • Working rule: Make “mutable Erlang libraries” an explicit rule at the :zip, :crypto, :digraph, :ets, :queue, :io_lib boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "mutable-erlang-libraries-positive", focus: "mutable Erlang libraries", mode: :positive, expect: :observable} and %{id: "mutable-erlang-libraries-negative", focus: "mutable Erlang libraries", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Erlang libraries
  4. iolist interoperability
    • Working rule: Make “iolist interoperability” an explicit rule at the :zip, :crypto, :digraph, :ets, :queue, :io_lib boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "iolist-interoperability-positive", focus: "iolist interoperability", mode: :positive, expect: :observable} and %{id: "iolist-interoperability-negative", focus: "iolist interoperability", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Erlang libraries

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “direct Erlang module calls” be enforced?
    • Which check catches the risk “An Erlang return shape is assumed to match an Elixir convention”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Each selected Erlang library has one justified responsibility”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Erlang libraries”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: direct Erlang module calls, OTP application dependencies, mutable Erlang libraries, iolist interoperability. Then trace the named counterexample “An Erlang return shape is assumed to match an Elixir convention” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose direct Erlang module calls, and what does this project prove about it?”
  2. “What interaction between the concept ‘OTP application dependencies’ and the concept ‘direct Erlang module calls’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘An Erlang return shape is assumed to match an Elixir convention’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with direct-erlang-module-calls-positive and an-erlang-return-shape-is-assumed-to-match-an-elixir-convention-counterexample. The first must make the concept “direct Erlang module calls” observable and establish “Each selected Erlang library has one justified responsibility”; the second must reproduce “An Erlang return shape is assumed to match an Elixir convention”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for getting-started/erlang-libraries.md
evaluate "direct Erlang module calls" through :zip, :crypto, :digraph, :ets, :queue, :io_lib
compare actual evidence with "Each selected Erlang library has one justified responsibility"
run negative fixture for "An Erlang return shape is assumed to match an Elixir convention"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Erlang libraries Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
direct Erlang module calls Elixir in Action, 3rd Edition Ch. 2-4
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement direct-erlang-module-calls-positive and prove “Each selected Erlang library has one justified responsibility”.
  3. Topic coverage: add fixtures for OTP application dependencies, mutable Erlang libraries, iolist interoperability.
  4. Failure campaign: reproduce each named risk: “An Erlang return shape is assumed to match an Elixir convention”; “A required OTP application is missing”; “Mutable library state leaks between tests”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute direct-erlang-module-calls-positive, otp-application-dependencies-positive, mutable-erlang-libraries-positive, iolist-interoperability-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute direct-erlang-module-calls-negative, otp-application-dependencies-negative, mutable-erlang-libraries-negative, iolist-interoperability-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute an-erlang-return-shape-is-assumed-to-match-an-elixir-convention-counterexample, a-required-otp-application-is-missing-counterexample, mutable-library-state-leaks-between-tests-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real :zip, :crypto, :digraph, :ets, :queue, :io_lib boundary from a clean shell.
  • Mutation check: violate “Each selected Erlang library has one justified responsibility” and prove the suite reports fixture direct-erlang-module-calls-positive as failed.
  • Regression corpus: retain the risks “An Erlang return shape is assumed to match an Elixir convention”; “A required OTP application is missing”; “Mutable library state leaks between tests” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “An Erlang return shape is assumed to match an Elixir convention”

  • Why: This breaks one or more observable capabilities at the :zip, :crypto, :digraph, :ets, :queue, :io_lib boundary while allowing the happy path to look correct.
  • Fix: Run an-erlang-return-shape-is-assumed-to-match-an-elixir-convention-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “A required OTP application is missing”

  • Why: This breaks one or more observable capabilities at the :zip, :crypto, :digraph, :ets, :queue, :io_lib boundary while allowing the happy path to look correct.
  • Fix: Run a-required-otp-application-is-missing-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “Mutable library state leaks between tests”

  • Why: This breaks one or more observable capabilities at the :zip, :crypto, :digraph, :ets, :queue, :io_lib boundary while allowing the happy path to look correct.
  • Fix: Run mutable-library-state-leaks-between-tests-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • Each selected Erlang library has one justified responsibility.
  • Crypto startup and dependency requirements are explicit.
  • Mutable ETS and graph state are cleaned after analysis.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 30: Reproducible Order-Pipeline Debugging Casebook

Official topic: Debugging — Elixir v1.20.2

Source file: lib/elixir/pages/getting-started/debugging.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Debugging / Runtime Introspection
  • Software or Tool: dbg, IEx, ExUnit breakpoints, Observer
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build intentionally broken local fixtures and diagnose each with IO.inspect, dbg, IEx pry, breakpoints, Observer, runtime_info, and one lower-level profiling or crash artifact.

Why it teaches this official topic: The artifact makes inspection and dbg, pry and breakpoints, Observer and runtime info, profilers and crash evidence observable through one bounded build instead of isolated syntax examples.

Scope boundary: Keep all failures deterministic and local; exclude production tracing and scheduler pressure campaigns.

Core challenges you will face:

  • inspection and dbg -> identify the accepted case, the counterexample, and the observable result at the dbg, IEx, ExUnit breakpoints, Observer boundary
  • pry and breakpoints -> identify the accepted case, the counterexample, and the observable result at the dbg, IEx, ExUnit breakpoints, Observer boundary
  • Observer and runtime info -> identify the accepted case, the counterexample, and the observable result at the dbg, IEx, ExUnit breakpoints, Observer boundary
  • profilers and crash evidence -> identify the accepted case, the counterexample, and the observable result at the dbg, IEx, ExUnit breakpoints, Observer boundary

Real World Outcome

Build intentionally broken local fixtures and diagnose each with IO.inspect, dbg, IEx pry, breakpoints, Observer, runtime_info, and one lower-level profiling or crash artifact. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Every bug has a reproduction command before diagnosis.
  • Each tool answers a different bounded question.
  • The casebook records evidence before and after the fix.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=getting-started/debugging.md
ARTIFACT=reproducible-order-pipeline-debugging-casebook
CHECK 01 PASS :: Every bug has a reproduction command before diagnosis
CHECK 02 PASS :: Each tool answers a different bounded question
CHECK 03 PASS :: The casebook records evidence before and after the fix
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“Which debugging tool gives the smallest trustworthy observation for the current hypothesis?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. inspection and dbg
    • Working rule: Make “inspection and dbg” an explicit rule at the dbg, IEx, ExUnit breakpoints, Observer boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "inspection-and-dbg-positive", focus: "inspection and dbg", mode: :positive, expect: :observable} and %{id: "inspection-and-dbg-negative", focus: "inspection and dbg", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Debugging
  2. pry and breakpoints
    • Working rule: Make “pry and breakpoints” an explicit rule at the dbg, IEx, ExUnit breakpoints, Observer boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "pry-and-breakpoints-positive", focus: "pry and breakpoints", mode: :positive, expect: :observable} and %{id: "pry-and-breakpoints-negative", focus: "pry and breakpoints", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Debugging
  3. Observer and runtime info
    • Working rule: Make “Observer and runtime info” an explicit rule at the dbg, IEx, ExUnit breakpoints, Observer boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "observer-and-runtime-info-positive", focus: "Observer and runtime info", mode: :positive, expect: :observable} and %{id: "observer-and-runtime-info-negative", focus: "Observer and runtime info", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Debugging
  4. profilers and crash evidence
    • Working rule: Make “profilers and crash evidence” an explicit rule at the dbg, IEx, ExUnit breakpoints, Observer boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "profilers-and-crash-evidence-positive", focus: "profilers and crash evidence", mode: :positive, expect: :observable} and %{id: "profilers-and-crash-evidence-negative", focus: "profilers and crash evidence", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Debugging

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “inspection and dbg” be enforced?
    • Which check catches the risk “Debug output changes the timing-dependent symptom”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Every bug has a reproduction command before diagnosis”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Debugging”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: inspection and dbg, pry and breakpoints, Observer and runtime info, profilers and crash evidence. Then trace the named counterexample “Debug output changes the timing-dependent symptom” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose inspection and dbg, and what does this project prove about it?”
  2. “What interaction between the concept ‘pry and breakpoints’ and the concept ‘inspection and dbg’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘Debug output changes the timing-dependent symptom’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with inspection-and-dbg-positive and debug-output-changes-the-timing-dependent-symptom-counterexample. The first must make the concept “inspection and dbg” observable and establish “Every bug has a reproduction command before diagnosis”; the second must reproduce “Debug output changes the timing-dependent symptom”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for getting-started/debugging.md
evaluate "inspection and dbg" through dbg, IEx, ExUnit breakpoints, Observer
compare actual evidence with "Every bug has a reproduction command before diagnosis"
run negative fixture for "Debug output changes the timing-dependent symptom"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Debugging Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
inspection and dbg Elixir in Action, 3rd Edition Ch. 2-4
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement inspection-and-dbg-positive and prove “Every bug has a reproduction command before diagnosis”.
  3. Topic coverage: add fixtures for pry and breakpoints, Observer and runtime info, profilers and crash evidence.
  4. Failure campaign: reproduce each named risk: “Debug output changes the timing-dependent symptom”; “Pry is expected to work without an IEx shell”; “Observer is used without a hypothesis”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute inspection-and-dbg-positive, pry-and-breakpoints-positive, observer-and-runtime-info-positive, profilers-and-crash-evidence-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute inspection-and-dbg-negative, pry-and-breakpoints-negative, observer-and-runtime-info-negative, profilers-and-crash-evidence-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute debug-output-changes-the-timing-dependent-symptom-counterexample, pry-is-expected-to-work-without-an-iex-shell-counterexample, observer-is-used-without-a-hypothesis-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real dbg, IEx, ExUnit breakpoints, Observer boundary from a clean shell.
  • Mutation check: violate “Every bug has a reproduction command before diagnosis” and prove the suite reports fixture inspection-and-dbg-positive as failed.
  • Regression corpus: retain the risks “Debug output changes the timing-dependent symptom”; “Pry is expected to work without an IEx shell”; “Observer is used without a hypothesis” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “Debug output changes the timing-dependent symptom”

  • Why: This breaks one or more observable capabilities at the dbg, IEx, ExUnit breakpoints, Observer boundary while allowing the happy path to look correct.
  • Fix: Run debug-output-changes-the-timing-dependent-symptom-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “Pry is expected to work without an IEx shell”

  • Why: This breaks one or more observable capabilities at the dbg, IEx, ExUnit breakpoints, Observer boundary while allowing the happy path to look correct.
  • Fix: Run pry-is-expected-to-work-without-an-iex-shell-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “Observer is used without a hypothesis”

  • Why: This breaks one or more observable capabilities at the dbg, IEx, ExUnit breakpoints, Observer boundary while allowing the happy path to look correct.
  • Fix: Run observer-is-used-without-a-hypothesis-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • Every bug has a reproduction command before diagnosis.
  • Each tool answers a different bounded question.
  • The casebook records evidence before and after the fix.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 31: Team-Ready Mix Project and CI Quality Gate

Official topic: Introduction to Mix — Elixir v1.20.2

Source file: lib/elixir/pages/mix-and-otp/introduction-to-mix.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Build Tooling / Developer Workflow
  • Software or Tool: Mix, ExUnit, mix format
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build a reusable starter application with a small environment-report API, mix.exs metadata, compilation evidence, ExUnit tests, targeted commands, formatter enforcement, environment checks, and one local CI-style quality command.

Why it teaches this official topic: The artifact makes Mix project structure, compilation and build artifacts, ExUnit workflow, environments and formatting observable through one bounded build instead of isolated syntax examples.

Scope boundary: Own project structure and feedback loops; exclude dependency auditing, release packaging, and bytecode inspection.

Core challenges you will face:

  • Mix project structure -> identify the accepted case, the counterexample, and the observable result at the Mix, ExUnit, mix format boundary
  • compilation and build artifacts -> identify the accepted case, the counterexample, and the observable result at the Mix, ExUnit, mix format boundary
  • ExUnit workflow -> identify the accepted case, the counterexample, and the observable result at the Mix, ExUnit, mix format boundary
  • environments and formatting -> identify the accepted case, the counterexample, and the observable result at the Mix, ExUnit, mix format boundary

Real World Outcome

Build a reusable starter application with a small environment-report API, mix.exs metadata, compilation evidence, ExUnit tests, targeted commands, formatter enforcement, environment checks, and one local CI-style quality command. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • A clean checkout compiles and tests with one command.
  • Dev, test, and prod environment differences are observable.
  • Formatter and focused-test commands fail the gate when violated.

Acceptance transcript:

$ mix quality
SOURCE_TOPIC=mix-and-otp/introduction-to-mix.md
ARTIFACT=team-ready-mix-project-and-ci-quality-gate
CHECK 01 PASS :: A clean checkout compiles and tests with one command
CHECK 02 PASS :: Dev, test, and prod environment differences are observable
CHECK 03 PASS :: Formatter and focused-test commands fail the gate when violated
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“What minimum Mix contract makes a small Elixir project reproducible for every teammate?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. Mix project structure
    • Working rule: Make “Mix project structure” an explicit rule at the Mix, ExUnit, mix format boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "mix-project-structure-positive", focus: "Mix project structure", mode: :positive, expect: :observable} and %{id: "mix-project-structure-negative", focus: "Mix project structure", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Introduction to Mix
  2. compilation and build artifacts
    • Working rule: Make “compilation and build artifacts” an explicit rule at the Mix, ExUnit, mix format boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "compilation-and-build-artifacts-positive", focus: "compilation and build artifacts", mode: :positive, expect: :observable} and %{id: "compilation-and-build-artifacts-negative", focus: "compilation and build artifacts", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Introduction to Mix
  3. ExUnit workflow
    • Working rule: Make “ExUnit workflow” an explicit rule at the Mix, ExUnit, mix format boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "exunit-workflow-positive", focus: "ExUnit workflow", mode: :positive, expect: :observable} and %{id: "exunit-workflow-negative", focus: "ExUnit workflow", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Introduction to Mix
  4. environments and formatting
    • Working rule: Make “environments and formatting” an explicit rule at the Mix, ExUnit, mix format boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "environments-and-formatting-positive", focus: "environments and formatting", mode: :positive, expect: :observable} and %{id: "environments-and-formatting-negative", focus: "environments and formatting", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Introduction to Mix

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “Mix project structure” be enforced?
    • Which check catches the risk “Generated build state hides a missing source file”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “A clean checkout compiles and tests with one command”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Introduction to Mix”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: Mix project structure, compilation and build artifacts, ExUnit workflow, environments and formatting. Then trace the named counterexample “Generated build state hides a missing source file” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose Mix project structure, and what does this project prove about it?”
  2. “What interaction between the concept ‘compilation and build artifacts’ and the concept ‘Mix project structure’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘Generated build state hides a missing source file’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with mix-project-structure-positive and generated-build-state-hides-a-missing-source-file-counterexample. The first must make the concept “Mix project structure” observable and establish “A clean checkout compiles and tests with one command”; the second must reproduce “Generated build state hides a missing source file”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for mix-and-otp/introduction-to-mix.md
evaluate "Mix project structure" through Mix, ExUnit, mix format
compare actual evidence with "A clean checkout compiles and tests with one command"
run negative fixture for "Generated build state hides a missing source file"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix quality from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Introduction to Mix Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
Mix project structure Elixir in Action, 3rd Edition Ch. 2-4
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement mix-project-structure-positive and prove “A clean checkout compiles and tests with one command”.
  3. Topic coverage: add fixtures for compilation and build artifacts, ExUnit workflow, environments and formatting.
  4. Failure campaign: reproduce each named risk: “Generated build state hides a missing source file”; “Environment-specific behavior leaks into tests”; “The quality command silently skips formatting”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute mix-project-structure-positive, compilation-and-build-artifacts-positive, exunit-workflow-positive, environments-and-formatting-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute mix-project-structure-negative, compilation-and-build-artifacts-negative, exunit-workflow-negative, environments-and-formatting-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute generated-build-state-hides-a-missing-source-file-counterexample, environment-specific-behavior-leaks-into-tests-counterexample, the-quality-command-silently-skips-formatting-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix quality through the real Mix, ExUnit, mix format boundary from a clean shell.
  • Mutation check: violate “A clean checkout compiles and tests with one command” and prove the suite reports fixture mix-project-structure-positive as failed.
  • Regression corpus: retain the risks “Generated build state hides a missing source file”; “Environment-specific behavior leaks into tests”; “The quality command silently skips formatting” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “Generated build state hides a missing source file”

  • Why: This breaks one or more observable capabilities at the Mix, ExUnit, mix format boundary while allowing the happy path to look correct.
  • Fix: Run generated-build-state-hides-a-missing-source-file-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix quality

Problem 2: “Environment-specific behavior leaks into tests”

  • Why: This breaks one or more observable capabilities at the Mix, ExUnit, mix format boundary while allowing the happy path to look correct.
  • Fix: Run environment-specific-behavior-leaks-into-tests-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix quality

Problem 3: “The quality command silently skips formatting”

  • Why: This breaks one or more observable capabilities at the Mix, ExUnit, mix format boundary while allowing the happy path to look correct.
  • Fix: Run the-quality-command-silently-skips-formatting-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix quality

Definition of Done

  • A clean checkout compiles and tests with one command.
  • Dev, test, and prod environment differences are observable.
  • Formatter and focused-test commands fail the gate when violated.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 32: Evidence-Based Elixir Smell Triage Board

Official topic: What are anti-patterns? — Elixir v1.20.2

Source file: lib/elixir/pages/anti-patterns/what-anti-patterns.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Engineering Judgment / Code Health
  • Software or Tool: ExUnit, benchmark and ADR fixtures
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build a CLI report that classifies mixed code, design, process, and macro smells as refactor, accept, or time-bounded waiver, with evidence and an architecture decision record.

Why it teaches this official topic: The artifact makes contextual code smells, anti-pattern categories, problem-example-refactoring analysis, documented exceptions observable through one bounded build instead of isolated syntax examples.

Scope boundary: Grade judgment over a mixed portfolio; leave category-specific refactors to the later anti-pattern projects.

Core challenges you will face:

  • contextual code smells -> identify the accepted case, the counterexample, and the observable result at the ExUnit, benchmark and ADR fixtures boundary
  • anti-pattern categories -> identify the accepted case, the counterexample, and the observable result at the ExUnit, benchmark and ADR fixtures boundary
  • problem-example-refactoring analysis -> identify the accepted case, the counterexample, and the observable result at the ExUnit, benchmark and ADR fixtures boundary
  • documented exceptions -> identify the accepted case, the counterexample, and the observable result at the ExUnit, benchmark and ADR fixtures boundary

Real World Outcome

Build a CLI report that classifies mixed code, design, process, and macro smells as refactor, accept, or time-bounded waiver, with evidence and an architecture decision record. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Every finding includes context and evidence.
  • Accept and waive decisions state why refactoring would be worse.
  • Refactor decisions define a measurable success criterion.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=anti-patterns/what-anti-patterns.md
ARTIFACT=evidence-based-elixir-smell-triage-board
CHECK 01 PASS :: Every finding includes context and evidence
CHECK 02 PASS :: Accept and waive decisions state why refactoring would be worse
CHECK 03 PASS :: Refactor decisions define a measurable success criterion
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“When is a recognizable pattern harmful enough to refactor, and what evidence justifies leaving it alone?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. contextual code smells
    • Working rule: Make “contextual code smells” an explicit rule at the ExUnit, benchmark and ADR fixtures boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "contextual-code-smells-positive", focus: "contextual code smells", mode: :positive, expect: :observable} and %{id: "contextual-code-smells-negative", focus: "contextual code smells", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: What are anti-patterns?
  2. anti-pattern categories
    • Working rule: Make “anti-pattern categories” an explicit rule at the ExUnit, benchmark and ADR fixtures boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "anti-pattern-categories-positive", focus: "anti-pattern categories", mode: :positive, expect: :observable} and %{id: "anti-pattern-categories-negative", focus: "anti-pattern categories", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: What are anti-patterns?
  3. problem-example-refactoring analysis
    • Working rule: Make “problem-example-refactoring analysis” an explicit rule at the ExUnit, benchmark and ADR fixtures boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "problem-example-refactoring-analysis-positive", focus: "problem-example-refactoring analysis", mode: :positive, expect: :observable} and %{id: "problem-example-refactoring-analysis-negative", focus: "problem-example-refactoring analysis", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: What are anti-patterns?
  4. documented exceptions
    • Working rule: Make “documented exceptions” an explicit rule at the ExUnit, benchmark and ADR fixtures boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "documented-exceptions-positive", focus: "documented exceptions", mode: :positive, expect: :observable} and %{id: "documented-exceptions-negative", focus: "documented exceptions", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: What are anti-patterns?

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “contextual code smells” be enforced?
    • Which check catches the risk “Every smell is treated as an automatic violation”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Every finding includes context and evidence”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “What are anti-patterns”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: contextual code smells, anti-pattern categories, problem-example-refactoring analysis, documented exceptions. Then trace the named counterexample “Every smell is treated as an automatic violation” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose contextual code smells, and what does this project prove about it?”
  2. “What interaction between the concept ‘anti-pattern categories’ and the concept ‘contextual code smells’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘Every smell is treated as an automatic violation’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with contextual-code-smells-positive and every-smell-is-treated-as-an-automatic-violation-counterexample. The first must make the concept “contextual code smells” observable and establish “Every finding includes context and evidence”; the second must reproduce “Every smell is treated as an automatic violation”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for anti-patterns/what-anti-patterns.md
evaluate "contextual code smells" through ExUnit, benchmark and ADR fixtures
compare actual evidence with "Every finding includes context and evidence"
run negative fixture for "Every smell is treated as an automatic violation"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
What are anti-patterns? Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
contextual code smells Elixir in Action, 3rd Edition Ch. 2-4
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement contextual-code-smells-positive and prove “Every finding includes context and evidence”.
  3. Topic coverage: add fixtures for anti-pattern categories, problem-example-refactoring analysis, documented exceptions.
  4. Failure campaign: reproduce each named risk: “Every smell is treated as an automatic violation”; “A waiver has no expiry or owner”; “Refactoring proceeds without behavioral evidence”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute contextual-code-smells-positive, anti-pattern-categories-positive, problem-example-refactoring-analysis-positive, documented-exceptions-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute contextual-code-smells-negative, anti-pattern-categories-negative, problem-example-refactoring-analysis-negative, documented-exceptions-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute every-smell-is-treated-as-an-automatic-violation-counterexample, a-waiver-has-no-expiry-or-owner-counterexample, refactoring-proceeds-without-behavioral-evidence-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real ExUnit, benchmark and ADR fixtures boundary from a clean shell.
  • Mutation check: violate “Every finding includes context and evidence” and prove the suite reports fixture contextual-code-smells-positive as failed.
  • Regression corpus: retain the risks “Every smell is treated as an automatic violation”; “A waiver has no expiry or owner”; “Refactoring proceeds without behavioral evidence” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “Every smell is treated as an automatic violation”

  • Why: This breaks one or more observable capabilities at the ExUnit, benchmark and ADR fixtures boundary while allowing the happy path to look correct.
  • Fix: Run every-smell-is-treated-as-an-automatic-violation-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “A waiver has no expiry or owner”

  • Why: This breaks one or more observable capabilities at the ExUnit, benchmark and ADR fixtures boundary while allowing the happy path to look correct.
  • Fix: Run a-waiver-has-no-expiry-or-owner-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “Refactoring proceeds without behavioral evidence”

  • Why: This breaks one or more observable capabilities at the ExUnit, benchmark and ADR fixtures boundary while allowing the happy path to look correct.
  • Fix: Run refactoring-proceeds-without-behavioral-evidence-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • Every finding includes context and evidence.
  • Accept and waive decisions state why refactoring would be worse.
  • Refactor decisions define a measurable success criterion.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 33: Round-Trip INI Configuration Tool

Source: ERL-P2. Build an INI parser/writer with sections, comments, validation, and stable round trips.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Erlang
  • Alternative Programming Languages: OCaml, Haskell, Rust
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: File I/O / Parsing
  • Software or Tool: INI Configuration Files
  • Main Book: “Programming Erlang” by Joe Armstrong

What you will build: Build an INI parser/writer with sections, comments, validation, and stable round trips.

Why it teaches the BEAM ecosystem: It makes you prove that parsing, rendering, and error locations are deterministic for a fixture corpus.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Build an INI parser/writer with sections, comments, validation, and stable round trips.

A library that reads INI configuration files into Erlang data structures and writes them back, handling sections, key-value pairs, and comments.

Build Round-Trip INI Configuration Tool as one runnable, observable artifact. Build an INI parser/writer with sections, comments, validation, and stable round trips.

Produce an evidence bundle containing:

  • one deterministic happy-path run;
  • one rejected or malformed input with an explicit reason;
  • one injected failure or boundary condition;
  • a final verification result proving: parsing, rendering, and error locations are deterministic for a fixture corpus.
artifact=round-trip_ini_configuration_tool
happy_path=PASS
invalid_input=REJECTED explicit_reason=true
failure_boundary=EXERCISED recovery_evidence=true
mastery_check=PASS

The Core Question You Are Answering

“How can Round-Trip INI Configuration Tool deliver its observable outcome while proving that parsing, rendering, and error locations are deterministic for a fixture corpus.”

Concepts You Must Understand First

  • File reading (file:read_file/1 returns binary) → maps to binary vs list strings
  • Line-by-line parsing → maps to binary pattern matching
  • Data representation (sections → keys → values) → maps to maps or records
  • Writing back to file → maps to iolist construction

Questions to Guide Your Design

  1. Which input and output contracts must remain stable across refactoring?
  2. Where should validation happen, and how will expected failures be represented?
  3. Which component owns mutable state or external effects, and what happens when it dies?
  4. What independent evidence proves this mastery condition: parsing, rendering, and error locations are deterministic for a fixture corpus.

Thinking Exercise

Draw Round-Trip INI Configuration Tool as an input → decision/state → effect → evidence pipeline.

Mark every failure boundary, retry boundary, and durable state transition. Then inject one failure at each boundary and predict the observable result before implementing it.

The Interview Questions They Will Ask

  1. “What is the hardest invariant in Round-Trip INI Configuration Tool, and where is it enforced?”
  2. “Which parts should be pure transformations and which require BEAM processes?”
  3. “How does the design behave under malformed input, process failure, or retry?”
  4. “What test or runtime evidence proves: parsing, rendering, and error locations are deterministic for a fixture corpus.”

Hints in Layers

Binary pattern matching in Erlang is powerful: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Erlang binaries use <<...>> syntax, and /binary in patterns means “rest of the binary.”

Hint 1: Starting Point Implement the narrowest happy path for: Build an INI parser/writer with sections, comments, validation, and stable round trips.

Hint 2: Next Level Separate parsing, validation, and transition decisions from effects so each can be tested directly.

Hint 3: Technical Details Represent expected failures as tagged outcomes and keep state ownership explicit; write only structural pseudocode before implementation.

Hint 4: Tools and Debugging Inject one failure at a time, correlate it with bounded telemetry, and save a deterministic transcript as evidence.

Books That Will Help

  • Main Book: “Programming Erlang” by Joe Armstrong

Implementation Milestones

  1. Read file into binary → You understand Erlang file operations
  2. Parse all line types correctly → You’ve mastered binary pattern matching
  3. Round-trip (read then write) preserves data → You understand iolists

Testing Strategy

  • Unit checks: pure parsing, validation, transition, and formatting decisions.
  • Integration checks: the real process, database, socket, notebook, or framework boundary.
  • Failure checks: malformed input plus at least one crash, timeout, duplicate, overload, or partition scenario.
  • Acceptance check: independently demonstrate that parsing, rendering, and error locations are deterministic for a fixture corpus.
  • Avoid arbitrary sleeps; use messages, monitors, deterministic clocks, fixtures, and deadlines where applicable.

Common Pitfalls and Debugging

Problem 1: Happy-path output looks correct but failures disappear

  • Why: validation, effects, and reporting share one opaque step.
  • Fix: preserve tagged errors and source identity through every stage.
  • Quick test: inject one invalid record or failed dependency and verify an explicit result.

Problem 2: Tests merely repeat the implementation

  • Why: assertions reuse the same transformation or state assumptions.
  • Fix: check external invariants, golden fixtures, and observable failure behavior.
  • Quick test: introduce a deliberate ordering or boundary bug and confirm the test fails.

Definition of Done

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • parsing, rendering, and error locations are deterministic for a fixture corpus.

Project 34: Markdown-to-HTML Transformation Pipeline

Source: ERL-P3. Build staged Erlang transformations for headings, lists, links, and escaping.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Erlang
  • Alternative Programming Languages: Haskell, OCaml, Rust
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Parsing / Text Processing
  • Software or Tool: Markdown
  • Main Book: “Programming Erlang” by Joe Armstrong

What you will build: Build staged Erlang transformations for headings, lists, links, and escaping.

Why it teaches the BEAM ecosystem: It makes you prove that each stage is independently testable and complete output matches golden fixtures.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Build staged Erlang transformations for headings, lists, links, and escaping.

Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Open README.html in a browser to verify correct rendering.

Build Markdown-to-HTML Transformation Pipeline as one runnable, observable artifact. Build staged Erlang transformations for headings, lists, links, and escaping.

Produce an evidence bundle containing:

  • one deterministic happy-path run;
  • one rejected or malformed input with an explicit reason;
  • one injected failure or boundary condition;
  • a final verification result proving: each stage is independently testable and complete output matches golden fixtures.
artifact=markdown-to-html_transformation_pipeline
happy_path=PASS
invalid_input=REJECTED explicit_reason=true
failure_boundary=EXERCISED recovery_evidence=true
mastery_check=PASS

The Core Question You Are Answering

“How can Markdown-to-HTML Transformation Pipeline deliver its observable outcome while proving that each stage is independently testable and complete output matches golden fixtures.”

Concepts You Must Understand First

  • Block vs inline parsing (paragraphs contain bold/italic) → maps to two-pass parsing
  • Nested lists → maps to recursive data structures
  • State tracking (inside code block? inside list?) → maps to accumulator patterns
  • HTML escaping (prevent XSS) → maps to binary transformation

Questions to Guide Your Design

  1. Which input and output contracts must remain stable across refactoring?
  2. Where should validation happen, and how will expected failures be represented?
  3. Which component owns mutable state or external effects, and what happens when it dies?
  4. What independent evidence proves this mastery condition: each stage is independently testable and complete output matches golden fixtures.

Thinking Exercise

Draw Markdown-to-HTML Transformation Pipeline as an input → decision/state → effect → evidence pipeline.

Mark every failure boundary, retry boundary, and durable state transition. Then inject one failure at each boundary and predict the observable result before implementing it.

The Interview Questions They Will Ask

  1. “What is the hardest invariant in Markdown-to-HTML Transformation Pipeline, and where is it enforced?”
  2. “Which parts should be pure transformations and which require BEAM processes?”
  3. “How does the design behave under malformed input, process failure, or retry?”
  4. “What test or runtime evidence proves: each stage is independently testable and complete output matches golden fixtures.”

Hints in Layers

Use a two-pass approach:

  1. Block pass: Split into paragraphs, headers, lists, code blocks
  2. Inline pass: Within each block, parse bold, italic, links, code spans

For nested lists, track indentation level and use recursion: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Hint 1: Starting Point Implement the narrowest happy path for: Build staged Erlang transformations for headings, lists, links, and escaping.

Hint 2: Next Level Separate parsing, validation, and transition decisions from effects so each can be tested directly.

Hint 3: Technical Details Represent expected failures as tagged outcomes and keep state ownership explicit; write only structural pseudocode before implementation.

Hint 4: Tools and Debugging Inject one failure at a time, correlate it with bounded telemetry, and save a deterministic transcript as evidence.

Books That Will Help

  • Main Book: “Programming Erlang” by Joe Armstrong

Implementation Milestones

  1. Headers and paragraphs work → Basic block parsing done
  2. Inline formatting works → You understand recursive descent in Erlang
  3. Nested lists render correctly → You’ve mastered recursive data structures

Testing Strategy

  • Unit checks: pure parsing, validation, transition, and formatting decisions.
  • Integration checks: the real process, database, socket, notebook, or framework boundary.
  • Failure checks: malformed input plus at least one crash, timeout, duplicate, overload, or partition scenario.
  • Acceptance check: independently demonstrate that each stage is independently testable and complete output matches golden fixtures.
  • Avoid arbitrary sleeps; use messages, monitors, deterministic clocks, fixtures, and deadlines where applicable.

Common Pitfalls and Debugging

Problem 1: Happy-path output looks correct but failures disappear

  • Why: validation, effects, and reporting share one opaque step.
  • Fix: preserve tagged errors and source identity through every stage.
  • Quick test: inject one invalid record or failed dependency and verify an explicit result.

Problem 2: Tests merely repeat the implementation

  • Why: assertions reuse the same transformation or state assumptions.
  • Fix: check external invariants, golden fixtures, and observable failure behavior.
  • Quick test: introduce a deliberate ordering or boundary bug and confirm the test fails.

Definition of Done

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • each stage is independently testable and complete output matches golden fixtures.

Project 35: Bank Statement Reconciliation CLI

Source: BEAM-P14. Build an Elixir CLI that normalizes statements, matches transactions, and explains ambiguous records.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Data Transformation, Financial Reconciliation
  • Software or Tool: Elixir, OptionParser, File/Stream
  • Main Book: “Elixir in Action”

What you will build: Build an Elixir CLI that normalizes statements, matches transactions, and explains ambiguous records.

Why it teaches the BEAM ecosystem: It makes you prove that repeated runs produce identical reconciliation and an auditable exception report.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Build an Elixir CLI that normalizes statements, matches transactions, and explains ambiguous records.

Build “reconcile”, a CLI that accepts bank and processor CSV files plus explicit format names. It emits a summary and four reports: matched pairs with explanations, unmatched transactions, duplicates/ambiguities, and malformed-row rejections.

Scope boundary: Do not add a web UI, database, distributed worker, ETS cache, or long-running process. This project teaches core Elixir data modeling and transformation and must not become a smaller version of Projects 34, 35, 36, 39, or 41.

$ mix reconcile --bank fixtures/bank.csv --processor fixtures/gateway.csv --out tmp/run-001
reconciliation_id=run-001
bank_rows=8 processor_rows=7
matched=5 unmatched_bank=1 unmatched_processor=0
duplicates=2 ambiguous=1 rejected=1
bank_total=154230 processor_total=154230 matched_total=149230 currency=BRL
reports=tmp/run-001/{matched,review,rejected,summary}.csv
status=review_required

3.7.1 How to Run

Prepare the two fixture exports, invoke the Mix task with an empty output directory, and inspect both terminal summary and generated reports. Run again into a second directory and compare checksums.

3.7.2 Golden Path Demo

The fixture contains five exact matches, one date-tolerant match, one duplicate processor reference, one unmatched bank fee, and one malformed amount. The report totals account for every row, and every non-exact decision includes a reason.

3.7.3 Exact Terminal Transcript

$ mix reconcile --bank fixtures/bank.csv --processor fixtures/gateway.csv --out tmp/a
matched=6 review=2 rejected=1 status=review_required
$ mix reconcile --bank fixtures/bank.csv --processor fixtures/gateway.csv --out tmp/b
matched=6 review=2 rejected=1 status=review_required
$ shasum -a 256 tmp/a/*.csv tmp/b/*.csv
6d7c... tmp/a/matched.csv
6d7c... tmp/b/matched.csv
1b2a... tmp/a/review.csv
1b2a... tmp/b/review.csv

The Core Question You Are Answering

How can immutable transformations turn messy financial exports into complete, deterministic, and explainable reconciliation evidence?

Concepts You Must Understand First

Understand function clauses and guards, structs versus maps, tagged result tuples, Enum versus Stream, integer money, and stable sorting.

Questions to Guide Your Design

  1. Which source-specific assumptions belong only in adapters?
  2. What is the minimum evidence needed to defend a match?
  3. How will you prove no row disappeared or was matched twice?
  4. Which errors should stop the command, and which should become review records?

Thinking Exercise

Draw a ledger with ten input row ids. Move each id into exactly one final category and circle every decision that consumes two ids. Now introduce two processor rows with the same reference and amount. Explain why choosing the first row is not a defensible rule.

The Interview Questions They Will Ask

  1. When would you use Stream instead of Enum?
  2. How do function clauses and guards improve parser clarity?
  3. Why should money use integers or a decimal type rather than floats?
  4. How would you guarantee deterministic output from map-based indexes?
  5. How does “with” help validation, and when does it become harder to read?
  6. How do you prove a reconciliation conserved all input rows?

Hints in Layers

Hint 1: Make one adapter pass a five-row fixture before designing matching.

Hint 2: Give every accepted or rejected row a stable source-line identity.

Hint 3: Index candidates to lists and keep a separate consumed-id set.

Hint 4: Compute category counts and integer totals before writing any report; reject the run if conservation fails.

Books That Will Help

Topic Book Chapter
Elixir data transformations “Programming Elixir >= 1.6” by Dave Thomas Ch. 5, Anonymous Functions; Ch. 10, Processing Collections
Pattern matching and control flow “Elixir in Action” by Saša Jurić Ch. 2, Building Blocks; Ch. 3, Control Flow
Financial domain modeling “Domain Modeling Made Functional” by Scott Wlaschin Ch. 4, Understanding Types; Ch. 9, A Complete Example

Implementation Milestones

Phase 1: Foundation (2-3 hours)

Define canonical structs and rejection codes; parse one fixture; add deterministic adapter tests.

Phase 2: Core Functionality (3-4 hours)

Build duplicate-preserving indexes, ordered match rules, consumed-id tracking, totals, and category reports.

Phase 3: Polish & Edge Cases (1-3 hours)

Add masked output, atomic writes, large fixtures, ambiguous cases, help text, and reproducibility checks.

Testing Strategy

6.1 Test Categories

  • Adapter unit tests for every row outcome
  • Table-driven money/date normalization tests
  • Rule tests for exact, tolerant, ambiguous, and consumed candidates
  • End-to-end fixture tests with exact report snapshots
  • Invariant tests for row conservation and totals
  • Performance test for the large fixture

6.2 Critical Test Cases

  1. Duplicate candidate keys preserve both rows.
  2. An invalid amount becomes a line-specific rejection.
  3. One processor row cannot satisfy two bank rows.
  4. Reversing input order does not change sorted report bytes.
  5. A report write failure does not leave a mixture of final and partial files.
  6. Negative refunds reconcile with sign preserved.

6.3 Test Data

Keep tiny fixtures for one behavior each, one golden mixed fixture, and a generated 100,000-row dataset containing deterministic duplicates and failures. Use fictional names and identifiers.

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Rows vanish: A parser filtered errors. Return rejection values and assert conservation.

Duplicates collapse: An index stored one value per key. Store a list and test duplicate fixtures.

Totals differ by cents: Floating-point parsing introduced drift. Parse directly to integer minor units.

Reports reorder: Enumeration order leaked into output. Sort by an explicit stable tuple.

7.2 Debugging Strategies

Run one row through every stage and print only safe shape/reason metadata. Add a reconciliation trace keyed by stable row id. When totals fail, calculate differences per source and category before inspecting individual rows.

7.3 Performance Traps

Repeated list concatenation, rescanning all processor rows for every bank row, materializing raw files before validation, and sorting inside matching loops all create avoidable cost. Index once and sort only final categories.

Definition of Done

  • Every input data row is accounted for exactly once.
  • Money is never represented as floating point.
  • Exact and tolerant rules produce explanations.
  • Duplicate and ambiguous rows are preserved for review.
  • Repeated runs produce byte-identical reports.
  • Tests cover malformed input, refunds, duplicates, and atomic output.
  • “mix help reconcile” documents formats, exit codes, and scope.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • repeated runs produce identical reconciliation and an auditable exception report.

Project 36: iCalendar Availability and Conflict Detector

Source: BEAM-P15. Parse calendars, normalize time zones, and report free intervals and conflicts.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Calendars, Interval Algorithms
  • Software or Tool: Elixir Calendar, DateTime, RFC 5545 subset
  • Main Book: “Elixir in Action”

What you will build: Parse calendars, normalize time zones, and report free intervals and conflicts.

Why it teaches the BEAM ecosystem: It makes you prove that DST boundaries, overlaps, and invalid records have deterministic examples.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Parse calendars, normalize time zones, and report free intervals and conflicts.

Build “calcheck”, a CLI accepting two or more ICS files, a reporting timezone, a date range, working hours, meeting duration, and travel buffer. It prints conflicts, unsupported constructs, and available meeting windows.

Scope boundary: Support unfolded VEVENT records with UID, SUMMARY, DTSTART, and DTEND plus a documented set of date-time forms. Detect but do not implement recurrence expansion, alarms, invitations, or full VTIMEZONE interpretation.

$ mix calcheck team.ics customer.ics --from 2026-07-15 --days 2 \
    --zone America/Sao_Paulo --work 09:00-18:00 --duration 45 --travel 15
events=12 accepted=10 unsupported=2
direct_conflicts=1 travel_violations=1
CONFLICT 2026-07-15 14:00-14:30 "Design Review" <> "Customer Call"
BUFFER   2026-07-16 09:00 shortfall=10m after "Airport Transfer"
AVAILABLE
  2026-07-15 10:15-11:00 America/Sao_Paulo
  2026-07-16 15:30-16:15 America/Sao_Paulo
status=review_required

3.7.1 How to Run

Use small hand-auditable fixtures, set the reporting zone explicitly, run the command, then compare output with a manually drawn timeline.

3.7.2 Golden Path Demo

The golden fixture includes adjacent meetings, one direct overlap, one buffer-only violation, one all-day event, one UTC event, and two unsupported recurring events. Availability never crosses busy intervals.

3.7.3 Exact Terminal Transcript

$ mix calcheck fixtures/a.ics fixtures/b.ics --zone Etc/UTC --from 2026-07-15 --days 1
accepted=6 unsupported=2 direct_conflicts=1 travel_violations=1 slots=3
$ echo $?
2
$ mix calcheck fixtures/clean.ics --zone Etc/UTC --from 2026-07-15 --days 1
accepted=4 unsupported=0 direct_conflicts=0 travel_violations=0 slots=4
status=ok

The Core Question You Are Answering

How can Elixir’s temporal types and explicit error values help a small scheduler produce honest answers from complicated calendar data?

Concepts You Must Understand First

Know binary/string splitting, structs, sorting comparators, Date versus DateTime, timezone database boundaries, half-open intervals, and tagged errors.

Questions to Guide Your Design

  1. Which RFC forms are accepted, rejected, or unsupported?
  2. What timezone assumption applies to floating values?
  3. Do touching busy intervals merge, and why?
  4. Does travel buffer block both sides or only after meetings?
  5. Which unsupported input changes the process exit status?

Thinking Exercise

Draw one day as a line and place four events: adjacent, overlapping, contained, and all-day. Expand two with travel buffers. Mark exact direct conflicts, buffer violations, and 45-minute gaps before writing the algorithm.

The Interview Questions They Will Ask

  1. What is the difference between NaiveDateTime and DateTime?
  2. Why do named timezone conversions require a database?
  3. How does a half-open interval simplify overlap logic?
  4. How would you find availability efficiently after sorting?
  5. Why is silently ignoring recurrence dangerous?
  6. How would you test DST ambiguity without depending on the host clock?

Hints in Layers

Hint 1: Begin with UTC DTSTART/DTEND and no recurrence.

Hint 2: Parse generic content lines before interpreting VEVENT properties.

Hint 3: Normalize accepted timed events, then make interval functions unaware of ICS syntax.

Hint 4: Merge busy intervals before generating gaps; keep original events for explanations.

Books That Will Help

Topic Book Chapter
Elixir dates and data “Elixir in Action” by Saša Jurić Ch. 2, Building Blocks; Ch. 3, Control Flow
Functional modeling “Domain Modeling Made Functional” by Scott Wlaschin Ch. 4, Understanding Types; Ch. 6, Domain Integrity
Specification-driven design “Release It!, 2nd Edition” by Michael Nygard Ch. 4, Stability Antipatterns; Ch. 5, Stability Patterns

Implementation Milestones

Phase 1: Foundation (3-4 hours)

Implement unfolding, content-line parsing, UTC/date-only event decoding, and source-aware diagnostics.

Phase 2: Core Functionality (3-5 hours)

Add timezone policy, interval validation, direct conflicts, buffers, busy merging, and free slots.

Phase 3: Polish & Edge Cases (2-3 hours)

Add unsupported recurrence detection, all-day clipping, DST fixtures, deterministic output, and CLI help.

Testing Strategy

6.1 Test Categories

  • Unfolding and escaped-value unit tests
  • Table-driven temporal decoding tests
  • Interval property tests for symmetry and boundaries
  • Golden conflict/availability fixtures
  • Unsupported-feature tests
  • Performance test on sorted and reverse-sorted large calendars

6.2 Critical Test Cases

  1. End-at-10 and start-at-10 are not a direct conflict.
  2. A containing interval conflicts with all contained events.
  3. Unknown TZID never falls back silently.
  4. RRULE produces an explicit unsupported record.
  5. Availability excludes direct busy and buffer-expanded intervals.
  6. Ambiguous DST local time follows the documented policy.

6.3 Test Data

Use one-property parser fixtures, hand-drawn daily timelines, RFC-inspired folded lines, fixed UTC instants, and synthetic DST cases. Never commit private calendar exports.

Common Pitfalls and Debugging

7.1 Frequent Mistakes

False adjacent conflict: Inclusive end logic was used. Adopt half-open intervals consistently.

Events shift by hours: Floating or TZID values were treated as UTC. Trace original form, zone policy, and normalized instant.

Recurring meetings disappear: RRULE was ignored. Make unsupported recurrence visible and affect status.

Parser breaks on valid input: Folded lines were parsed before unfolding.

7.2 Debugging Strategies

Render normalized intervals beside original temporal text and UID. For a conflict, print the two predicates used by the overlap rule. For missing slots, print merged busy ranges after clipping to working hours.

7.3 Performance Traps

Comparing every event with every other event, repeatedly converting the same timezone values, and subtracting unmerged busy intervals create avoidable work. Normalize once, sort once, and merge once.

Definition of Done

  • The supported iCalendar subset is explicit.
  • Every unsupported construct is reported with source context.
  • Temporal forms are represented by appropriate Elixir types.
  • Direct conflicts and buffer violations are distinct.
  • Availability is verified against hand-drawn golden timelines.
  • Output records timezone assumptions and is deterministic.
  • Tests cover boundaries, containment, all-day events, and DST policy.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • DST boundaries, overlaps, and invalid records have deterministic examples.

Project 37: Duplicate File Quarantine Planner

Source: BEAM-P16. Lazily scan and hash files, then emit a reversible quarantine plan.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Filesystems, Safety, Integrity
  • Software or Tool: File, Path, Stream, :crypto
  • Main Book: “The Pragmatic Programmer”

What you will build: Lazily scan and hash files, then emit a reversible quarantine plan.

Why it teaches the BEAM ecosystem: It makes you prove that large trees remain memory-bounded and every proposed move is explainable.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Lazily scan and hash files, then emit a reversible quarantine plan.

Build “dupeplan”, a CLI with “scan”, “apply”, and “rollback” modes. Scan emits a human summary and machine-readable plan. Apply consumes that exact plan. Rollback consumes the completed-action journal.

Scope boundary: Do not delete duplicates permanently, follow symlinks, build a GUI, monitor directories continuously, or distribute work. The product is a local safety planner, distinct from every existing P1-P13 service.

$ mix dupeplan scan ~/Documents --quarantine ~/Documents/.quarantine --plan tmp/plan.json
files=1842 candidate_bytes=812441600 hashed_files=96
duplicate_groups=14 duplicate_files=19 reclaimable_bytes=32498112
skipped_symlinks=3 errors=1
plan_id=sha256:81be... actions=19 mode=dry_run

$ mix dupeplan apply tmp/plan.json
applied=18 skipped_changed=1 failed=0 journal=tmp/plan.applied.json

3.7.1 How to Run

Use a temporary fixture tree containing known duplicate and unique files. Scan, inspect the plan, apply, confirm keeper/content, then rollback and compare the full tree inventory with the original.

3.7.2 Golden Path Demo

The fixture has three duplicate groups, a same-name nonduplicate, a symlink, and one file modified after scan. Apply moves eligible duplicates, skips the changed file, and rollback restores all completed moves.

3.7.3 Exact Terminal Transcript

$ mix dupeplan scan test/fixtures/tree --quarantine tmp/q --plan tmp/p.json
files=9 duplicate_groups=3 actions=4 reclaimable_bytes=12288 errors=0
$ mix dupeplan apply tmp/p.json
applied=3 skipped_changed=1 failed=0
$ mix dupeplan rollback tmp/p.applied.json
restored=3 conflicts=0 failed=0 status=restored

The Core Question You Are Answering

How can an immutable Elixir plan make inherently mutable filesystem cleanup reviewable, deterministic, and reversible?

Concepts You Must Understand First

Understand recursion, Stream.resource or comparable lazy production, File versus Path, crypto hash state, maps of lists, stable sorting, tagged results, and atomic-write concepts.

Questions to Guide Your Design

  1. What is proof of duplicate identity?
  2. Which paths may traversal enter?
  3. Which preconditions must still hold before a move?
  4. How are destination collisions impossible by construction?
  5. What can rollback promise after external changes?

Thinking Exercise

Draw a timeline where a file is scanned, hashed, modified, and then applied. Mark which observations are stale and which revalidation catches them. Repeat with a process crash after the second of four moves.

The Interview Questions They Will Ask

  1. How would you recursively traverse while handling errors as values?
  2. Why use lazy streams for file content?
  3. What is a TOCTOU race?
  4. Why is size-plus-hash grouped in two phases?
  5. How do you make dry-run and apply behavior consistent?
  6. What makes rollback safe but necessarily conditional?

Hints in Layers

Hint 1: Build an inventory command before hashing anything.

Hint 2: Group by size and hash only nonsingletons.

Hint 3: Make a plan a value with no File mutation functions inside the planner.

Hint 4: At apply, compare current facts to recorded preconditions and journal after each successful move.

Books That Will Help

Topic Book Chapter
Elixir collections and files “Programming Elixir >= 1.6” by Dave Thomas Ch. 10, Processing Collections; Ch. 12, Control Flow
Failure-aware design “Release It!, 2nd Edition” by Michael Nygard Ch. 4, Stability Antipatterns; Ch. 5, Stability Patterns
Domain types and workflows “Domain Modeling Made Functional” by Scott Wlaschin Ch. 4, Understanding Types; Ch. 7, Modeling Workflows

Implementation Milestones

Phase 1: Foundation (3-4 hours)

Build fixture-safe traversal, observation structs, exclusion policy, size grouping, and chunked hashes.

Phase 2: Core Functionality (3-5 hours)

Create duplicate groups, deterministic keepers, collision-free actions, plan serialization, and dry-run rendering.

Phase 3: Polish & Edge Cases (2-3 hours)

Add revalidation, journals, rollback, changed-file tests, interrupted apply simulation, and performance metrics.

Testing Strategy

6.1 Test Categories

  • Walker tests for regular, symlink, error, and vanished entries
  • Fingerprint tests for empty, large, and equal files
  • Planner invariant and deterministic-order tests
  • Apply precondition tests in temporary directories
  • Rollback conflict and reverse-order tests
  • End-to-end inventory-before/after tests

6.2 Critical Test Cases

  1. Same name with different bytes never groups.
  2. Same bytes with different names groups.
  3. A file changed after scan is skipped.
  4. Existing destination is never overwritten.
  5. Quarantine nested under root is rejected.
  6. Partial apply journal rolls back only completed moves.
  7. Rollback refuses an occupied original path.

6.3 Test Data

Generate fixture bytes deterministically, including zero-byte files, large chunk-boundary files, same-size nonduplicates, duplicate trees, symlinks, and permission-restricted entries where portable.

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Infinite traversal: Symlinks were followed. Classify links and skip by default.

Memory spike: Whole files were read at once. Stream fixed-size chunks into hash state.

Wrong file moved: Scan evidence was trusted during apply. Revalidate size/digest.

Lost quarantine file: Destination collision overwrote it. Reserve and reject collisions before mutation.

7.2 Debugging Strategies

Render every stage for one relative path: observation, fingerprint, group, keeper decision, action, revalidation, journal. Compare plan id and normalized roots when reproducing differences.

7.3 Performance Traps

Hashing all files, repeatedly reading metadata, list concatenation in recursion, sorting per directory, and byte-comparing every candidate waste I/O or CPU. Filter by size, accumulate efficiently, and sort once.

Definition of Done

  • Traversal records errors without aborting unrelated roots.
  • Hashing is chunked and bounded.
  • Plans select one keeper and reserve unique destinations.
  • Dry-run and apply use the identical plan.
  • Changed sources and occupied destinations are not moved.
  • Completed actions can be rolled back conditionally.
  • No command deletes or overwrites user files.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • large trees remain memory-bounded and every proposed move is explainable.

Project 38: Fixed-Width Settlement Parser and Property Lab

Source: BEAM-P18. Build a binary-pattern parser with checksums and property-based round-trip tests.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Binary Parsing, Verification
  • Software or Tool: Bitstrings, ExUnit, StreamData
  • Main Book: “Elixir in Action”

What you will build: Build a binary-pattern parser with checksums and property-based round-trip tests.

Why it teaches the BEAM ecosystem: It makes you prove that malformed generated records shrink to useful counterexamples.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Build a binary-pattern parser with checksums and property-based round-trip tests.

Build “settlecheck”, a library and CLI for an invented but realistic 80-byte header/detail/trailer format. It prints accepted settlement totals or line-specific structural, field, sequencing, and trailer errors.

Scope boundary: Implement only the versioned fixture specification. Do not claim compatibility with a real payment network, process money, persist records, distribute parsing, or build a GenStage pipeline.

$ mix settlecheck fixtures/settlement-ok.txt
settlement_id=20260715A records=4 details=2
currency=BRL declared_total=125050 calculated_total=125050
status=accepted

$ mix settlecheck fixtures/settlement-bad.txt
line=3 code=invalid_amount field=amount value="00A01000"
line=5 code=trailer_count_mismatch declared=3 calculated=2
status=rejected errors=2

3.7.1 How to Run

Run golden valid/invalid fixtures, then execute focused property tests with a reproducible seed. Preserve the smallest counterexample when deliberately injecting a parser bug.

3.7.2 Golden Path Demo

A valid file with two details is accepted. Corrupted variants for each field and file invariant are rejected with exact codes. Generated arbitrary binaries never raise.

3.7.3 Exact Terminal Transcript

$ mix test test/settlecheck_property_test.exs --seed 4242
property valid settlements round-trip
property arbitrary bounded binaries never crash
property corrupted trailer totals are rejected
property duplicate ids are rejected
4 properties, 0 failures

$ mix settlecheck fixtures/bad-trailer.txt
line=4 code=trailer_total_mismatch declared=120000 calculated=125050
status=rejected

The Core Question You Are Answering

How can binary patterns and properties prove that a parser both accepts valid settlement data and rejects malformed or dishonest files without crashing?

Concepts You Must Understand First

Understand binary versus bitstring, byte_size, sized binary segments, guards, integer/date conversion results, recursive state, ExUnit assertions, generators, properties, classification, and shrinking.

Questions to Guide Your Design

  1. Which checks are structural, field-semantic, or file-semantic?
  2. Can parsing continue safely after a malformed record?
  3. What does accepted status require at EOF?
  4. Which properties are independent of the renderer?
  5. How will generators exercise each corruption family?

Thinking Exercise

Write an 80-column ruler and place every detail field under it. Manually change one byte at each boundary and predict the outcome. Then draw the parser phases before-header, details, and after-trailer with valid/invalid transitions.

The Interview Questions They Will Ask

  1. How does binary pattern matching differ from string slicing?
  2. Why separate extraction from semantic validation?
  3. How would you avoid exceptions from integer conversion?
  4. What makes a good property versus a large example test?
  5. How does shrinking help diagnose failures?
  6. Why can round-trip tests preserve a shared encoder/decoder bug?

Hints in Layers

Hint 1: Parse one exact detail record into raw fields.

Hint 2: Give every field validator one stable result/error contract.

Hint 3: Make file sequence and totals one explicit parser state.

Hint 4: Generate valid structs first, derive trailers, render late, and mutate one named rule at a time.

Books That Will Help

Topic Book Chapter
Binaries and pattern matching “Programming Elixir >= 1.6” by Dave Thomas Ch. 6, Modules and Named Functions; Ch. 11, Strings and Binaries
Testing discipline “Test Driven Development: By Example” by Kent Beck Part I, The Money Example; Ch. 25, Test-Driven Development Patterns
Integration contracts “Enterprise Integration Patterns” by Hohpe and Woolf Ch. 3, Messaging Systems; Ch. 4, Messaging Channels

Implementation Milestones

Phase 1: Foundation (4-5 hours)

Write format table, domain structs, exact record decoders, validators, and golden examples.

Phase 2: Core Functionality (4-6 hours)

Implement parser state, totals/sequence/duplicate invariants, CLI output, and domain renderer.

Phase 3: Polish & Edge Cases (4-7 hours)

Add structured generators, named corruptions, shrinking-friendly properties, parser limits, and performance checks.

Testing Strategy

6.1 Test Categories

  • Exact offset/decoder unit tests
  • Table-driven field validator tests
  • File grammar/invariant tests
  • Golden protocol fixtures
  • Valid-domain round-trip properties
  • Named corruption rejection properties
  • Arbitrary bounded-binary safety property

6.2 Critical Test Cases

  1. Every field boundary accepts exact width and rejects off-by-one records.
  2. Non-ASCII bytes in ASCII fields reject.
  3. Duplicate ids never disappear through a map overwrite.
  4. False trailer count/total reject.
  5. Detail after trailer rejects.
  6. Arbitrary bounded input never raises.
  7. Generated zero-detail valid settlement follows the specified policy.

6.3 Test Data

Maintain a field-boundary fixture matrix, valid one/two/many-detail files, each grammar violation, numeric boundaries, and generated structured records. Record the seed for any failure.

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Offsets drift: Fields were trimmed/split before width matching. Match exact bytes first.

Unicode surprise: Character length was used for a byte protocol. Declare and enforce encoding.

Parser crashes: Bang conversions were used on untrusted fields. Convert through tagged results.

Properties pass trivially: Generator never produces meaningful data or parser accepts everything. Classify cases and assert semantics.

7.2 Debugging Strategies

Print a byte-offset ruler with safe hex for the failing record. Preserve line, tag, and field in every error. Replay property failures with seed and shrunk counterexample before adding another example.

7.3 Performance Traps

Repeated binary concatenation, copying entire files, retaining all details when only summary is needed, and unbounded generators cause waste. Parse line by line and choose retention deliberately.

Definition of Done

  • The 80-byte format is documented independently of code.
  • Structural, semantic, and file-level errors are distinct.
  • Accepted totals/counts exactly match the trailer.
  • Public parsing never raises for bounded arbitrary binaries.
  • Valid settlements round-trip canonically.
  • Targeted corruptions are classified and rejected.
  • Smallest failing seeds are reproducible.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • malformed generated records shrink to useful counterexamples.

Project 39: Executable Interactive Field Report

Sources: LIVE-P1, LIVE-P2. Build a replayable Livebook report with validated Kino inputs and visible provenance.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang cells; Python integration for comparison only
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Literate programming, functional transformations, reproducibility
  • Software or Tool: Livebook, ExUnit, Git
  • Main Book: Elixir in Action, Third Edition

What you will build: Build a replayable Livebook report with validated Kino inputs and visible provenance.

Why it teaches the BEAM ecosystem: It makes you prove that a fresh runtime reproduces the result and invalid input cannot mislead.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Integrated Scope

This is one consolidated project, not separate source builds. Implement the following contributions as phases of the same artifact:

  • Start with LIVE-P1 reproducibility: explicit inputs, cell ancestry, replay evidence, and invariant checks.
  • Fold in LIVE-P2 as Kino controls, validated scenarios, and an interactive result without creating a second notebook.

Real World Outcome

Build target: Build a replayable Livebook report with validated Kino inputs and visible provenance.

Create one .livemd notebook named energy-field-report.livemd. It will contain:

  1. A title, purpose, report period, assumptions, units, and declared scope.
  2. A setup section that declares dependencies and displays the runtime baseline.
  3. A committed six-row appliance fixture with watts, daily hours, days used, and efficiency factor.
  4. A boundary-validation section that reports every invalid row with stable row identity.
  5. Named Elixir modules or clearly named pure functions for normalization, usage calculation, cost calculation, scenario comparison, and verification.
  6. A baseline scenario and an efficient scenario using the same validated readings.
  7. A human-readable report with totals, cost, savings, and independent PASS/FAIL checks.
  8. A provenance manifest suitable for review in Git.
  9. A clean-runtime replay procedure and recorded transcript.

The notebook is the report, but the core calculation must not depend on notebook UI state. A reviewer should be able to read each stage, trace the formula, and identify exactly which input produced each output.

The learner opens the notebook, evaluates the setup and fixture sections, then evaluates the report section. The report renders this exact reference transcript:

ENERGY AUDIT — JULY 2026
Input rows: 6          Tariff: R$ 0.91/kWh
Baseline: 184.2 kWh    Estimated cost: R$ 167.62
Efficient scenario: 141.7 kWh   Savings: R$ 38.68 (23.1%)

Verification
[PASS] total = sum(appliance totals)
[PASS] no negative hours or watts
[PASS] baseline - efficient = reported savings
[PASS] clean-runtime replay

An invalid fixture does not produce a misleading partial report. It produces a structured summary such as:

REPORT BLOCKED — INPUT CONTRACT FAILED
row=3 appliance="dryer" field=daily_hours value=27 reason=outside_0_to_24
row=5 appliance="freezer" field=watts value=-80 reason=must_be_non_negative
Accepted rows: 4
Rejected rows: 2
Calculation status: NOT RUN

When you open the finished file in Livebook, the first screen explains what is being estimated and what is deliberately not claimed. A compact input table lists the six appliances and units. A validation card immediately below states whether the fixture is admissible. The calculation section presents a small stage-by-stage table: energy per appliance, baseline total, efficient total, cost, and savings.

The final report is not merely a chart or a number. It includes a verification panel in which every invariant is independently labeled. A manifest panel identifies the exact snapshot and execution environment. If you edit the tariff cell, the report cells below become visibly stale until you evaluate their dependency branch. If you reconnect the runtime, old bindings disappear; evaluating from the beginning reconstructs the same result and changes the replay check from pending to PASS.

The repository diff contains the narrative, fixture, formulas expressed as readable Elixir, and validation expectations. It does not contain machine-specific paths, transient timestamps used as evidence, hidden secrets, or unexplained generated data. A reviewer can reproduce both the valid report and the blocked invalid-input state without asking the author for missing instructions.

The Core Question You Are Answering

“What must an executable document declare so another person can reconstruct both its reasoning and its result?”

Before implementing, list everything the current result depends on. Classify each dependency as source-controlled input, declared package, runtime fact, operator choice, or accidental hidden state. Your design is complete only when accidental hidden state is empty and every operator choice is visible in the report.

Concepts You Must Understand First

Stop and research these before building the report:

  1. Immutable data and rebinding
    • How can a name change without a value being mutated?
    • Why are distinct stage names clearer than repeatedly rebinding data?
    • Book Reference: Elixir in Action, 3rd ed., Chapters 2–3.
  2. Pattern matching and tagged outcomes
    • What information belongs in OK(value) versus ERROR(reasons)?
    • Which invalid inputs are expected domain outcomes rather than exceptional crashes?
    • Book Reference: Programming Elixir 1.6, Chapters 4–7.
  3. Livebook evaluation model
    • Which bindings and module definitions reach a cell?
    • What does the stale indicator prove, and what does it not prove?
    • Primary Reference: Introduction to Livebook.
  4. Units and rounding
    • At which exact step do watt-hours become kilowatt-hours?
    • Why should currency be rounded at one boundary?
  5. Reproducibility and provenance
    • Which inputs must be snapshotted rather than fetched live?
    • How will a checksum and formula revision help later review?

Questions to Guide Your Design

  1. Which cells are narrative, setup, input, domain logic, verification, and presentation?
  2. Which values have physical units, and are those units visible in names and output?
  3. Does validation report all actionable row errors or stop after the first?
  4. Is the efficient scenario derived from immutable baseline readings or from already rounded output?
  5. Can the invariant calculations detect a stale cost after the tariff changes?
  6. What exact information must be in the manifest for a reviewer six months later?
  7. What happens when baseline usage is zero and percentage savings would divide by zero?
  8. Does a reconnect reconstruct modules, bindings, results, and verification without manual memory?

Thinking Exercise

Draw the notebook dependency graph on paper. Include nodes for fixture, tariff, validation, baseline calculation, efficient calculation, cost, report, invariants, and manifest. Draw arrows only where data is truly required.

Then simulate these edits without running anything:

  1. Change only the report title. Which cells should become stale?
  2. Change tariff from 0.91 to 0.95. Which outputs and invariants must change?
  3. Change one appliance’s efficiency factor. Should the baseline move?
  4. Remove the cell defining the calculator module and reconnect. Where should evaluation fail?
  5. Add an invalid negative wattage. Should any cost total be presented as valid?

Compare your prediction with Livebook’s actual stale-cell behavior and record discrepancies.

The Interview Questions They Will Ask

  1. “How does rebinding in Elixir differ from mutation?”
  2. “Why can a notebook show a plausible but stale result?”
  3. “What makes a computational report reproducible?”
  4. “Why put core logic in named functions or modules instead of a long cell?”
  5. “How do invariants differ from golden-output tests?”
  6. “Where should rounding occur in a calculation involving physical estimates and currency?”

Hints in Layers

Hint 1: Write the report contract first. Define the final fields, units, and failure states before calculating anything.

Hint 2: Preserve transformation stages. Keep raw, validated, baseline, efficient, and verified conceptually distinct.

Hint 3: Make invalid data boring. Expected input defects should become stable tagged errors that the report can render.

Hint 4: Verify with different arithmetic paths. Do not prove a total by comparing a value with itself after formatting.

Hint 5: Reconnect early. A clean runtime in the first hour reveals hidden bindings before the notebook becomes large.

Books That Will Help

Topic Book Chapter
Elixir values and control flow Elixir in Action, 3rd ed., Saša Jurić Chapters 2–4
Functions, modules, pattern matching Programming Elixir 1.6, Dave Thomas Chapters 4–7
Reproducible engineering practice The Pragmatic Programmer, 20th Anniversary ed. Orthogonality, tracer bullets, automation
Testing properties and invariants Property-Based Testing with PropEr, Erlang, and Elixir Foundations and property design chapters

Implementation Milestones

Integrated basic-to-advanced progression

  1. Start with LIVE-P1 reproducibility: explicit inputs, cell ancestry, replay evidence, and invariant checks.
  2. Fold in LIVE-P2 as Kino controls, validated scenarios, and an interactive result without creating a second notebook.

Milestone 1 — Contract and fixture: define one representative input, output, invariant, and failure case.

Milestone 2 — Core artifact: Build a replayable Livebook report with validated Kino inputs and visible provenance.

Milestone 3 — Failure behavior: add timeouts, invalid inputs, crashes, retries, or partitions appropriate to the project.

Milestone 4 — Evidence: automate the definition of done and record a reproducible result.

Phase 1: Foundation (1.5–2 hours)

Goals: Define the contract and obtain one transparent baseline calculation.

Tasks:

  1. Create the notebook outline and record versions, period, tariff, units, and assumptions.
  2. Add the six-row fixture and a separate invalid fixture.
  3. Write the validation-result and domain-record schemas in prose or pseudocode.
  4. Calculate one appliance by hand and record the expected unit conversion.

Checkpoint: A reviewer can predict the baseline formula and identify every input without evaluating the notebook.

Phase 2: Core Functionality (2.5–3.5 hours)

Goals: Implement pure validation, scenarios, report assembly, and independent checks.

Tasks:

  1. Build parsing and accumulated validation around stable row identity.
  2. Implement baseline and efficient calculations as pure transformations.
  3. Add the valid report, blocked report, and zero-baseline state.
  4. Add aggregation, range, cost, and savings invariants.

Checkpoint: Valid input matches the reference transcript; invalid input displays all seeded errors and no valid-looking total.

Phase 3: Polish & Edge Cases (1–2.5 hours)

Goals: Prove replay, reviewability, and resilience to edits.

Tasks:

  1. Add the manifest and stable fixture checksum.
  2. Exercise tariff edits and document stale descendants.
  3. Reconnect to a clean runtime and evaluate in document order.
  4. Review the Git diff for noise, hidden paths, and accidental secrets.

Checkpoint: A clean clone and runtime reproduce all PASS checks using the written instructions alone.

Testing Strategy

6.1 Test Categories

Category Purpose Examples
Pure calculation tests Verify formulas independent of Livebook one appliance, six-row totals, zero baseline, efficiency extremes
Validation tests Prove boundary policy blank name, negative watts, 25 hours/day, non-numeric tariff
Invariant tests Detect internal inconsistency sum of rows, cost relation, baseline minus efficient savings
Notebook integration tests Verify cell ancestry and rendering stale tariff descendants, blocked state, module setup
Replay tests Expose hidden dependencies reconnect, clean clone, top-to-bottom evaluation
Review/security tests Protect artifacts absolute-path scan, secret scan, stable diff

6.2 Critical Test Cases

  1. Reference fixture: Six valid rows produce exactly 184.2 kWh, R$ 167.62, 141.7 kWh, and R$ 38.68 savings under the declared policy.
  2. Multiple invalid fields: One row with negative watts and 27 daily hours reports both defects and blocks calculation.
  3. Tariff edit: Changing tariff marks cost/report descendants stale while usage remains conceptually unchanged.
  4. Zero baseline: Savings percentage renders as not applicable or a documented zero case; it never divides by zero.
  5. Rounding edge: Values near a half-cent follow one named rounding rule and reconcile.
  6. Clean runtime: Reconnect removes current modules and bindings; document-order replay restores all results.
  7. Missing setup: Evaluating a downstream calculation before its definitions gives an understandable dependency failure, not silently reused state.

6.3 Test Data

CASE valid_reference
rows=6 tariff=0.91
expected baseline_kwh=184.2
expected baseline_cost_r=167.62
expected efficient_kwh=141.7
expected savings_r=38.68
expected checks=all_PASS

CASE invalid_accumulation
row=3 watts=-80 daily_hours=27
expected reasons=[must_be_non_negative, outside_0_to_24]
expected calculation_status=NOT_RUN

CASE zero_baseline
all daily_hours=0
expected baseline_kwh=0
expected savings_percent=NOT_APPLICABLE

CASE replay
action=reconnect_then_evaluate_document_order
expected stable_output_relation=equal_to_committed_baseline

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Pitfall Symptom Solution
Hidden prior binding Notebook fails only after reconnect Move every definition and input into an evaluated ancestor cell
Stale descendant Old cost remains visible after tariff edit Follow stale markers and re-evaluate the affected branch
Unit confusion Totals are 1,000× too large or small Name units and centralize watt-hour to kWh conversion
Repeated rounding Savings differs by a cent Declare one currency rounding boundary and test reconciliation
Silent row filtering Report total looks plausible with fewer rows Block or explicitly quarantine invalid rows and reconcile counts
Incidental nondeterminism Manifest changes on every replay Separate useful provenance from wall-clock noise

7.2 Debugging Strategies

  • Shrink to one appliance: Verify units and hand arithmetic before debugging aggregation.
  • Inspect stage shapes: Render raw, validation result, and domain values separately without mixing presentation strings into the core.
  • Force a reconnect: Treat a new runtime as a diagnostic tool for hidden state.
  • Change one ancestor: Edit tariff or a single reading and predict the stale branch before evaluating.
  • Compare manifests: A changed output with unchanged input hash suggests runtime, formula, or nondeterministic behavior changed.

7.3 Performance Traps

Performance is not a major constraint at six rows, but dependency installation can dominate replay. Keep dependencies minimal. Avoid fetching remote data merely to make the report look realistic. Do not repeatedly hash huge serialized terms in every presentation cell; compute stable provenance once from canonical input.

Definition of Done

Minimum Viable Completion:

  • One .livemd report evaluates a committed six-row fixture into baseline and efficient totals.
  • Expected input failures are represented explicitly and block misleading calculations.
  • At least four independent verification checks are visible.
  • A reconnect followed by document-order evaluation reproduces the reference output.

Full Completion:

  • All minimum criteria plus:
  • The manifest records checksum, report period, assumptions, formula revision, versions, and verification status.
  • Invalid, zero-baseline, tariff-edit, rounding, and missing-setup cases are tested.
  • A clean clone reproduces the result without machine-specific instructions.
  • The notebook reads as a coherent short report, not a sequence of unexplained cells.

Excellence (Going Above & Beyond):

  • Property-based tests verify range, aggregation, and scenario relationships across generated fixtures.
  • Core domain modules and ExUnit tests are extracted to a small Mix project while the notebook remains the narrative interface.
  • CI verifies the supported Elixir/OTP baseline and compares stable output evidence.
  • A second person successfully reproduces the report and records an independent review.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • Every merged source contribution is implemented as a phase of this one artifact, not as a separate project.
  • a fresh runtime reproduces the result and invalid input cannot mislead.

Project 40: Livebook Data Triage and Mobility Pipeline

Sources: LIVE-P3, LIVE-P5. Turn messy CSV into a contract-aware Explorer pipeline and Parquet artifact.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: SQL; Python integration for result comparison
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: DataFrames, lazy queries, data quality, columnar formats
  • Software or Tool: Livebook, Explorer, KinoExplorer, Parquet
  • Main Book: Data Science for Business

What you will build: Turn messy CSV into a contract-aware Explorer pipeline and Parquet artifact.

Why it teaches the BEAM ecosystem: It makes you prove that schema drift is explicit and lazy plans remain inspectable.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Integrated Scope

This is one consolidated project, not separate source builds. Implement the following contributions as phases of the same artifact:

  • Use LIVE-P3 to profile and normalize the messy CSV contract before transformation.
  • Extend that same pipeline with LIVE-P5 lazy Explorer stages and a portable Parquet artifact.

Real World Outcome

Build target: Turn messy CSV into a contract-aware Explorer pipeline and Parquet artifact.

Create a Livebook notebook that ingests a snapshot of city trip records plus a zone dimension, validates both against declared contracts, separates rejected rows, enriches accepted trips, computes service metrics lazily, and writes three artifacts:

  1. mobility-clean.parquet — accepted, normalized, enriched trips.
  2. mobility-quarantine.parquet — rejected records with one or more machine-readable reason codes.
  3. mobility-run-manifest.json — source identity, policy version, schemas, reconciliation counts, join evidence, collection boundary, and output checksums.

The pipeline should compute a bounded daily_zone_summary before collection. Keep raw and accepted trip rows out of an eager notebook result unless a deliberately small sample is requested.

The notebook’s final evidence panel should resemble this transcript:

CITY MOBILITY PIPELINE
Source rows: 2,400,000
Accepted rows: 2,372,814
Quarantined rows: 27,186
Row reconciliation: PASS
Zone join unmatched keys: 43
Collection boundary: daily_zone_summary (3,648 rows)
Output: mobility-clean.parquet
Manifest checksum: sha256:REDACTED_EXAMPLE

Add a validation table such as:

CHECK                         EXPECTED              OBSERVED             STATUS
trip_id dtype                 string                string               PASS
zone dimension uniqueness    duplicate keys = 0    0                    PASS
row reconciliation            2,400,000             2,400,000            PASS
post-join row count           2,372,814             2,372,814            PASS
collected summary rows        <= 5,000              3,648                PASS

This is illustrative output, not hard-coded expected data. Your fixture generator or supplied snapshot must define its own known truth.

A reviewer can open the notebook and answer, without inspecting hidden state:

  • What source snapshot was processed?
  • What schema did the reader infer, and where did it differ from the contract?
  • Why did each rejected row fail?
  • Did enrichment preserve the accepted trip population?
  • How many rows crossed the collection boundary?
  • Which exact artifacts were written, and how can their identity be verified?

The result is a small analytical data product rather than a one-off chart. Another operator can replay the run, verify the manifest, and use the Parquet outputs without trusting the original author’s memory.

The Core Question You Are Answering

Where does an analytical pipeline actually execute, and what evidence proves no rows or meanings disappeared?

Annotate the notebook with execution boundaries. Identify which cells construct expressions, which trigger scans or aggregations, which materialize results, and which write persistent artifacts. Then associate each semantic risk—dtype, timezone, rejection, join cardinality—with an explicit piece of evidence.

Concepts You Must Understand First

Before implementing, be able to explain:

  1. Why an identifier may need a string dtype even when every observed value is numeric.
  2. The difference between a lazy dataframe plan and a collected dataframe.
  3. Why a left join can multiply rows.
  4. The difference between a rejected record and a missing record.
  5. Why a byte checksum and a logical-content checksum answer different questions.
  6. How Parquet projection and partitioning can reduce work without changing results.

Recommended reading: the Explorer DataFrame and introductory guides, plus the chapters on data representation and evaluation in Data Science for Business.

Questions to Guide Your Design

  • Which timestamp fields are UTC, localized, or timezone-naive at the source?
  • Is a negative duration always invalid, or can an upstream clock correction explain it?
  • Which errors are safe to normalize, which require quarantine, and which should abort the entire run?
  • Is an unmatched zone rejected, retained as unknown, or reported in a separate exception product?
  • What proves the zone dimension is valid for the trip snapshot’s effective date?
  • What is the maximum acceptable collected row count, and who sets it?
  • Should checksums cover file bytes, canonical sorted logical rows, or both?
  • Which manifest fields are operational metadata and therefore expected to differ across replays?

Thinking Exercise

Trace five adversarial rows through the system:

  1. A valid trip crossing midnight UTC.
  2. A trip with local timestamps around a daylight-saving transition.
  3. A trip whose pickup zone occurs twice in the dimension.
  4. A trip with a missing identifier and negative duration.
  5. A valid trip whose zone was retired before the snapshot date.

For each row, write its dtype interpretation, normalization, validation reasons, final partition, join behavior, and manifest evidence. Then ask: could a reviewer distinguish “no matching zone” from “zone data failed to load”?

The Interview Questions They Will Ask

  1. What is lazy execution, and where would you place a collection boundary in this pipeline?
  2. How do you detect and prevent accidental many-to-many joins?
  3. Why is row-count reconciliation necessary but insufficient for data correctness?
  4. How would you make a dataframe pipeline reproducible across dependency upgrades?
  5. What information belongs in a data-product manifest?
  6. How would you investigate a checksum mismatch when counts and schemas still match?

Hints in Layers

Hint 1 — Make the contract visible. Render declared and inferred schemas side by side before applying casts.

Hint 2 — Build reason expressions independently. Give every rule a stable identifier and count it before splitting the frame.

Hint 3 — Guard the dimension first. Abort enrichment if the intended unique key is duplicated; do not try to detect multiplication after publishing output.

Hint 4 — Aggregate before collection. Filter, group, and summarize while lazy; collect only the small daily-zone result.

Hint 5 — Test replayability. Use an immutable fixture, stable policy version, deterministic ordering, and a clearly defined checksum basis.

Pseudocode sketch:

observed = inspect_schema(source)
assert_compatible(observed, declared_contract)
classified = attach_reason_codes(normalize(source, policy))
accepted, quarantine = partition(classified)
assert_reconciled(source, accepted, quarantine)
assert_unique(zone_dimension, zone_id)
enriched = guarded_join(accepted, zone_dimension)
summary = enriched |> lazy_group_and_summarize |> collect_bounded
publish_only_if_all_assertions_pass()

Books That Will Help

Topic Book Suggested focus
Data contracts and analytical validity Data Science for Business — Provost & Fawcett Data, measurement, leakage, and evaluation
Reliable pipelines Designing Data-Intensive Applications — Martin Kleppmann Encoding, batch processing, derived data
Dimensional modeling The Data Warehouse Toolkit — Ralph Kimball and Margy Ross Fact grain, dimensions, slowly changing dimensions
Elixir data workflows Elixir in Action — Saša Jurić Immutable transformations and process/runtime fundamentals

Implementation Milestones

Integrated basic-to-advanced progression

  1. Use LIVE-P3 to profile and normalize the messy CSV contract before transformation.
  2. Extend that same pipeline with LIVE-P5 lazy Explorer stages and a portable Parquet artifact.

Milestone 1 — Contract and fixture: define one representative input, output, invariant, and failure case.

Milestone 2 — Core artifact: Turn messy CSV into a contract-aware Explorer pipeline and Parquet artifact.

Milestone 3 — Failure behavior: add timeouts, invalid inputs, crashes, retries, or partitions appropriate to the project.

Milestone 4 — Evidence: automate the definition of done and record a reproducible result.

Phase 1 — Contract and fixtures (2–3 hours)

  • Create a small deterministic fixture with known valid and invalid rows.
  • Declare trip and zone schemas, units, nullability, and timezone assumptions.
  • Define expected counts and known join behavior.

Phase 2 — Profiling and validation (3–4 hours)

  • Compare inferred and declared dtypes.
  • Add validation reason codes and the quarantine split.
  • Prove row reconciliation on fixtures and the full snapshot.

Phase 3 — Join and lazy metrics (3–5 hours)

  • Validate dimension uniqueness.
  • Add guarded enrichment and pre/post count checks.
  • Build lazy daily-zone metrics and enforce the bounded collection threshold.

Phase 4 — Artifacts and replay (3–5 hours)

  • Write Parquet outputs and manifest.
  • Re-read output metadata and compute checksums.
  • Replay from a fresh runtime and compare stable evidence.

Phase 5 — Failure demonstration (1–3 hours)

  • Introduce duplicate dimension keys, timezone defects, and premature collection.
  • Capture the expected failed checks and document the diagnosis path.

Testing Strategy

6.1 Test Categories

Use tests at four levels.

The suite combines contract fixtures, property and invariant checks, failure injection, and deterministic replay. Together they verify both the transformation result and the evidence needed to trust it.

6.2 Critical Test Cases

Contract fixtures

Case Expected result
Numeric-looking string identifier Remains string
Missing required trip ID Quarantined with stable reason
End before start Quarantined or repaired only by explicit policy
Coordinate outside valid bounds Quarantined
Unknown optional category Policy-defined sentinel or quarantine

Property and invariant tests

  • For every run, source = accepted + quarantined.
  • Every quarantined row has at least one recognized reason code.
  • Every accepted row satisfies every required predicate.
  • Zone uniqueness is proven before the join.
  • When dimension keys are unique, enrichment does not change accepted row count.
  • Collected summary rows never exceed the configured bound.

Failure-injection tests

  1. Duplicate one zone key and verify publication stops before the join.
  2. Remove a required column and verify a contract error, not a downstream null surprise.
  3. Inject daylight-saving ambiguity and verify the timezone policy decides it explicitly.
  4. Corrupt a Parquet output and verify its checksum fails.
  5. Change rule ordering and confirm the chosen reason-code representation remains deterministic.
  6. Force an unbounded collection request and verify the guard rejects it.

Replay test

Run from a fresh Livebook runtime twice with the same source snapshots and dependency lock. Compare declared/observed schemas, counts, reason distributions, join evidence, canonical logical checksums, and artifact metadata. Separate stable fields from expected run-specific fields such as wall-clock timestamps.

6.3 Test Data

Maintain a tiny hand-auditable fixture, a medium deterministic mobility snapshot, and deliberately malformed variants. Pin source checksums and include duplicate dimension keys, missing identifiers, invalid coordinates, timezone transitions, unknown categories, and reordered-but-logically-equivalent rows.

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Problem: Trip count rises after zone enrichment

  • Likely cause: duplicate zone keys created a many-to-many join.
  • Evidence: dimension distinct-key count is lower than row count; duplicated key report is non-empty.
  • Fix: validate uniqueness before joining and resolve the dimension’s effective-date/grain problem.
  • Quick test: compare pre-join and post-join row counts on a fixture containing one deliberate duplicate.

Problem: The lazy pipeline consumes excessive memory

  • Likely cause: an early collect, rendered full dataframe, unbounded sort, or operation unsupported by the chosen lazy backend.
  • Evidence: memory rises at a specific action; plan boundary occurs earlier than documented.
  • Fix: project required columns, filter and aggregate first, and enforce a result bound before collection.
  • Quick test: run with increasing input sizes while the summary cardinality stays fixed.

Problem: Durations become negative near a timezone transition

  • Likely cause: naive local timestamps were interpreted as UTC or ambiguous wall times were normalized inconsistently.
  • Evidence: failures cluster around transition dates and a source region.
  • Fix: preserve source timezone metadata and define an ambiguity/nonexistent-time policy.
  • Quick test: include timestamps immediately before, during, and after the transition.

Problem: Replay checksum changes while metrics match

  • Likely cause: unstable row ordering, different file encoding metadata, floating-point formatting, or run timestamps included in the checksum.
  • Evidence: logical sorted rows match while raw file bytes differ.
  • Fix: distinguish byte identity from logical identity and canonicalize the latter.
  • Quick test: reorder equal input rows and compare both checksum types.

Problem: Reconciliation passes but results are still wrong

  • Likely cause: values were misparsed, repairs changed meaning, or accepted rows received incorrect dimensions.
  • Evidence: dtype/range/profile or referential-integrity checks fail despite equal counts.
  • Fix: treat reconciliation as one invariant among schema, domain, cardinality, and distribution checks.

7.2 Debugging Strategies

Debug from evidence boundaries: confirm source identity, inspect declared and inferred schemas, compare reason-code counts, prove dimension uniqueness, locate the collection boundary, and compare canonical logical rows before comparing physical file bytes. Change one policy or fixture condition at a time so the first diverging invariant remains visible.

7.3 Performance Traps

Watch for premature collection, rendering entire frames, unbounded sorts, full-dataset joins, and operations the lazy backend cannot push down. Measure row counts and memory at each boundary, and make maximum collected rows an executable assertion rather than a comment.

Definition of Done

Submit the Livebook notebook, immutable training fixtures or resolvable fixture references, clean Parquet, quarantine Parquet, manifest, and a short replay report.

The submission is complete when:

  • The declared and observed schemas are displayed and compared.
  • Source, accepted, and quarantined row counts reconcile exactly.
  • Every quarantine row has deterministic reason evidence.
  • Dimension uniqueness is checked before joining.
  • Pre-join and post-join counts plus unmatched keys are reported.
  • The lazy plan and exact collection boundary are explained.
  • The collected result is bounded and contains only the required summary.
  • Clean and quarantine Parquet outputs pass read-back validation.
  • Stable checksums match across two clean replays of the same snapshot.
  • Duplicate keys, timezone defects, schema drift, and unbounded collection have demonstrated failure behavior.
  • No full unbounded dataframe is rendered in the notebook.
  • Another person can reproduce the run from the submitted instructions.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • Every merged source contribution is implemented as a phase of this one artifact, not as a separate project.
  • schema drift is explicit and lazy plans remain inspectable.

Project 41: Safe SQL Incident Runbook

Source: LIVE-P6. Build a read-only Livebook investigation with secrets, bounded queries, and freshness labels.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir and SQL
  • Alternative Programming Languages: Erlang; Python for notebook comparison
  • Coolness Level: Level 2: Practical
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 1: Foundational
  • Knowledge Area: Databases, operational diagnostics, security, evidence
  • Software or Tool: Livebook, KinoDB, PostgreSQL or SQLite training database
  • Main Book: Designing Data-Intensive Applications, Second Edition

What you will build: Build a read-only Livebook investigation with secrets, bounded queries, and freshness labels.

Why it teaches the BEAM ecosystem: It makes you prove that operators answer the incident question without mutation authority.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Build a read-only Livebook investigation with secrets, bounded queries, and freshness labels.

Create a Livebook notebook named delayed_invoice_sync that investigates a seeded incident in a disposable training database. It must provide:

  1. A conspicuous TRAINING environment and READ ONLY authority panel.
  2. A catalog of reviewed diagnostic questions identified by stable query IDs and versions.
  3. Typed controls for a bounded UTC time window, service/tenant fixture selector, severity, and maximum returned rows.
  4. Parameterized execution through KinoDB or Postgrex without string interpolation.
  5. Database-role and read-only-transaction verification before every diagnostic execution.
  6. A preflight workload estimate or bounded-plan check appropriate to the training schema.
  7. A hard timeout and maximum result count.
  8. Aggregated and redacted evidence views.
  9. Explicit ready, empty, rejected, timed-out, failed, stale, and partial states.
  10. An exportable audit transcript containing query IDs and redacted parameters but no secrets or direct identifiers.

The notebook must expose no free-form SQL cell for operators. Authors may inspect schema during construction, but the submitted artifact must offer only the cataloged investigative paths.

The final evidence panel should resemble:

RUNBOOK: delayed_invoice_sync
Environment: TRAINING
Database role: support_readonly
Transaction mode: READ ONLY
Window: 2026-07-15 12:00Z..13:00Z
Rows scanned estimate: 82,410
Rows returned: 214 / limit 500
Query duration: 184 ms
PII redaction: PASS
Mutation capability: NONE

A query attempt with an injection-shaped parameter must remain an ordinary value:

request_id: trn-0042
query_id: invoice_sync_by_tenant_v2
tenant_filter: [REDACTED, length=24]
parameter_binding: PASS
statement_structure_changed: false
status: EMPTY

An excessive request should stop before query execution:

request_id: trn-0043
requested_window: 31 days
maximum_window: 24 hours
database_query_sent: false
status: REJECTED_BOUND

A teammate can use the runbook to diagnose the seeded delay, explain which bounded questions were asked, distinguish absence of matching records from query failure, and export a safe transcript. A reviewer can verify that:

  • no mutation path exists in the notebook or the role;
  • values are bound separately from SQL structure;
  • expensive or broad requests are rejected;
  • displayed and exported data follow the same redaction policy;
  • query results and failure states remain distinguishable;
  • the evidence identifies the training environment and authority actually in effect.

The durable outcome is a reusable pattern for constrained operational investigation, not permission to point the notebook at a real system.

The Core Question You Are Answering

How can an executable runbook accelerate diagnosis without becoming an unbounded production shell?

Answer by listing each capability the operator genuinely needs and the independent mechanism that constrains it. If a feature requires arbitrary SQL, unrestricted export, production authority, or hidden credentials, it is outside this project’s scope.

Concepts You Must Understand First

Before implementation, explain:

  1. Why parameter binding protects statement structure but not workload cost.
  2. The difference between a database role, a transaction mode, and a notebook UI permission.
  3. Why a returned-row limit may not bound scanned or sorted data.
  4. How redaction by query/view design differs from post-fetch masking.
  5. Why an empty result and a failed request require different states.
  6. What an audit transcript must include to be useful without becoming a leakage channel.

Questions to Guide Your Design

  • Which incident questions are common and stable enough to deserve catalog entries?
  • Which parameters are values, and which apparent “parameters” are actually SQL structure requiring allowlisted variants?
  • What maximum time window and timeout fit each question?
  • How will the runbook determine source freshness and replica lag in the training model?
  • Which columns are prohibited even for notebook authors?
  • What is the policy when a query returns exactly the row cap?
  • How will the operator know whether data is partial, truncated, stale, or complete?
  • Which actual database query proves the current role and transaction mode?
  • Where will audit events be stored so that the lab remains read-only with respect to the investigated database? A local in-memory/export artifact is acceptable; writing an audit row into the training database through this role is not.

Thinking Exercise

Threat-model four actors and trace the controls that stop them:

  1. A well-meaning operator selects a 90-day window during an incident.
  2. A malicious input contains quotes, comments, and a second SQL statement.
  3. The training credential is copied outside the notebook.
  4. An author attaches the notebook to a more privileged runtime.

For each actor, identify prevention, detection, evidence, and residual risk. Then analyze a fifth case: the query returns zero rows because the seeded data refresh is stale. Which state should the operator see, and why is EMPTY dishonest?

The Interview Questions They Will Ask

  1. What problem do prepared or parameterized statements solve, and what do they not solve?
  2. How would you enforce read-only behavior for an incident-analysis tool?
  3. Why can a query with LIMIT 100 still overload a database?
  4. How would you prevent sensitive data from leaking through errors and exports?
  5. What states should a diagnostic dashboard distinguish?
  6. How would you version and review an allowlisted query catalog?

Hints in Layers

Hint 1 — Start from questions, not SQL. Define “show delayed jobs for one bounded window” as a catalog capability.

Hint 2 — Bind every value. Map structural choices to reviewed query IDs; never concatenate a sort column, relation, predicate, or direction from user text.

Hint 3 — Bound twice or more. Validate the requested window in Elixir, encode the same bounded predicate in SQL, set a timeout, and cap rendered rows.

Hint 4 — Redact before data crosses the connection. Prefer reporting views or explicit safe projections.

Hint 5 — Verify actual authority. Read the database’s current role and transaction properties inside the same connection/transaction used for the query.

Pseudocode outline:

definition = catalog.fetch_exact(request.query_id)
validated = validate_values(request, definition.parameter_schema)
assert_training_endpoint()
with dedicated_connection:
  begin_read_only_transaction()
  assert_actual_role_and_mode()
  assert_preflight_within_budget(definition, validated)
  result = execute_with_bound_values(definition.statement, validated.values)
  safe_result = enforce_output_contract(result, definition)
emit_redacted_transcript(definition.id, validated.redacted_summary, safe_result.status)

Books That Will Help

Topic Book Suggested focus
PostgreSQL roles and query behavior PostgreSQL: Up and Running — Regina Obe and Leo Hsu Roles, permissions, query inspection
Database reliability Designing Data-Intensive Applications — Martin Kleppmann Transactions, replication, derived views
Security engineering Security Engineering — Ross Anderson Least privilege, audit, threat modeling
Operational response Seeking SRE — David Blank-Edelman Incident response and operational tooling

Implementation Milestones

Phase 1 — Threat model and training database (2–4 hours)

  • Define the safety boundary and prohibited capabilities.
  • Seed synthetic incident data and create redacted reporting views.
  • Create the constrained database role and prove mutation denial.

Phase 2 — Query catalog and parameter validation (3–4 hours)

  • Implement two or three catalog questions.
  • Define typed bounds and stable IDs/versions.
  • Test injection-shaped values and invalid structural choices.

Phase 3 — Authority and workload gates (3–5 hours)

  • Use a dedicated connection and explicitly read-only transaction.
  • Verify role/mode in the active context.
  • Add maximum window, timeout, row cap, and training preflight budget.

Phase 4 — States, redaction, and transcript (3–4 hours)

  • Render bounded summaries and anomaly visuals.
  • Implement distinct empty/rejected/timeout/failed/stale/partial states.
  • Export a transcript with redacted parameter metadata.

Phase 5 — Abuse and replay tests (1–3 hours)

  • Attempt every prohibited path against the training fixture.
  • Simulate slow, stale, disconnected, and truncated responses.
  • Reproduce the seeded diagnosis from a fresh runtime.

Testing Strategy

6.1 Test Categories

The suite covers authority, input structure, operational states, privacy, and workload cost. Each category must prove a boundary independently so that a friendly UI cannot conceal an unsafe role, statement, result, or execution plan.

6.2 Critical Test Cases

Privilege tests

  • Verify the role can connect only to the training database intended for the lab.
  • Verify approved selects succeed.
  • Verify insert, update, delete, truncate, create, alter, and drop attempts are denied against disposable test objects.
  • Verify the submitted notebook contains no API or control that initiates those attempts.
  • Verify execution refuses to continue if the actual role differs from support_readonly.

Input and injection tests

Input Expected behavior
Valid bounded UTC window Query executes
Window over maximum Rejected before database call
Injection-shaped tenant value Treated as one bound value; statement unchanged
Unknown query ID Rejected
User-supplied sort fragment Rejected; only known enum variants allowed
Result limit above catalog max Clamped or rejected according to documented policy

Operational state tests

  • Known empty fixture → EMPTY, with query success evidence.
  • Invalid input → REJECTED, with database_query_sent=false.
  • Deliberately delayed query beyond timeout → TIMED_OUT.
  • Dropped connection → FAILED_CONNECTION.
  • Old fixture refresh marker → STALE, not empty or ready.
  • Forced row cap → PARTIAL or TRUNCATED, never silently complete.
  • Malformed result contract → FAILED_OUTPUT_CONTRACT.

Privacy tests

  • Search rendered notebook output, exported transcript, runtime logs, and controlled error text for seeded canary PII and secret canary values.
  • Confirm neither canary appears.
  • Confirm prohibited columns never cross the connection by inspecting the reviewed projection and training query logs.

Cost tests

  • Compare an indexed bounded window with a deliberately broad request.
  • Demonstrate that a small returned limit can still have a high preflight estimate.
  • Verify the broad request is rejected before execution.

6.3 Test Data

Use only a disposable, seeded PostgreSQL database containing synthetic tenants, delayed jobs, stale refresh markers, forbidden columns, and unique PII and secret canaries. Include narrow indexed windows, deliberately broad windows, empty results, delayed statements, and dropped connections; never copy production rows into the fixture.

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Problem: A query returns only 500 rows but remains expensive

  • Why: the database scanned, joined, grouped, or sorted a large population before applying the final limit.
  • Evidence: preflight plan/estimate and elapsed time exceed the query catalog budget.
  • Fix: add selective indexed predicates, reduce window, preaggregate a reporting view, and keep the budget gate.
  • Quick test: compare plans for one-hour and thirty-day requests on the seeded fixture.

Problem: The UI is redacted but the export leaks PII

  • Why: raw rows were fetched and only the renderer masked them.
  • Evidence: canary identifier appears in the export or runtime inspection.
  • Fix: select from a redacted view or explicit safe projection; apply one output contract to UI and export.
  • Quick test: place a unique canary in a forbidden source column and scan every artifact.

Problem: The notebook says read-only but mutation succeeds

  • Why: a privileged connection was reused, transaction mode was not applied, or grants were too broad.
  • Evidence: actual role/mode differs from the banner; negative mutation test succeeds.
  • Fix: destroy the environment, create a dedicated role, revoke privileges, and fail closed on actual-state mismatch.

Problem: Empty and failed look identical

  • Why: errors are converted to an empty dataframe.
  • Evidence: no terminal status, query ID, duration, or freshness evidence accompanies the blank table.
  • Fix: model result states explicitly and render a distinct panel for each.

Problem: Parameterization test still changes SQL structure

  • Why: identifiers, ordering, or a predicate fragment were interpolated even though scalar values were bound.
  • Evidence: statement checksum varies with a user input.
  • Fix: map structural options to complete reviewed query variants.

Problem: Attached runtime grants unintended authority

  • Why: the notebook runs inside an application node with broader credentials or network reach.
  • Evidence: environment and connection identity differ from the standalone training setup.
  • Fix: use a standalone Livebook runtime and isolated training network/credentials.

7.2 Debugging Strategies

Start by reading actual state from the same connection used for the query: role, database, transaction mode, catalog ID, bound parameters, timeout, freshness, and terminal status. Compare the reviewed statement checksum before inspecting rendered output, and search every controlled artifact for canary data after each failure.

7.3 Performance Traps

Do not equate returned rows with work performed. Broad predicates, sorts before limits, unindexed joins, repeated reactive events, plan inspection that executes the statement, and unrestricted exports can all exceed the workload budget. Validate bounds before the database call and preserve timeout and concurrency caps during debugging.

Definition of Done

Submit the notebook, synthetic seed description, role/grant definition as a non-runnable reviewed configuration transcript or separate training setup artifact, query-catalog manifest, redacted example transcript, and test report.

The submission is complete when:

  • TRAINING ONLY and READ ONLY are prominent and reflect verified state.
  • A dedicated restricted role is used; mutation capability is proven absent.
  • Every operator query comes from a stable allowlisted catalog.
  • All scalar values are bound separately; no user-controlled SQL structure is interpolated.
  • Time-window, returned-row, timeout, and workload/preflight bounds are tested.
  • Over-budget requests are stopped before execution.
  • Result schemas redact or aggregate by construction.
  • Empty, rejected, timeout, connection failure, stale, and partial states are demonstrated.
  • The transcript includes query IDs and redacted parameter metadata, never secrets or raw PII.
  • Canary scans pass across rendering, exports, logs, and errors.
  • The submitted notebook contains no arbitrary SQL, mutation, administration, or production connection path.
  • A clean runtime reproduces the training diagnosis.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • operators answer the incident question without mutation authority.

Phase 2 - Processes, Message Passing, OTP, and Local State

Project 42: Set-Theoretic Fulfillment API Contract Atlas

Official topic: Set-theoretic types cheatsheet — Elixir v1.20.2

Source file: lib/elixir/pages/cheatsheets/types-cheat.cheatmd

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 2: Intermediate
  • Knowledge Area: Type Systems / API Contracts
  • Software or Tool: Elixir compiler type diagnostics
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build a fixture library of realistic fulfillment command and result shapes plus accepted and rejected compiler-analysis cases covering unions, intersections, negation, functions, maps, lists, tuples, and aliases.

Why it teaches this official topic: The artifact makes set operators, map and tuple types, list and function types, convenience type aliases observable through one bounded build instead of isolated syntax examples.

Scope boundary: Keep this a static contract atlas; exclude Ash resources, runtime schema validation, and general linting.

Core challenges you will face:

  • set operators -> identify the accepted case, the counterexample, and the observable result at the Elixir compiler type diagnostics boundary
  • map and tuple types -> identify the accepted case, the counterexample, and the observable result at the Elixir compiler type diagnostics boundary
  • list and function types -> identify the accepted case, the counterexample, and the observable result at the Elixir compiler type diagnostics boundary
  • convenience type aliases -> identify the accepted case, the counterexample, and the observable result at the Elixir compiler type diagnostics boundary

Real World Outcome

Build a fixture library of realistic fulfillment command and result shapes plus accepted and rejected compiler-analysis cases covering unions, intersections, negation, functions, maps, lists, tuples, and aliases. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Every documented type constructor has an accepted fixture.
  • Every rejection explains the incompatible set.
  • Open and closed map contracts are visibly different.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=cheatsheets/types-cheat.cheatmd
ARTIFACT=set-theoretic-fulfillment-api-contract-atlas
CHECK 01 PASS :: Every documented type constructor has an accepted fixture
CHECK 02 PASS :: Every rejection explains the incompatible set
CHECK 03 PASS :: Open and closed map contracts are visibly different
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“How do set operations describe the exact values an Elixir API accepts and returns?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. set operators
    • Working rule: Make “set operators” an explicit rule at the Elixir compiler type diagnostics boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "set-operators-positive", focus: "set operators", mode: :positive, expect: :observable} and %{id: "set-operators-negative", focus: "set operators", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Set-theoretic types cheatsheet
  2. map and tuple types
    • Working rule: Make “map and tuple types” an explicit rule at the Elixir compiler type diagnostics boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "map-and-tuple-types-positive", focus: "map and tuple types", mode: :positive, expect: :observable} and %{id: "map-and-tuple-types-negative", focus: "map and tuple types", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Set-theoretic types cheatsheet
  3. list and function types
    • Working rule: Make “list and function types” an explicit rule at the Elixir compiler type diagnostics boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "list-and-function-types-positive", focus: "list and function types", mode: :positive, expect: :observable} and %{id: "list-and-function-types-negative", focus: "list and function types", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Set-theoretic types cheatsheet
  4. convenience type aliases
    • Working rule: Make “convenience type aliases” an explicit rule at the Elixir compiler type diagnostics boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "convenience-type-aliases-positive", focus: "convenience type aliases", mode: :positive, expect: :observable} and %{id: "convenience-type-aliases-negative", focus: "convenience type aliases", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Set-theoretic types cheatsheet

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “set operators” be enforced?
    • Which check catches the risk “Runtime validation is confused with static analysis”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Every documented type constructor has an accepted fixture”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Set-theoretic types cheatsheet”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: set operators, map and tuple types, list and function types, convenience type aliases. Then trace the named counterexample “Runtime validation is confused with static analysis” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose set operators, and what does this project prove about it?”
  2. “What interaction between the concept ‘map and tuple types’ and the concept ‘set operators’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘Runtime validation is confused with static analysis’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with set-operators-positive and runtime-validation-is-confused-with-static-analysis-counterexample. The first must make the concept “set operators” observable and establish “Every documented type constructor has an accepted fixture”; the second must reproduce “Runtime validation is confused with static analysis”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for cheatsheets/types-cheat.cheatmd
evaluate "set operators" through Elixir compiler type diagnostics
compare actual evidence with "Every documented type constructor has an accepted fixture"
run negative fixture for "Runtime validation is confused with static analysis"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Set-theoretic types cheatsheet Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
set operators Elixir in Action, 3rd Edition Ch. 4: data abstractions and contracts
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement set-operators-positive and prove “Every documented type constructor has an accepted fixture”.
  3. Topic coverage: add fixtures for map and tuple types, list and function types, convenience type aliases.
  4. Failure campaign: reproduce each named risk: “Runtime validation is confused with static analysis”; “An open map is documented as closed”; “A broad alias erases the useful contract”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute set-operators-positive, map-and-tuple-types-positive, list-and-function-types-positive, convenience-type-aliases-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute set-operators-negative, map-and-tuple-types-negative, list-and-function-types-negative, convenience-type-aliases-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute runtime-validation-is-confused-with-static-analysis-counterexample, an-open-map-is-documented-as-closed-counterexample, a-broad-alias-erases-the-useful-contract-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real Elixir compiler type diagnostics boundary from a clean shell.
  • Mutation check: violate “Every documented type constructor has an accepted fixture” and prove the suite reports fixture set-operators-positive as failed.
  • Regression corpus: retain the risks “Runtime validation is confused with static analysis”; “An open map is documented as closed”; “A broad alias erases the useful contract” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “Runtime validation is confused with static analysis”

  • Why: This breaks one or more observable capabilities at the Elixir compiler type diagnostics boundary while allowing the happy path to look correct.
  • Fix: Run runtime-validation-is-confused-with-static-analysis-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “An open map is documented as closed”

  • Why: This breaks one or more observable capabilities at the Elixir compiler type diagnostics boundary while allowing the happy path to look correct.
  • Fix: Run an-open-map-is-documented-as-closed-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “A broad alias erases the useful contract”

  • Why: This breaks one or more observable capabilities at the Elixir compiler type diagnostics boundary while allowing the happy path to look correct.
  • Fix: Run a-broad-alias-erases-the-useful-contract-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • Every documented type constructor has an accepted fixture.
  • Every rejection explains the incompatible set.
  • Open and closed map contracts are visibly different.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 43: Process Lifecycle Incident Simulator

Official topic: Processes — Elixir v1.20.2

Source file: lib/elixir/pages/getting-started/processes.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 2: Intermediate
  • Knowledge Area: Concurrency / Process Primitives
  • Software or Tool: spawn, send, receive, Task, Agent
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build deterministic scenarios for isolated and linked crashes, mailbox selection and timeout, Task completion, a recursive state loop, registration, and an Agent-backed incident counter.

Why it teaches this official topic: The artifact makes process isolation, mailbox messaging, links and failure propagation, state loops and Task abstractions observable through one bounded build instead of isolated syntax examples.

Scope boundary: Remain an unsupervised primitives laboratory; exclude TCP, chat, Registry, GenServer, and supervision strategies.

Core challenges you will face:

  • process isolation -> identify the accepted case, the counterexample, and the observable result at the spawn, send, receive, Task, Agent boundary
  • mailbox messaging -> identify the accepted case, the counterexample, and the observable result at the spawn, send, receive, Task, Agent boundary
  • links and failure propagation -> identify the accepted case, the counterexample, and the observable result at the spawn, send, receive, Task, Agent boundary
  • state loops and Task abstractions -> identify the accepted case, the counterexample, and the observable result at the spawn, send, receive, Task, Agent boundary

Real World Outcome

Build deterministic scenarios for isolated and linked crashes, mailbox selection and timeout, Task completion, a recursive state loop, registration, and an Agent-backed incident counter. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Isolated and linked crash outcomes are contrasted.
  • Mailbox timeouts and selective receive are observable.
  • Task and Agent abstractions are mapped back to process primitives.

Acceptance transcript:

$ mix test test/process_lifecycle_incident_test.exs
SOURCE_TOPIC=getting-started/processes.md
ARTIFACT=process-lifecycle-incident-simulator
CHECK 01 PASS :: Isolated and linked crash outcomes are contrasted
CHECK 02 PASS :: Mailbox timeouts and selective receive are observable
CHECK 03 PASS :: Task and Agent abstractions are mapped back to process primitives
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“What properties do raw BEAM processes provide before OTP adds standard lifecycle structure?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. process isolation
    • Working rule: Make “process isolation” an explicit rule at the spawn, send, receive, Task, Agent boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "process-isolation-positive", focus: "process isolation", mode: :positive, expect: :observable} and %{id: "process-isolation-negative", focus: "process isolation", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Processes
  2. mailbox messaging
    • Working rule: Make “mailbox messaging” an explicit rule at the spawn, send, receive, Task, Agent boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "mailbox-messaging-positive", focus: "mailbox messaging", mode: :positive, expect: :observable} and %{id: "mailbox-messaging-negative", focus: "mailbox messaging", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Processes
  3. links and failure propagation
    • Working rule: Make “links and failure propagation” an explicit rule at the spawn, send, receive, Task, Agent boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "links-and-failure-propagation-positive", focus: "links and failure propagation", mode: :positive, expect: :observable} and %{id: "links-and-failure-propagation-negative", focus: "links and failure propagation", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Processes
  4. state loops and Task abstractions
    • Working rule: Make “state loops and Task abstractions” an explicit rule at the spawn, send, receive, Task, Agent boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "state-loops-and-task-abstractions-positive", focus: "state loops and Task abstractions", mode: :positive, expect: :observable} and %{id: "state-loops-and-task-abstractions-negative", focus: "state loops and Task abstractions", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Processes

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “process isolation” be enforced?
    • Which check catches the risk “A receive loop has no timeout or stop protocol”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Isolated and linked crash outcomes are contrasted”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Processes”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: process isolation, mailbox messaging, links and failure propagation, state loops and Task abstractions. Then trace the named counterexample “A receive loop has no timeout or stop protocol” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose process isolation, and what does this project prove about it?”
  2. “What interaction between the concept ‘mailbox messaging’ and the concept ‘process isolation’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘A receive loop has no timeout or stop protocol’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with process-isolation-positive and a-receive-loop-has-no-timeout-or-stop-protocol-counterexample. The first must make the concept “process isolation” observable and establish “Isolated and linked crash outcomes are contrasted”; the second must reproduce “A receive loop has no timeout or stop protocol”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for getting-started/processes.md
evaluate "process isolation" through spawn, send, receive, Task, Agent
compare actual evidence with "Isolated and linked crash outcomes are contrasted"
run negative fixture for "A receive loop has no timeout or stop protocol"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix test test/process_lifecycle_incident_test.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Processes Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
process isolation Elixir in Action, 3rd Edition Ch. 5-6: concurrency primitives
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement process-isolation-positive and prove “Isolated and linked crash outcomes are contrasted”.
  3. Topic coverage: add fixtures for mailbox messaging, links and failure propagation, state loops and Task abstractions.
  4. Failure campaign: reproduce each named risk: “A receive loop has no timeout or stop protocol”; “A link is mistaken for a monitor”; “State ownership is spread across callers”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute process-isolation-positive, mailbox-messaging-positive, links-and-failure-propagation-positive, state-loops-and-task-abstractions-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute process-isolation-negative, mailbox-messaging-negative, links-and-failure-propagation-negative, state-loops-and-task-abstractions-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute a-receive-loop-has-no-timeout-or-stop-protocol-counterexample, a-link-is-mistaken-for-a-monitor-counterexample, state-ownership-is-spread-across-callers-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix test test/process_lifecycle_incident_test.exs through the real spawn, send, receive, Task, Agent boundary from a clean shell.
  • Mutation check: violate “Isolated and linked crash outcomes are contrasted” and prove the suite reports fixture process-isolation-positive as failed.
  • Regression corpus: retain the risks “A receive loop has no timeout or stop protocol”; “A link is mistaken for a monitor”; “State ownership is spread across callers” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “A receive loop has no timeout or stop protocol”

  • Why: This breaks one or more observable capabilities at the spawn, send, receive, Task, Agent boundary while allowing the happy path to look correct.
  • Fix: Run a-receive-loop-has-no-timeout-or-stop-protocol-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix test test/process_lifecycle_incident_test.exs

Problem 2: “A link is mistaken for a monitor”

  • Why: This breaks one or more observable capabilities at the spawn, send, receive, Task, Agent boundary while allowing the happy path to look correct.
  • Fix: Run a-link-is-mistaken-for-a-monitor-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix test test/process_lifecycle_incident_test.exs

Problem 3: “State ownership is spread across callers”

  • Why: This breaks one or more observable capabilities at the spawn, send, receive, Task, Agent boundary while allowing the happy path to look correct.
  • Fix: Run state-ownership-is-spread-across-callers-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix test test/process_lifecycle_incident_test.exs

Definition of Done

  • Isolated and linked crash outcomes are contrasted.
  • Mailbox timeouts and selective receive are observable.
  • Task and Agent abstractions are mapped back to process primitives.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 44: TCP Echo Server from Raw Processes

Source: PHX-P1. Build a TCP accept loop with one isolated process per connection.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: Level 2: Micro-SaaS / Pro Tool
  • Curriculum Difficulty: Level 2: Intermediate
  • Knowledge Area: Concurrency / Networking
  • Software or Tool: Elixir, :gen_tcp
  • Main Book: “Elixir in Action” by Saša Jurić

What you will build: Build a TCP accept loop with one isolated process per connection.

Why it teaches the BEAM ecosystem: It makes you prove that a failing handler does not terminate the listener or unrelated clients.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Build a TCP accept loop with one isolated process per connection.

# Terminal 1: Start your server
$ iex -S mix
iex> EchoServer.start(4000)
Listening on port 4000...

# Terminal 2: Connect with telnet
$ telnet localhost 4000
Connected to localhost.
Hello, BEAM!
Hello, BEAM!    # Server echoes back

# Terminal 3: Another simultaneous connection
$ telnet localhost 4000
Connected to localhost.
Second connection!
Second connection!

# Both connections work independently, each in its own process!

The Core Question You Are Answering

“How can TCP Echo Server from Raw Processes deliver its observable outcome while proving that a failing handler does not terminate the listener or unrelated clients.”

Concepts You Must Understand First

  • Spawning processes for each connection → maps to the actor model
  • Message passing between processes → maps to how Phoenix Channels work
  • Handling process crashes → maps to fault tolerance
  • Using :gen_tcp → maps to understanding Cowboy’s foundation

Questions to Guide Your Design

  1. Which input and output contracts must remain stable across refactoring?
  2. Where should validation happen, and how will expected failures be represented?
  3. Which component owns mutable state or external effects, and what happens when it dies?
  4. What independent evidence proves this mastery condition: a failing handler does not terminate the listener or unrelated clients.

Thinking Exercise

Draw TCP Echo Server from Raw Processes as an input → decision/state → effect → evidence pipeline.

Mark every failure boundary, retry boundary, and durable state transition. Then inject one failure at each boundary and predict the observable result before implementing it.

The Interview Questions They Will Ask

  1. “What is the hardest invariant in TCP Echo Server from Raw Processes, and where is it enforced?”
  2. “Which parts should be pure transformations and which require BEAM processes?”
  3. “How does the design behave under malformed input, process failure, or retry?”
  4. “What test or runtime evidence proves: a failing handler does not terminate the listener or unrelated clients.”

Hints in Layers

The core pattern for accepting connections:

1. Open a listening socket with :gen_tcp.listen/2
2. Accept a connection with :gen_tcp.accept/1
3. Spawn a new process to handle this connection
4. Go back to step 2 (accept loop)

For each client process:
1. Receive data with :gen_tcp.recv/2
2. Send it back with :gen_tcp.send/2
3. Loop until connection closes

Key questions to answer:

  • What happens when you spawn a function?
  • How does receive block a process without blocking others?
  • What happens if a client process crashes? Does the server crash?
  • How many connections can you handle simultaneously?

Hint 1: Starting Point Implement the narrowest happy path for: Build a TCP accept loop with one isolated process per connection.

Hint 2: Next Level Separate parsing, validation, and transition decisions from effects so each can be tested directly.

Hint 3: Technical Details Represent expected failures as tagged outcomes and keep state ownership explicit; write only structural pseudocode before implementation.

Hint 4: Tools and Debugging Inject one failure at a time, correlate it with bounded telemetry, and save a deterministic transcript as evidence.

Books That Will Help

  • Main Book: “Elixir in Action” by Saša Jurić

Implementation Milestones

  1. Single connection works → You understand :gen_tcp basics
  2. Multiple connections work simultaneously → You understand process spawning
  3. Server survives client crashes → You understand process isolation
  4. You can track active connections → You understand process communication

Testing Strategy

  • Unit checks: pure parsing, validation, transition, and formatting decisions.
  • Integration checks: the real process, database, socket, notebook, or framework boundary.
  • Failure checks: malformed input plus at least one crash, timeout, duplicate, overload, or partition scenario.
  • Acceptance check: independently demonstrate that a failing handler does not terminate the listener or unrelated clients.
  • Avoid arbitrary sleeps; use messages, monitors, deterministic clocks, fixtures, and deadlines where applicable.

Common Pitfalls and Debugging

Problem 1: Happy-path output looks correct but failures disappear

  • Why: validation, effects, and reporting share one opaque step.
  • Fix: preserve tagged errors and source identity through every stage.
  • Quick test: inject one invalid record or failed dependency and verify an explicit result.

Problem 2: Tests merely repeat the implementation

  • Why: assertions reuse the same transformation or state assumptions.
  • Fix: check external invariants, golden fixtures, and observable failure behavior.
  • Quick test: introduce a deliberate ordering or boundary bug and confirm the test fails.

Definition of Done

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • a failing handler does not terminate the listener or unrelated clients.

Project 45: Chat Server Without OTP

Source: ERL-P4. Build stateful chat with spawn, send, receive, links, monitors, and hand-written loops.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Erlang
  • Alternative Programming Languages: Go, Rust, Haskell
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: Level 2: Micro-SaaS / Pro Tool
  • Curriculum Difficulty: Level 2: Intermediate
  • Knowledge Area: Concurrency / Networking
  • Software or Tool: TCP Sockets
  • Main Book: “Programming Erlang” by Joe Armstrong

What you will build: Build stateful chat with spawn, send, receive, links, monitors, and hand-written loops.

Why it teaches the BEAM ecosystem: It makes you prove that ordering and process-death behavior are visible before behaviours hide mechanics.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Build stateful chat with spawn, send, receive, links, monitors, and hand-written loops.

A multi-user TCP chat server where each client gets their own process, messages broadcast to all users, and crashes don’t bring down the server—all using raw spawn, spawn_link, and message passing without any OTP behaviors.

Build Chat Server Without OTP as one runnable, observable artifact. Build stateful chat with spawn, send, receive, links, monitors, and hand-written loops.

Produce an evidence bundle containing:

  • one deterministic happy-path run;
  • one rejected or malformed input with an explicit reason;
  • one injected failure or boundary condition;
  • a final verification result proving: ordering and process-death behavior are visible before behaviours hide mechanics.
artifact=chat_server_without_otp
happy_path=PASS
invalid_input=REJECTED explicit_reason=true
failure_boundary=EXERCISED recovery_evidence=true
mastery_check=PASS

The Core Question You Are Answering

“How can Chat Server Without OTP deliver its observable outcome while proving that ordering and process-death behavior are visible before behaviours hide mechanics.”

Concepts You Must Understand First

  • Accepting TCP connections → maps to gen_tcp module
  • One process per client → maps to spawn and message passing
  • Broadcasting messages → maps to maintaining process registry
  • Handling client disconnection → maps to monitors and exit signals
  • Server state (list of connected clients) → maps to stateful receive loops

Questions to Guide Your Design

  1. Which input and output contracts must remain stable across refactoring?
  2. Where should validation happen, and how will expected failures be represented?
  3. Which component owns mutable state or external effects, and what happens when it dies?
  4. What independent evidence proves this mastery condition: ordering and process-death behavior are visible before behaviours hide mechanics.

Thinking Exercise

Draw Chat Server Without OTP as an input → decision/state → effect → evidence pipeline.

Mark every failure boundary, retry boundary, and durable state transition. Then inject one failure at each boundary and predict the observable result before implementing it.

The Interview Questions They Will Ask

  1. “What is the hardest invariant in Chat Server Without OTP, and where is it enforced?”
  2. “Which parts should be pure transformations and which require BEAM processes?”
  3. “How does the design behave under malformed input, process failure, or retry?”
  4. “What test or runtime evidence proves: ordering and process-death behavior are visible before behaviours hide mechanics.”

Hints in Layers

The architecture:

                    ┌─────────────┐
                    │ Acceptor    │ (accepts connections)
                    └──────┬──────┘
                           │ spawns
            ┌──────────────┼──────────────┐
            ▼              ▼              ▼
    ┌───────────┐  ┌───────────┐  ┌───────────┐
    │ Client 1  │  │ Client 2  │  │ Client 3  │
    └─────┬─────┘  └─────┬─────┘  └─────┬─────┘
          │              │              │
          └──────────────┼──────────────┘
                         ▼
                  ┌─────────────┐
                  │ Room Process│ (maintains client list)
                  └─────────────┘

Key Erlang pattern - the receive loop with state: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Hint 1: Starting Point Implement the narrowest happy path for: Build stateful chat with spawn, send, receive, links, monitors, and hand-written loops.

Hint 2: Next Level Separate parsing, validation, and transition decisions from effects so each can be tested directly.

Hint 3: Technical Details Represent expected failures as tagged outcomes and keep state ownership explicit; write only structural pseudocode before implementation.

Hint 4: Tools and Debugging Inject one failure at a time, correlate it with bounded telemetry, and save a deterministic transcript as evidence.

Books That Will Help

  • Main Book: “Programming Erlang” by Joe Armstrong

Implementation Milestones

  1. Single client can connect and send messages → Basic gen_tcp working
  2. Multiple clients see each other’s messages → Broadcasting works
  3. Client disconnect doesn’t crash server → You understand monitors

Testing Strategy

  • Unit checks: pure parsing, validation, transition, and formatting decisions.
  • Integration checks: the real process, database, socket, notebook, or framework boundary.
  • Failure checks: malformed input plus at least one crash, timeout, duplicate, overload, or partition scenario.
  • Acceptance check: independently demonstrate that ordering and process-death behavior are visible before behaviours hide mechanics.
  • Avoid arbitrary sleeps; use messages, monitors, deterministic clocks, fixtures, and deadlines where applicable.

Common Pitfalls and Debugging

Problem 1: Happy-path output looks correct but failures disappear

  • Why: validation, effects, and reporting share one opaque step.
  • Fix: preserve tagged errors and source identity through every stage.
  • Quick test: inject one invalid record or failed dependency and verify an explicit result.

Problem 2: Tests merely repeat the implementation

  • Why: assertions reuse the same transformation or state assumptions.
  • Fix: check external invariants, golden fixtures, and observable failure behavior.
  • Quick test: introduce a deliberate ordering or boundary bug and confirm the test fails.

Definition of Done

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • ordering and process-death behavior are visible before behaviours hide mechanics.

Project 46: Workshop Check-In Counter with Encapsulated Agent State

Official topic: Simple state with agents — Elixir v1.20.2

Source file: lib/elixir/pages/mix-and-otp/agents.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 2: Intermediate
  • Knowledge Area: State Ownership / Agent
  • Software or Tool: Agent and ExUnit
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build a capacity-aware check-in and check-out service with atomic get-and-update operations, named and unnamed instances, isolated async tests, and a deliberate slow-operation experiment.

Why it teaches this official topic: The artifact makes immutable versus process-held state, Agent get and update, API encapsulation, client versus server work observable through one bounded build instead of isolated syntax examples.

Scope boundary: Keep the artifact deliberately Agent-sized; exclude ETS, rate limiting, and transactional inventory.

Core challenges you will face:

  • immutable versus process-held state -> identify the accepted case, the counterexample, and the observable result at the Agent and ExUnit boundary
  • Agent get and update -> identify the accepted case, the counterexample, and the observable result at the Agent and ExUnit boundary
  • API encapsulation -> identify the accepted case, the counterexample, and the observable result at the Agent and ExUnit boundary
  • client versus server work -> identify the accepted case, the counterexample, and the observable result at the Agent and ExUnit boundary

Real World Outcome

Build a capacity-aware check-in and check-out service with atomic get-and-update operations, named and unnamed instances, isolated async tests, and a deliberate slow-operation experiment. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Capacity updates are atomic.
  • Tests never share a registered name accidentally.
  • Slow computation location and timeout consequences are measured.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=mix-and-otp/agents.md
ARTIFACT=workshop-check-in-counter-with-encapsulated-agent-state
CHECK 01 PASS :: Capacity updates are atomic
CHECK 02 PASS :: Tests never share a registered name accidentally
CHECK 03 PASS :: Slow computation location and timeout consequences are measured
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“When is an Agent the honest owner of simple state, and when does its convenience hide a poor boundary?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. immutable versus process-held state
    • Working rule: Make “immutable versus process-held state” an explicit rule at the Agent and ExUnit boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "immutable-versus-process-held-state-positive", focus: "immutable versus process-held state", mode: :positive, expect: :observable} and %{id: "immutable-versus-process-held-state-negative", focus: "immutable versus process-held state", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Simple state with agents
  2. Agent get and update
    • Working rule: Make “Agent get and update” an explicit rule at the Agent and ExUnit boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "agent-get-and-update-positive", focus: "Agent get and update", mode: :positive, expect: :observable} and %{id: "agent-get-and-update-negative", focus: "Agent get and update", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Simple state with agents
  3. API encapsulation
    • Working rule: Make “API encapsulation” an explicit rule at the Agent and ExUnit boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "api-encapsulation-positive", focus: "API encapsulation", mode: :positive, expect: :observable} and %{id: "api-encapsulation-negative", focus: "API encapsulation", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Simple state with agents
  4. client versus server work
    • Working rule: Make “client versus server work” an explicit rule at the Agent and ExUnit boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "client-versus-server-work-positive", focus: "client versus server work", mode: :positive, expect: :observable} and %{id: "client-versus-server-work-negative", focus: "client versus server work", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Simple state with agents

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “immutable versus process-held state” be enforced?
    • Which check catches the risk “Callers manipulate raw Agent state directly”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Capacity updates are atomic”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Simple state with agents”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: immutable versus process-held state, Agent get and update, API encapsulation, client versus server work. Then trace the named counterexample “Callers manipulate raw Agent state directly” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose immutable versus process-held state, and what does this project prove about it?”
  2. “What interaction between the concept ‘Agent get and update’ and the concept ‘immutable versus process-held state’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘Callers manipulate raw Agent state directly’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with immutable-versus-process-held-state-positive and callers-manipulate-raw-agent-state-directly-counterexample. The first must make the concept “immutable versus process-held state” observable and establish “Capacity updates are atomic”; the second must reproduce “Callers manipulate raw Agent state directly”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for mix-and-otp/agents.md
evaluate "immutable versus process-held state" through Agent and ExUnit
compare actual evidence with "Capacity updates are atomic"
run negative fixture for "Callers manipulate raw Agent state directly"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Simple state with agents Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
immutable versus process-held state Elixir in Action, 3rd Edition Ch. 6: generic server processes
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement immutable-versus-process-held-state-positive and prove “Capacity updates are atomic”.
  3. Topic coverage: add fixtures for Agent get and update, API encapsulation, client versus server work.
  4. Failure campaign: reproduce each named risk: “Callers manipulate raw Agent state directly”; “A slow callback blocks every client”; “Global naming makes async tests collide”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute immutable-versus-process-held-state-positive, agent-get-and-update-positive, api-encapsulation-positive, client-versus-server-work-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute immutable-versus-process-held-state-negative, agent-get-and-update-negative, api-encapsulation-negative, client-versus-server-work-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute callers-manipulate-raw-agent-state-directly-counterexample, a-slow-callback-blocks-every-client-counterexample, global-naming-makes-async-tests-collide-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real Agent and ExUnit boundary from a clean shell.
  • Mutation check: violate “Capacity updates are atomic” and prove the suite reports fixture immutable-versus-process-held-state-positive as failed.
  • Regression corpus: retain the risks “Callers manipulate raw Agent state directly”; “A slow callback blocks every client”; “Global naming makes async tests collide” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “Callers manipulate raw Agent state directly”

  • Why: This breaks one or more observable capabilities at the Agent and ExUnit boundary while allowing the happy path to look correct.
  • Fix: Run callers-manipulate-raw-agent-state-directly-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “A slow callback blocks every client”

  • Why: This breaks one or more observable capabilities at the Agent and ExUnit boundary while allowing the happy path to look correct.
  • Fix: Run a-slow-callback-blocks-every-client-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “Global naming makes async tests collide”

  • Why: This breaks one or more observable capabilities at the Agent and ExUnit boundary while allowing the happy path to look correct.
  • Fix: Run global-naming-makes-async-tests-collide-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • Capacity updates are atomic.
  • Tests never share a registered name accidentally.
  • Slow computation location and timeout consequences are measured.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 47: Mailbox-to-Registry Topic Bus

Sources: PUB-P1, PUB-P2. Implement broadcast with raw sends, then Registry dispatch.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: Level 2: Micro-SaaS / Pro Tool
  • Curriculum Difficulty: Level 2: Intermediate
  • Knowledge Area: Process registry, local routing, supervision
  • Software or Tool: Elixir Registry, Supervisor, ExUnit
  • Main Book: “Enterprise Integration Patterns” by Hohpe & Woolf

What you will build: Implement broadcast with raw sends, then Registry dispatch.

Why it teaches the BEAM ecosystem: It makes you prove that ordering, duplicate subscription, cleanup, and slow subscribers are observable.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Integrated Scope

This is one consolidated project, not separate source builds. Implement the following contributions as phases of the same artifact:

  • Implement PUB-P1 raw mailbox fanout first so ordering, death, and queue growth are visible.
  • Replace manual subscriber bookkeeping with the PUB-P2 Registry topic bus while keeping the same observable contract.

Real World Outcome

Build target: Implement broadcast with raw sends, then Registry dispatch.

Build a supervised local topic bus named LocalTopics. Subscriber processes register themselves under duplicate topic keys. A thin domain-neutral wrapper validates topic forms, makes repeated subscription idempotent, stores compact metadata, and exposes subscribe, unsubscribe, publish, membership count, and diagnostic snapshot operations.

The project includes three IEx subscriber fixtures, a churn scenario, a quiet benchmark profile, and tests for duplicates, cleanup, partition behavior, and publisher-path boundedness. It does not include cross-node propagation, durable replay, or authorization policy.

$ mix run --no-halt
bus=LocalTopics scope=node_local registry_partitions=4 status=ready
subscribe pid=<0.181.0> topic=sensor:west result=new
subscribe pid=<0.182.0> topic=sensor:west result=new
subscribe pid=<0.183.0> topic=sensor:east result=new
subscribe pid=<0.181.0> topic=sensor:west result=already_subscribed
publish topic=sensor:west entries_observed=2 sends_issued=2 partitions_touched=2 duration_us=41
handled pid=<0.181.0> event=evt-7 topic=sensor:west
handled pid=<0.182.0> event=evt-7 topic=sensor:west
exit pid=<0.182.0> reason=shutdown
membership topic=sensor:west count=1 cleanup=automatic
publish topic=sensor:west entries_observed=1 sends_issued=1 acknowledgement=none

Open three IEx sessions attached to one local node. Two processes join sensor:west and one joins sensor:east. Publishing a west event produces exactly two handler lines. Calling the wrapper’s subscribe operation again from the first west process returns already_subscribed, and the next publication still reaches it once.

Terminate the second west process. Without calling an application cleanup service, its Registry entry disappears. The next diagnostic snapshot shows one west member. Switching the benchmark profile from one partition to four shows how dispatch work is divided, but the report never uses callback order as a correctness guarantee. The final output clearly states scope=node_local and acknowledgement=none.

The Core Question You Are Answering

“How can process-owned registrations replace a centralized subscription broker without pretending local membership is delivery?”

Answer this by drawing ownership. If a separate process owns the membership map, that process must observe subscriber death. If each subscriber owns its Registry entry, the Registry can remove it with process lifecycle. Neither design acknowledges handler completion merely by routing.

Concepts You Must Understand First

  1. Duplicate keys
    • Can several PIDs share one key?
    • Can one PID create repeated raw entries?
    • Reference: Elixir Registry module documentation.
  2. Process-owned lifecycle
    • Why does an entry disappear on process exit?
    • Why can a just-looked-up PID still die?
    • Book: “Designing for Scalability with Erlang/OTP,” process lifecycle.
  3. Dispatch execution
    • Which caller pays for filtering and instrumentation?
    • Why must callback work be bounded?
    • Reference: Registry.dispatch documentation.
  4. Partitions
    • Why can one logical dispatch have several callback batches?
    • Why does batch order not define subscriber order?
    • Reference: Registry options and dispatch.
  5. Supervision
    • In which order should Registry and subscribers start?
    • How does a restarted subscriber recover membership?
    • Reference: Elixir Supervisor documentation.

Questions to Guide Your Design

  1. Is repeated subscribe idempotent or intentionally multiplicative?
  2. How does the wrapper recognize current-process membership without scanning the whole Registry?
  3. What topic forms are valid?
  4. Which metadata fields are bounded and safe?
  5. What happens if one metadata value is malformed?
  6. How will callbacks merge counts across partitions?
  7. What metrics can use topic family rather than raw topic?
  8. What should a restarted subscriber do during initialization?
  9. Which feature would justify returning to a central GenServer?

Thinking Exercise

Draw two implementations:

central GenServer: topic -> PID set
duplicate Registry: process-owned topic rows

For each, answer:

  • Where is membership state?
  • Which component is a serialization point?
  • Who observes subscriber death?
  • What happens after the membership component crashes?
  • How is one topic published?
  • Can one slow handler block routing?
  • What is still volatile?

Then decide whether idempotence belongs in Registry itself or in your wrapper contract.

The Interview Questions They Will Ask

  1. How does Registry differ from a GenServer-owned map?
  2. Why are duplicate keys useful for Pub/Sub?
  3. What happens when a registered process exits?
  4. Where does Registry dispatch callback work execute?
  5. Is Registry distributed across nodes?
  6. How do partitions affect dispatch assumptions?

Hints in Layers

Hint 1: Supervise the Registry first

Put it before subscribers in the application supervision tree so initialization can register safely.

Hint 2: Hide raw registration

Make the wrapper the only application API and encode idempotence there.

Hint 3: Keep metadata boring

Store small values needed for bounded routing. Resolve everything else in the subscriber.

Hint 4: Benchmark churn, not just lookup

Exercise repeated subscriber start, subscribe, publish, and exit. Static lookup alone hides lifecycle costs.

Books That Will Help

Topic Book Chapter or Section
Publish-Subscribe Channel “Enterprise Integration Patterns” Ch. 3 Messaging Channels
Process architecture “Designing for Scalability with Erlang/OTP” Processes and supervision
Stability “Release It!, 2nd Edition” Stability Patterns
Data ownership “Programming Elixir” OTP and process state chapters

Implementation Milestones

Integrated basic-to-advanced progression

  1. Implement PUB-P1 raw mailbox fanout first so ordering, death, and queue growth are visible.
  2. Replace manual subscriber bookkeeping with the PUB-P2 Registry topic bus while keeping the same observable contract.

Milestone 1 — Contract and fixture: define one representative input, output, invariant, and failure case.

Milestone 2 — Core artifact: Implement broadcast with raw sends, then Registry dispatch.

Milestone 3 — Failure behavior: add timeouts, invalid inputs, crashes, retries, or partitions appropriate to the project.

Milestone 4 — Evidence: automate the definition of done and record a reproducible result.

Phase 1: Supervised Registry — 2 hours

  • Add duplicate Registry to the application supervision tree.
  • Create two subscriber fixtures sharing a topic.
  • Prove exit cleanup.

Checkpoint: A dead fixture disappears from lookup without application cleanup code.

Phase 2: Semantic Wrapper — 3 hours

  • Define canonical topic and metadata validation.
  • Make repeated logical subscribe idempotent.
  • Define unsubscribe results.

Checkpoint: Subscribe twice, publish once, and observe exactly one copy.

Phase 3: Partition-Safe Dispatch — 3 hours

  • Add bounded dispatch and merged routing counters.
  • Exercise one and several partitions.
  • Prohibit callback I/O.

Checkpoint: All matching subscribers receive one event regardless of callback batch count.

Phase 4: Diagnostics and Churn — 2 hours

  • Add routing summaries and rate-limited snapshots.
  • Run subscriber start/exit churn.
  • Add topic-family metrics.

Checkpoint: No ghost membership remains after the churn scenario.

Phase 5: Testing and Documentation — 2–4 hours

  • Add lifecycle, duplicate, malformed metadata, and no-subscriber tests.
  • Document local-only scope and non-guarantees.
  • Record representative profile output.

Checkpoint: The README never calls sends “processed deliveries.”

Testing Strategy

6.1 Test Categories

Category Purpose Examples
Unit Validate topic and metadata rules Reject oversized or malformed values
Subscription Validate wrapper semantics NEW then ALREADY_SUBSCRIBED
Dispatch Validate fanout and filters Two west recipients, zero east recipients
Lifecycle Validate automatic cleanup Exit removes process-owned rows
Partition Validate multiple callback batches Merge counts without order assumptions
Churn Detect ghost memberships Start and stop many short-lived subscribers
Performance observation Find caller-path regressions Slow callback fixture is rejected

6.2 Critical Test Cases

  1. Two PIDs share one duplicate key and each receives one event.
  2. One PID calls logical subscribe twice and receives one copy.
  3. One PID can subscribe to two distinct topics.
  4. Unsubscribe removes only that process’s membership for the topic.
  5. Process exit removes all of its Registry entries.
  6. Publish to an empty topic returns zero entries and zero sends.
  7. Malformed metadata is rejected before registration.
  8. Partitioned dispatch reaches all entries without relying on callback order.
  9. A subscriber exits between dispatch lookup and handling; no processing claim is made.
  10. Churn leaves the final membership count at zero.

6.3 Test Data

topics:
  sensor:west
  sensor:east
  alerts:operations

subscribers:
  west_ui:    class=ui,         filter=west
  west_alert: class=alert,      filter=west
  east_ui:    class=ui,         filter=east

event:
  id=evt-7
  type=sensor.reading_changed
  schema_version=1

expected:
  publish sensor:west -> west_ui once, west_alert once
  publish sensor:east -> east_ui once
  duplicate logical subscribe by west_ui -> still one west copy
  exit west_alert -> west membership count becomes one

6.4 Benchmark Discipline

  • Warm the node before recording a profile.
  • Compare like-for-like event and membership counts.
  • Run one-partition and multi-partition profiles separately.
  • Include subscription churn, not just publication.
  • Disable verbose per-message logging in profile mode.
  • Treat results as local evidence, not universal Registry limits.

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Pitfall Symptom Solution
Raw duplicate register exposed One subscriber gets two copies Enforce wrapper idempotence
Business work inside dispatch Publish latency spikes Send only; handle in subscriber
One callback expected Missing counters or entries with partitions Merge independent callback batches
Registry treated as distributed Remote subscribers receive nothing Label node-local; add adapter later
Full user state stored as metadata Memory and dispatch cost grow Store compact routing values
Subscriber restart not registering Replacement receives nothing Subscribe in new process initialization
Raw topic in every metric label Metrics backend cardinality explodes Use bounded topic family
Lookup used as liveness proof Race causes missing handling Accept lifecycle race; use protocol receipt if needed

7.2 Debugging Strategies

  • Compare Registry keys for a PID with expected logical memberships.
  • Inspect lookup output for repeated PID-key entries when duplicate delivery occurs.
  • Temporarily log callback batch sizes and partition count, not full payloads.
  • Measure dispatch duration around the wrapper to expose expensive callbacks.
  • Monitor subscriber fixture exits to distinguish cleanup from failed registration.
  • Reduce to one partition to diagnose logic, then restore the production-like configuration.

7.3 Performance Traps

Full scans, large metadata, expensive filter predicates, and per-recipient synchronous logging can dominate fanout. More partitions are not a free speedup; they add tables and coordination and should be chosen from representative contention and membership shape. Optimize only after preserving the wrapper’s semantic invariants.

Definition of Done

Minimum Viable Completion

  • A supervised duplicate Registry holds one topic with two subscriber PIDs.
  • Publishing reaches both.
  • Subscriber exit removes its membership.

Full Completion

  • The wrapper enforces idempotent logical subscription.
  • Topic and metadata validation are explicit.
  • Partition-safe dispatch performs only bounded routing work.
  • Diagnostics show entries, sends, partitions, and duration.
  • Churn and lifecycle tests prove no ghost memberships.
  • Documentation clearly states node-local, volatile, no replay, and no processing acknowledgement.

Excellence

  • A representative churn/fanout report compares configurations without overclaiming.
  • Property-based subscription sequences preserve membership invariants.
  • The design notes identify the exact adapter seam that consolidated Project 71 will replace with Phoenix.PubSub.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • Every merged source contribution is implemented as a phase of this one artifact, not as a separate project.
  • ordering, duplicate subscription, cleanup, and slow subscribers are observable.

Project 48: Monitored Process Pool Manager

Source: ERL-P5. Lease workers, monitor borrowers, reclaim capacity, and replace failed workers.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Erlang
  • Alternative Programming Languages: Go, Rust, C
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: Level 2: Micro-SaaS / Pro Tool
  • Curriculum Difficulty: Level 2: Intermediate
  • Knowledge Area: Concurrency / Resource Management
  • Software or Tool: Worker Pool
  • Main Book: “Erlang and OTP in Action” by Logan, Merritt, Carlsson

What you will build: Lease workers, monitor borrowers, reclaim capacity, and replace failed workers.

Why it teaches the BEAM ecosystem: It makes you prove that no lease is lost or double-assigned across timeout and crash scenarios.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Lease workers, monitor borrowers, reclaim capacity, and replace failed workers.

A worker pool that maintains N worker processes, distributes tasks to available workers, queues tasks when all workers are busy, and restarts crashed workers—without using poolboy or OTP behaviors.

Build Monitored Process Pool Manager as one runnable, observable artifact. Lease workers, monitor borrowers, reclaim capacity, and replace failed workers.

Produce an evidence bundle containing:

  • one deterministic happy-path run;
  • one rejected or malformed input with an explicit reason;
  • one injected failure or boundary condition;
  • a final verification result proving: no lease is lost or double-assigned across timeout and crash scenarios.
artifact=monitored_process_pool_manager
happy_path=PASS
invalid_input=REJECTED explicit_reason=true
failure_boundary=EXERCISED recovery_evidence=true
mastery_check=PASS

The Core Question You Are Answering

“How can Monitored Process Pool Manager deliver its observable outcome while proving that no lease is lost or double-assigned across timeout and crash scenarios.”

Concepts You Must Understand First

  • Worker lifecycle (spawn, monitor, restart) → maps to process management
  • Task distribution (round-robin vs least-loaded) → maps to state management
  • Queue management (tasks waiting for workers) → maps to queue data structure
  • Handling worker crashes → maps to monitors and restart logic
  • Graceful shutdown (wait for tasks to complete) → maps to coordinated termination

Questions to Guide Your Design

  1. Which input and output contracts must remain stable across refactoring?
  2. Where should validation happen, and how will expected failures be represented?
  3. Which component owns mutable state or external effects, and what happens when it dies?
  4. What independent evidence proves this mastery condition: no lease is lost or double-assigned across timeout and crash scenarios.

Thinking Exercise

Draw Monitored Process Pool Manager as an input → decision/state → effect → evidence pipeline.

Mark every failure boundary, retry boundary, and durable state transition. Then inject one failure at each boundary and predict the observable result before implementing it.

The Interview Questions They Will Ask

  1. “What is the hardest invariant in Monitored Process Pool Manager, and where is it enforced?”
  2. “Which parts should be pure transformations and which require BEAM processes?”
  3. “How does the design behave under malformed input, process failure, or retry?”
  4. “What test or runtime evidence proves: no lease is lost or double-assigned across timeout and crash scenarios.”

Hints in Layers

Pool manager state structure:

-record(pool_state, {
    size        :: integer(),
    workers     :: [pid()],        % All worker PIDs
    available   :: [pid()],        % Idle workers
    busy        :: [{pid(), ref()}], % {Worker, TaskRef}
    queue       :: queue:queue()   % Waiting tasks
}).

Key insight: Use monitors, not links. Links propagate crashes bidirectionally. Monitors just notify you when a process dies: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

When you receive {'DOWN', Ref, process, Pid, Reason}, spawn a replacement and redistribute any queued tasks.

Hint 1: Starting Point Implement the narrowest happy path for: Lease workers, monitor borrowers, reclaim capacity, and replace failed workers.

Hint 2: Next Level Separate parsing, validation, and transition decisions from effects so each can be tested directly.

Hint 3: Technical Details Represent expected failures as tagged outcomes and keep state ownership explicit; write only structural pseudocode before implementation.

Hint 4: Tools and Debugging Inject one failure at a time, correlate it with bounded telemetry, and save a deterministic transcript as evidence.

Books That Will Help

  • Main Book: “Erlang and OTP in Action” by Logan, Merritt, Carlsson

Implementation Milestones

  1. Fixed pool runs tasks → Basic pool works
  2. Tasks queue when busy → State management correct
  3. Workers restart after crash → Monitor handling works
  4. Pool handles backpressure (rejects when queue too long) → Production-ready thinking

Testing Strategy

  • Unit checks: pure parsing, validation, transition, and formatting decisions.
  • Integration checks: the real process, database, socket, notebook, or framework boundary.
  • Failure checks: malformed input plus at least one crash, timeout, duplicate, overload, or partition scenario.
  • Acceptance check: independently demonstrate that no lease is lost or double-assigned across timeout and crash scenarios.
  • Avoid arbitrary sleeps; use messages, monitors, deterministic clocks, fixtures, and deadlines where applicable.

Common Pitfalls and Debugging

Problem 1: Happy-path output looks correct but failures disappear

  • Why: validation, effects, and reporting share one opaque step.
  • Fix: preserve tagged errors and source identity through every stage.
  • Quick test: inject one invalid record or failed dependency and verify an explicit result.

Problem 2: Tests merely repeat the implementation

  • Why: assertions reuse the same transformation or state assumptions.
  • Fix: check external invariants, golden fixtures, and observable failure behavior.
  • Quick test: introduce a deliberate ordering or boundary bug and confirm the test fails.

Definition of Done

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • no lease is lost or double-assigned across timeout and crash scenarios.

Project 49: Raw ETS Token-Bucket Rate Limiter

Source: ERL-P6. Use atomic ETS counters and timer messages for per-client refill and cleanup before introducing GenServer abstractions.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Erlang
  • Alternative Programming Languages: Go, Rust, C
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: Level 2: Micro-SaaS / Pro Tool
  • Curriculum Difficulty: Level 2: Intermediate
  • Knowledge Area: Algorithms / Concurrency
  • Software or Tool: API Rate Limiting
  • Main Book: “Programming Erlang” by Joe Armstrong

What you will build: Use atomic ETS counters and timer messages for per-client refill and cleanup before introducing GenServer abstractions.

Why it teaches the BEAM ecosystem: It makes you prove that concurrent callers cannot overspend tokens.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Use atomic ETS counters and timer messages for per-client refill and cleanup before introducing GenServer abstractions.

A token bucket rate limiter that limits requests to N per second per client, using ETS for shared state and a refill process that adds tokens periodically.

Build Raw ETS Token-Bucket Rate Limiter as one runnable, observable artifact. Use atomic ETS counters and timer messages for per-client refill and cleanup before introducing GenServer abstractions.

Produce an evidence bundle containing:

  • one deterministic happy-path run;
  • one rejected or malformed input with an explicit reason;
  • one injected failure or boundary condition;
  • a final verification result proving: concurrent callers cannot overspend tokens.
artifact=raw_ets_token-bucket_rate_limiter
happy_path=PASS
invalid_input=REJECTED explicit_reason=true
failure_boundary=EXERCISED recovery_evidence=true
mastery_check=PASS

The Core Question You Are Answering

“How can Raw ETS Token-Bucket Rate Limiter deliver its observable outcome while proving that concurrent callers cannot overspend tokens.”

Concepts You Must Understand First

  • ETS table management (create, read, update atomically) → maps to ETS operations
  • Atomic operations (check-and-decrement must be atomic) → maps to ets:update_counter/3
  • Token refill timing → maps to erlang:send_after/3
  • Multiple buckets (per-client rate limiting) → maps to table design
  • Cleanup (remove stale client entries) → maps to garbage collection patterns

Questions to Guide Your Design

  1. Which input and output contracts must remain stable across refactoring?
  2. Where should validation happen, and how will expected failures be represented?
  3. Which component owns mutable state or external effects, and what happens when it dies?
  4. What independent evidence proves this mastery condition: concurrent callers cannot overspend tokens.

Thinking Exercise

Draw Raw ETS Token-Bucket Rate Limiter as an input → decision/state → effect → evidence pipeline.

Mark every failure boundary, retry boundary, and durable state transition. Then inject one failure at each boundary and predict the observable result before implementing it.

The Interview Questions They Will Ask

  1. “What is the hardest invariant in Raw ETS Token-Bucket Rate Limiter, and where is it enforced?”
  2. “Which parts should be pure transformations and which require BEAM processes?”
  3. “How does the design behave under malformed input, process failure, or retry?”
  4. “What test or runtime evidence proves: concurrent callers cannot overspend tokens.”

Hints in Layers

Create ETS table with atomic counter support: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

The check function uses atomic update: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

The cryptic {2, -1, 0, 0} means: “Update field 2, subtract 1, but floor at 0, and if already 0 return 0.”

Hint 1: Starting Point Implement the narrowest happy path for: Use atomic ETS counters and timer messages for per-client refill and cleanup before introducing GenServer abstractions.

Hint 2: Next Level Separate parsing, validation, and transition decisions from effects so each can be tested directly.

Hint 3: Technical Details Represent expected failures as tagged outcomes and keep state ownership explicit; write only structural pseudocode before implementation.

Hint 4: Tools and Debugging Inject one failure at a time, correlate it with bounded telemetry, and save a deterministic transcript as evidence.

Books That Will Help

  • Main Book: “Programming Erlang” by Joe Armstrong

Implementation Milestones

  1. Basic rate limiting works → ETS fundamentals understood
  2. Tokens refill correctly → Timer handling works
  3. High concurrency (1000 clients) works → ETS scales

Testing Strategy

  • Unit checks: pure parsing, validation, transition, and formatting decisions.
  • Integration checks: the real process, database, socket, notebook, or framework boundary.
  • Failure checks: malformed input plus at least one crash, timeout, duplicate, overload, or partition scenario.
  • Acceptance check: independently demonstrate that concurrent callers cannot overspend tokens.
  • Avoid arbitrary sleeps; use messages, monitors, deterministic clocks, fixtures, and deadlines where applicable.

Common Pitfalls and Debugging

Problem 1: Happy-path output looks correct but failures disappear

  • Why: validation, effects, and reporting share one opaque step.
  • Fix: preserve tagged errors and source identity through every stage.
  • Quick test: inject one invalid record or failed dependency and verify an explicit result.

Problem 2: Tests merely repeat the implementation

  • Why: assertions reuse the same transformation or state assumptions.
  • Fix: check external invariants, golden fixtures, and observable failure behavior.
  • Quick test: introduce a deliberate ordering or boundary bug and confirm the test fails.

Definition of Done

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • concurrent callers cannot overspend tokens.

Project 50: Build Your Own Generic Server

Source: ERL-P7. Implement request/reply, calls, casts, timeouts, and system-message awareness.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Erlang
  • Alternative Programming Languages: None (Erlang-specific)
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: Level 2: Micro-SaaS / Pro Tool
  • Curriculum Difficulty: Level 2: Intermediate
  • Knowledge Area: OTP Internals / Behavior Design
  • Software or Tool: OTP Behaviors
  • Main Book: “Erlang and OTP in Action” by Logan, Merritt, Carlsson

What you will build: Implement request/reply, calls, casts, timeouts, and system-message awareness.

Why it teaches the BEAM ecosystem: It makes you prove that comparison with OTP explains exactly what GenServer adds.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Implement request/reply, calls, casts, timeouts, and system-message awareness.

A simplified gen_server behavior from scratch that handles call (synchronous), cast (asynchronous), info (other messages), and proper termination—understanding exactly how the real gen_server works.

Build Build Your Own Generic Server as one runnable, observable artifact. Implement request/reply, calls, casts, timeouts, and system-message awareness.

Produce an evidence bundle containing:

  • one deterministic happy-path run;
  • one rejected or malformed input with an explicit reason;
  • one injected failure or boundary condition;
  • a final verification result proving: comparison with OTP explains exactly what GenServer adds.
artifact=build_your_own_generic_server
happy_path=PASS
invalid_input=REJECTED explicit_reason=true
failure_boundary=EXERCISED recovery_evidence=true
mastery_check=PASS

The Core Question You Are Answering

“How can Build Your Own Generic Server deliver its observable outcome while proving that comparison with OTP explains exactly what GenServer adds.”

Concepts You Must Understand First

  • Synchronous call/reply (gen_server:call blocks) → maps to reference-based reply matching
  • Handling all message types (call, cast, info) → maps to message tagging
  • Callback invocation (calling module’s handle_* functions) → maps to module as parameter
  • Timeout handling → maps to receive timeouts
  • Clean termination → maps to terminate callback

Questions to Guide Your Design

  1. Which input and output contracts must remain stable across refactoring?
  2. Where should validation happen, and how will expected failures be represented?
  3. Which component owns mutable state or external effects, and what happens when it dies?
  4. What independent evidence proves this mastery condition: comparison with OTP explains exactly what GenServer adds.

Thinking Exercise

Draw Build Your Own Generic Server as an input → decision/state → effect → evidence pipeline.

Mark every failure boundary, retry boundary, and durable state transition. Then inject one failure at each boundary and predict the observable result before implementing it.

The Interview Questions They Will Ask

  1. “What is the hardest invariant in Build Your Own Generic Server, and where is it enforced?”
  2. “Which parts should be pure transformations and which require BEAM processes?”
  3. “How does the design behave under malformed input, process failure, or retry?”
  4. “What test or runtime evidence proves: comparison with OTP explains exactly what GenServer adds.”

Hints in Layers

The core receive loop: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

The call function that blocks: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Hint 1: Starting Point Implement the narrowest happy path for: Implement request/reply, calls, casts, timeouts, and system-message awareness.

Hint 2: Next Level Separate parsing, validation, and transition decisions from effects so each can be tested directly.

Hint 3: Technical Details Represent expected failures as tagged outcomes and keep state ownership explicit; write only structural pseudocode before implementation.

Hint 4: Tools and Debugging Inject one failure at a time, correlate it with bounded telemetry, and save a deterministic transcript as evidence.

Books That Will Help

  • Main Book: “Erlang and OTP in Action” by Logan, Merritt, Carlsson

Implementation Milestones

  1. Call/cast work → You understand the basic pattern
  2. Timeout works → You understand receive timeouts
  3. Use your behavior to build a real module → It’s actually usable!

Testing Strategy

  • Unit checks: pure parsing, validation, transition, and formatting decisions.
  • Integration checks: the real process, database, socket, notebook, or framework boundary.
  • Failure checks: malformed input plus at least one crash, timeout, duplicate, overload, or partition scenario.
  • Acceptance check: independently demonstrate that comparison with OTP explains exactly what GenServer adds.
  • Avoid arbitrary sleeps; use messages, monitors, deterministic clocks, fixtures, and deadlines where applicable.

Common Pitfalls and Debugging

Problem 1: Happy-path output looks correct but failures disappear

  • Why: validation, effects, and reporting share one opaque step.
  • Fix: preserve tagged errors and source identity through every stage.
  • Quick test: inject one invalid record or failed dependency and verify an explicit result.

Problem 2: Tests merely repeat the implementation

  • Why: assertions reuse the same transformation or state assumptions.
  • Fix: check external invariants, golden fixtures, and observable failure behavior.
  • Quick test: introduce a deliberate ordering or boundary bug and confirm the test fails.

Definition of Done

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • comparison with OTP explains exactly what GenServer adds.

Project 51: Monitored Build-Watcher Hub with Automatic Subscriber Cleanup

Official topic: Client-server with GenServer — Elixir v1.20.2

Source file: lib/elixir/pages/mix-and-otp/genservers.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 2: Intermediate
  • Knowledge Area: OTP / GenServer Lifecycle
  • Software or Tool: GenServer, Process.monitor, active once
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build a hub whose clients subscribe to build events, whose server monitors every follower and removes dead subscribers, and whose experiments compare call, cast, info, and active-once flow control.

Why it teaches this official topic: The artifact makes links versus monitors, GenServer client and callbacks, call cast and info selection, subscriber cleanup and flow control observable through one bounded build instead of isolated syntax examples.

Scope boundary: Center lifecycle correctness; do not duplicate the raw topic bus, chat service, or generic-server implementation.

Core challenges you will face:

  • links versus monitors -> identify the accepted case, the counterexample, and the observable result at the GenServer, Process.monitor, active once boundary
  • GenServer client and callbacks -> identify the accepted case, the counterexample, and the observable result at the GenServer, Process.monitor, active once boundary
  • call cast and info selection -> identify the accepted case, the counterexample, and the observable result at the GenServer, Process.monitor, active once boundary
  • subscriber cleanup and flow control -> identify the accepted case, the counterexample, and the observable result at the GenServer, Process.monitor, active once boundary

Real World Outcome

Build a hub whose clients subscribe to build events, whose server monitors every follower and removes dead subscribers, and whose experiments compare call, cast, info, and active-once flow control. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Dead subscribers are removed through DOWN messages.
  • Synchronous and asynchronous API choices are justified.
  • Mailbox growth is bounded in the active-once experiment.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=mix-and-otp/genservers.md
ARTIFACT=monitored-build-watcher-hub-with-automatic-subscriber-cleanup
CHECK 01 PASS :: Dead subscribers are removed through DOWN messages
CHECK 02 PASS :: Synchronous and asynchronous API choices are justified
CHECK 03 PASS :: Mailbox growth is bounded in the active-once experiment
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“How does a GenServer turn message protocols and lifecycle cleanup into an explicit client-server contract?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. links versus monitors
    • Working rule: Make “links versus monitors” an explicit rule at the GenServer, Process.monitor, active once boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "links-versus-monitors-positive", focus: "links versus monitors", mode: :positive, expect: :observable} and %{id: "links-versus-monitors-negative", focus: "links versus monitors", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Client-server with GenServer
  2. GenServer client and callbacks
    • Working rule: Make “GenServer client and callbacks” an explicit rule at the GenServer, Process.monitor, active once boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "genserver-client-and-callbacks-positive", focus: "GenServer client and callbacks", mode: :positive, expect: :observable} and %{id: "genserver-client-and-callbacks-negative", focus: "GenServer client and callbacks", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Client-server with GenServer
  3. call cast and info selection
    • Working rule: Make “call cast and info selection” an explicit rule at the GenServer, Process.monitor, active once boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "call-cast-and-info-selection-positive", focus: "call cast and info selection", mode: :positive, expect: :observable} and %{id: "call-cast-and-info-selection-negative", focus: "call cast and info selection", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Client-server with GenServer
  4. subscriber cleanup and flow control
    • Working rule: Make “subscriber cleanup and flow control” an explicit rule at the GenServer, Process.monitor, active once boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "subscriber-cleanup-and-flow-control-positive", focus: "subscriber cleanup and flow control", mode: :positive, expect: :observable} and %{id: "subscriber-cleanup-and-flow-control-negative", focus: "subscriber cleanup and flow control", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Client-server with GenServer

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “links versus monitors” be enforced?
    • Which check catches the risk “A cast is used where the caller needs confirmation”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Dead subscribers are removed through DOWN messages”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Client-server with GenServer”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: links versus monitors, GenServer client and callbacks, call cast and info selection, subscriber cleanup and flow control. Then trace the named counterexample “A cast is used where the caller needs confirmation” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose links versus monitors, and what does this project prove about it?”
  2. “What interaction between the concept ‘GenServer client and callbacks’ and the concept ‘links versus monitors’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘A cast is used where the caller needs confirmation’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with links-versus-monitors-positive and a-cast-is-used-where-the-caller-needs-confirmation-counterexample. The first must make the concept “links versus monitors” observable and establish “Dead subscribers are removed through DOWN messages”; the second must reproduce “A cast is used where the caller needs confirmation”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for mix-and-otp/genservers.md
evaluate "links versus monitors" through GenServer, Process.monitor, active once
compare actual evidence with "Dead subscribers are removed through DOWN messages"
run negative fixture for "A cast is used where the caller needs confirmation"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Client-server with GenServer Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
links versus monitors Elixir in Action, 3rd Edition Ch. 6-7: GenServer and fault tolerance
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement links-versus-monitors-positive and prove “Dead subscribers are removed through DOWN messages”.
  3. Topic coverage: add fixtures for GenServer client and callbacks, call cast and info selection, subscriber cleanup and flow control.
  4. Failure campaign: reproduce each named risk: “A cast is used where the caller needs confirmation”; “Monitor references are not correlated”; “Active sockets flood an unbounded mailbox”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute links-versus-monitors-positive, genserver-client-and-callbacks-positive, call-cast-and-info-selection-positive, subscriber-cleanup-and-flow-control-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute links-versus-monitors-negative, genserver-client-and-callbacks-negative, call-cast-and-info-selection-negative, subscriber-cleanup-and-flow-control-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute a-cast-is-used-where-the-caller-needs-confirmation-counterexample, monitor-references-are-not-correlated-counterexample, active-sockets-flood-an-unbounded-mailbox-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real GenServer, Process.monitor, active once boundary from a clean shell.
  • Mutation check: violate “Dead subscribers are removed through DOWN messages” and prove the suite reports fixture links-versus-monitors-positive as failed.
  • Regression corpus: retain the risks “A cast is used where the caller needs confirmation”; “Monitor references are not correlated”; “Active sockets flood an unbounded mailbox” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “A cast is used where the caller needs confirmation”

  • Why: This breaks one or more observable capabilities at the GenServer, Process.monitor, active once boundary while allowing the happy path to look correct.
  • Fix: Run a-cast-is-used-where-the-caller-needs-confirmation-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “Monitor references are not correlated”

  • Why: This breaks one or more observable capabilities at the GenServer, Process.monitor, active once boundary while allowing the happy path to look correct.
  • Fix: Run monitor-references-are-not-correlated-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “Active sockets flood an unbounded mailbox”

  • Why: This breaks one or more observable capabilities at the GenServer, Process.monitor, active once boundary while allowing the happy path to look correct.
  • Fix: Run active-sockets-flood-an-unbounded-mailbox-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • Dead subscribers are removed through DOWN messages.
  • Synchronous and asynchronous API choices are justified.
  • Mailbox growth is bounded in the active-once experiment.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 52: Support Session Directory with Registry and Application Lifecycle

Official topic: Registries and supervision trees — Elixir v1.20.2

Source file: lib/elixir/pages/mix-and-otp/supervisor-and-application.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 2: Intermediate
  • Knowledge Area: OTP Applications / Registry
  • Software or Tool: Application, Supervisor, Registry
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build supervised support-session processes addressed by arbitrary external ticket IDs through Registry, with an application callback, dependency and boot-order checks, graceful shutdown, and restart evidence.

Why it teaches this official topic: The artifact makes safe process naming, OTP application lifecycle, static supervision trees, startup and shutdown ordering observable through one bounded build instead of isolated syntax examples.

Scope boundary: Focus on safe naming and application lifecycle, not strategy visualization or distributed discovery.

Core challenges you will face:

  • safe process naming -> identify the accepted case, the counterexample, and the observable result at the Application, Supervisor, Registry boundary
  • OTP application lifecycle -> identify the accepted case, the counterexample, and the observable result at the Application, Supervisor, Registry boundary
  • static supervision trees -> identify the accepted case, the counterexample, and the observable result at the Application, Supervisor, Registry boundary
  • startup and shutdown ordering -> identify the accepted case, the counterexample, and the observable result at the Application, Supervisor, Registry boundary

Real World Outcome

Build supervised support-session processes addressed by arbitrary external ticket IDs through Registry, with an application callback, dependency and boot-order checks, graceful shutdown, and restart evidence. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • No external ticket identifier becomes an atom.
  • Application boot starts dependencies and children in order.
  • A crashed session is recovered without corrupting the directory.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=mix-and-otp/supervisor-and-application.md
ARTIFACT=support-session-directory-with-registry-and-application-lifecycle
CHECK 01 PASS :: No external ticket identifier becomes an atom
CHECK 02 PASS :: Application boot starts dependencies and children in order
CHECK 03 PASS :: A crashed session is recovered without corrupting the directory
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“How do Registry, Application, and Supervisor collaborate to make named process lifecycle repeatable?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. safe process naming
    • Working rule: Make “safe process naming” an explicit rule at the Application, Supervisor, Registry boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "safe-process-naming-positive", focus: "safe process naming", mode: :positive, expect: :observable} and %{id: "safe-process-naming-negative", focus: "safe process naming", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Registries and supervision trees
  2. OTP application lifecycle
    • Working rule: Make “OTP application lifecycle” an explicit rule at the Application, Supervisor, Registry boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "otp-application-lifecycle-positive", focus: "OTP application lifecycle", mode: :positive, expect: :observable} and %{id: "otp-application-lifecycle-negative", focus: "OTP application lifecycle", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Registries and supervision trees
  3. static supervision trees
    • Working rule: Make “static supervision trees” an explicit rule at the Application, Supervisor, Registry boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "static-supervision-trees-positive", focus: "static supervision trees", mode: :positive, expect: :observable} and %{id: "static-supervision-trees-negative", focus: "static supervision trees", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Registries and supervision trees
  4. startup and shutdown ordering
    • Working rule: Make “startup and shutdown ordering” an explicit rule at the Application, Supervisor, Registry boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "startup-and-shutdown-ordering-positive", focus: "startup and shutdown ordering", mode: :positive, expect: :observable} and %{id: "startup-and-shutdown-ordering-negative", focus: "startup and shutdown ordering", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Registries and supervision trees

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “safe process naming” be enforced?
    • Which check catches the risk “Dynamic atoms exhaust the atom table”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “No external ticket identifier becomes an atom”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Registries and supervision trees”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: safe process naming, OTP application lifecycle, static supervision trees, startup and shutdown ordering. Then trace the named counterexample “Dynamic atoms exhaust the atom table” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose safe process naming, and what does this project prove about it?”
  2. “What interaction between the concept ‘OTP application lifecycle’ and the concept ‘safe process naming’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘Dynamic atoms exhaust the atom table’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with safe-process-naming-positive and dynamic-atoms-exhaust-the-atom-table-counterexample. The first must make the concept “safe process naming” observable and establish “No external ticket identifier becomes an atom”; the second must reproduce “Dynamic atoms exhaust the atom table”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for mix-and-otp/supervisor-and-application.md
evaluate "safe process naming" through Application, Supervisor, Registry
compare actual evidence with "No external ticket identifier becomes an atom"
run negative fixture for "Dynamic atoms exhaust the atom table"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Registries and supervision trees Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
safe process naming Elixir in Action, 3rd Edition Ch. 8: supervision trees
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement safe-process-naming-positive and prove “No external ticket identifier becomes an atom”.
  3. Topic coverage: add fixtures for OTP application lifecycle, static supervision trees, startup and shutdown ordering.
  4. Failure campaign: reproduce each named risk: “Dynamic atoms exhaust the atom table”; “A child starts before its Registry”; “Application stop leaves unmanaged processes”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute safe-process-naming-positive, otp-application-lifecycle-positive, static-supervision-trees-positive, startup-and-shutdown-ordering-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute safe-process-naming-negative, otp-application-lifecycle-negative, static-supervision-trees-negative, startup-and-shutdown-ordering-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute dynamic-atoms-exhaust-the-atom-table-counterexample, a-child-starts-before-its-registry-counterexample, application-stop-leaves-unmanaged-processes-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real Application, Supervisor, Registry boundary from a clean shell.
  • Mutation check: violate “No external ticket identifier becomes an atom” and prove the suite reports fixture safe-process-naming-positive as failed.
  • Regression corpus: retain the risks “Dynamic atoms exhaust the atom table”; “A child starts before its Registry”; “Application stop leaves unmanaged processes” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “Dynamic atoms exhaust the atom table”

  • Why: This breaks one or more observable capabilities at the Application, Supervisor, Registry boundary while allowing the happy path to look correct.
  • Fix: Run dynamic-atoms-exhaust-the-atom-table-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “A child starts before its Registry”

  • Why: This breaks one or more observable capabilities at the Application, Supervisor, Registry boundary while allowing the happy path to look correct.
  • Fix: Run a-child-starts-before-its-registry-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “Application stop leaves unmanaged processes”

  • Why: This breaks one or more observable capabilities at the Application, Supervisor, Registry boundary while allowing the happy path to look correct.
  • Fix: Run application-stop-leaves-unmanaged-processes-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • No external ticket identifier becomes an atom.
  • Application boot starts dependencies and children in order.
  • A crashed session is recovered without corrupting the directory.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 53: On-Demand Customer Workspace Supervisor

Official topic: Supervising dynamic children — Elixir v1.20.2

Source file: lib/elixir/pages/mix-and-otp/dynamic-supervisor.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 2: Intermediate
  • Knowledge Area: OTP / Dynamic Supervision
  • Software or Tool: DynamicSupervisor, Registry, Observer
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build create, locate, stop, crash, and restart operations for one isolated runtime per customer, using DynamicSupervisor, registry-backed names, explicit child specs, test-owned processes, and Observer evidence.

Why it teaches this official topic: The artifact makes child specifications, runtime child creation, dynamic names, test supervision and Observer observable through one bounded build instead of isolated syntax examples.

Scope boundary: Own runtime-created child lifecycle; exclude worker pools, chat rooms, and dynamic database repositories.

Core challenges you will face:

  • child specifications -> identify the accepted case, the counterexample, and the observable result at the DynamicSupervisor, Registry, Observer boundary
  • runtime child creation -> identify the accepted case, the counterexample, and the observable result at the DynamicSupervisor, Registry, Observer boundary
  • dynamic names -> identify the accepted case, the counterexample, and the observable result at the DynamicSupervisor, Registry, Observer boundary
  • test supervision and Observer -> identify the accepted case, the counterexample, and the observable result at the DynamicSupervisor, Registry, Observer boundary

Real World Outcome

Build create, locate, stop, crash, and restart operations for one isolated runtime per customer, using DynamicSupervisor, registry-backed names, explicit child specs, test-owned processes, and Observer evidence. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Duplicate customer starts return an explicit result.
  • Each test owns and cleans its workspace.
  • Crash replacement is visible through pid and Observer evidence.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=mix-and-otp/dynamic-supervisor.md
ARTIFACT=on-demand-customer-workspace-supervisor
CHECK 01 PASS :: Duplicate customer starts return an explicit result
CHECK 02 PASS :: Each test owns and cleans its workspace
CHECK 03 PASS :: Crash replacement is visible through pid and Observer evidence
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“What lifecycle contract is required when supervised children are discovered only at runtime?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. child specifications
    • Working rule: Make “child specifications” an explicit rule at the DynamicSupervisor, Registry, Observer boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "child-specifications-positive", focus: "child specifications", mode: :positive, expect: :observable} and %{id: "child-specifications-negative", focus: "child specifications", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Supervising dynamic children
  2. runtime child creation
    • Working rule: Make “runtime child creation” an explicit rule at the DynamicSupervisor, Registry, Observer boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "runtime-child-creation-positive", focus: "runtime child creation", mode: :positive, expect: :observable} and %{id: "runtime-child-creation-negative", focus: "runtime child creation", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Supervising dynamic children
  3. dynamic names
    • Working rule: Make “dynamic names” an explicit rule at the DynamicSupervisor, Registry, Observer boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "dynamic-names-positive", focus: "dynamic names", mode: :positive, expect: :observable} and %{id: "dynamic-names-negative", focus: "dynamic names", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Supervising dynamic children
  4. test supervision and Observer
    • Working rule: Make “test supervision and Observer” an explicit rule at the DynamicSupervisor, Registry, Observer boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "test-supervision-and-observer-positive", focus: "test supervision and Observer", mode: :positive, expect: :observable} and %{id: "test-supervision-and-observer-negative", focus: "test supervision and Observer", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Supervising dynamic children

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “child specifications” be enforced?
    • Which check catches the risk “Child identifiers collide under one supervisor”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Duplicate customer starts return an explicit result”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Supervising dynamic children”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: child specifications, runtime child creation, dynamic names, test supervision and Observer. Then trace the named counterexample “Child identifiers collide under one supervisor” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose child specifications, and what does this project prove about it?”
  2. “What interaction between the concept ‘runtime child creation’ and the concept ‘child specifications’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘Child identifiers collide under one supervisor’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with child-specifications-positive and child-identifiers-collide-under-one-supervisor-counterexample. The first must make the concept “child specifications” observable and establish “Duplicate customer starts return an explicit result”; the second must reproduce “Child identifiers collide under one supervisor”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for mix-and-otp/dynamic-supervisor.md
evaluate "child specifications" through DynamicSupervisor, Registry, Observer
compare actual evidence with "Duplicate customer starts return an explicit result"
run negative fixture for "Child identifiers collide under one supervisor"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Supervising dynamic children Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
child specifications Elixir in Action, 3rd Edition Ch. 8: dynamic supervision
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement child-specifications-positive and prove “Duplicate customer starts return an explicit result”.
  3. Topic coverage: add fixtures for runtime child creation, dynamic names, test supervision and Observer.
  4. Failure campaign: reproduce each named risk: “Child identifiers collide under one supervisor”; “Tests start unmanaged linked processes”; “A restart loses the external customer mapping”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute child-specifications-positive, runtime-child-creation-positive, dynamic-names-positive, test-supervision-and-observer-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute child-specifications-negative, runtime-child-creation-negative, dynamic-names-negative, test-supervision-and-observer-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute child-identifiers-collide-under-one-supervisor-counterexample, tests-start-unmanaged-linked-processes-counterexample, a-restart-loses-the-external-customer-mapping-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real DynamicSupervisor, Registry, Observer boundary from a clean shell.
  • Mutation check: violate “Duplicate customer starts return an explicit result” and prove the suite reports fixture child-specifications-positive as failed.
  • Regression corpus: retain the risks “Child identifiers collide under one supervisor”; “Tests start unmanaged linked processes”; “A restart loses the external customer mapping” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “Child identifiers collide under one supervisor”

  • Why: This breaks one or more observable capabilities at the DynamicSupervisor, Registry, Observer boundary while allowing the happy path to look correct.
  • Fix: Run child-identifiers-collide-under-one-supervisor-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “Tests start unmanaged linked processes”

  • Why: This breaks one or more observable capabilities at the DynamicSupervisor, Registry, Observer boundary while allowing the happy path to look correct.
  • Fix: Run tests-start-unmanaged-linked-processes-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “A restart loses the external customer mapping”

  • Why: This breaks one or more observable capabilities at the DynamicSupervisor, Registry, Observer boundary while allowing the happy path to look correct.
  • Fix: Run a-restart-loses-the-external-customer-mapping-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • Duplicate customer starts return an explicit result.
  • Each test owns and cleans its workspace.
  • Crash replacement is visible through pid and Observer evidence.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 54: Concurrent TCP Health-Check Console with Isolated Client Sessions

Official topic: Task and gen_tcp — Elixir v1.20.2

Source file: lib/elixir/pages/mix-and-otp/task-and-gen-tcp.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 2: Intermediate
  • Knowledge Area: Networking / Supervised Tasks
  • Software or Tool: gen_tcp, Task.Supervisor
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build a line-oriented TCP console where Task.Supervisor owns concurrent client sessions, socket controlling processes transfer explicitly, and one crashing client cannot terminate the acceptor or peers.

Why it teaches this official topic: The artifact makes passive TCP sockets, per-connection Tasks, socket controlling process, restart semantics observable through one bounded build instead of isolated syntax examples.

Scope boundary: Begin where the raw echo server ends: teach supervised task isolation and ownership transfer, not echo mechanics.

Core challenges you will face:

  • passive TCP sockets -> identify the accepted case, the counterexample, and the observable result at the gen_tcp, Task.Supervisor boundary
  • per-connection Tasks -> identify the accepted case, the counterexample, and the observable result at the gen_tcp, Task.Supervisor boundary
  • socket controlling process -> identify the accepted case, the counterexample, and the observable result at the gen_tcp, Task.Supervisor boundary
  • restart semantics -> identify the accepted case, the counterexample, and the observable result at the gen_tcp, Task.Supervisor boundary

Real World Outcome

Build a line-oriented TCP console where Task.Supervisor owns concurrent client sessions, socket controlling processes transfer explicitly, and one crashing client cannot terminate the acceptor or peers. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Concurrent clients receive independent responses.
  • Socket ownership is transferred before the session reads.
  • Session crashes leave the acceptor and peers alive.

Acceptance transcript:

$ mix test test/tcp_health_console_integration_test.exs
SOURCE_TOPIC=mix-and-otp/task-and-gen-tcp.md
ARTIFACT=concurrent-tcp-health-check-console-with-isolated-client-sessions
CHECK 01 PASS :: Concurrent clients receive independent responses
CHECK 02 PASS :: Socket ownership is transferred before the session reads
CHECK 03 PASS :: Session crashes leave the acceptor and peers alive
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“How should TCP connection ownership move into supervised Tasks without coupling unrelated client failures?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. passive TCP sockets
    • Working rule: Make “passive TCP sockets” an explicit rule at the gen_tcp, Task.Supervisor boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "passive-tcp-sockets-positive", focus: "passive TCP sockets", mode: :positive, expect: :observable} and %{id: "passive-tcp-sockets-negative", focus: "passive TCP sockets", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Task and gen_tcp
  2. per-connection Tasks
    • Working rule: Make “per-connection Tasks” an explicit rule at the gen_tcp, Task.Supervisor boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "per-connection-tasks-positive", focus: "per-connection Tasks", mode: :positive, expect: :observable} and %{id: "per-connection-tasks-negative", focus: "per-connection Tasks", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Task and gen_tcp
  3. socket controlling process
    • Working rule: Make “socket controlling process” an explicit rule at the gen_tcp, Task.Supervisor boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "socket-controlling-process-positive", focus: "socket controlling process", mode: :positive, expect: :observable} and %{id: "socket-controlling-process-negative", focus: "socket controlling process", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Task and gen_tcp
  4. restart semantics
    • Working rule: Make “restart semantics” an explicit rule at the gen_tcp, Task.Supervisor boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "restart-semantics-positive", focus: "restart semantics", mode: :positive, expect: :observable} and %{id: "restart-semantics-negative", focus: "restart semantics", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Task and gen_tcp

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “passive TCP sockets” be enforced?
    • Which check catches the risk “A Task reads a socket it does not own”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Concurrent clients receive independent responses”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Task and gen_tcp”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: passive TCP sockets, per-connection Tasks, socket controlling process, restart semantics. Then trace the named counterexample “A Task reads a socket it does not own” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose passive TCP sockets, and what does this project prove about it?”
  2. “What interaction between the concept ‘per-connection Tasks’ and the concept ‘passive TCP sockets’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘A Task reads a socket it does not own’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with passive-tcp-sockets-positive and a-task-reads-a-socket-it-does-not-own-counterexample. The first must make the concept “passive TCP sockets” observable and establish “Concurrent clients receive independent responses”; the second must reproduce “A Task reads a socket it does not own”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for mix-and-otp/task-and-gen-tcp.md
evaluate "passive TCP sockets" through gen_tcp, Task.Supervisor
compare actual evidence with "Concurrent clients receive independent responses"
run negative fixture for "A Task reads a socket it does not own"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix test test/tcp_health_console_integration_test.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Task and gen_tcp Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
passive TCP sockets Elixir in Action, 3rd Edition Ch. 6-8: tasks, sockets, and supervisors
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement passive-tcp-sockets-positive and prove “Concurrent clients receive independent responses”.
  3. Topic coverage: add fixtures for per-connection Tasks, socket controlling process, restart semantics.
  4. Failure campaign: reproduce each named risk: “A Task reads a socket it does not own”; “Linked session failure kills the acceptor”; “A temporary client is configured for permanent restart”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute passive-tcp-sockets-positive, per-connection-tasks-positive, socket-controlling-process-positive, restart-semantics-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute passive-tcp-sockets-negative, per-connection-tasks-negative, socket-controlling-process-negative, restart-semantics-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute a-task-reads-a-socket-it-does-not-own-counterexample, linked-session-failure-kills-the-acceptor-counterexample, a-temporary-client-is-configured-for-permanent-restart-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix test test/tcp_health_console_integration_test.exs through the real gen_tcp, Task.Supervisor boundary from a clean shell.
  • Mutation check: violate “Concurrent clients receive independent responses” and prove the suite reports fixture passive-tcp-sockets-positive as failed.
  • Regression corpus: retain the risks “A Task reads a socket it does not own”; “Linked session failure kills the acceptor”; “A temporary client is configured for permanent restart” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “A Task reads a socket it does not own”

  • Why: This breaks one or more observable capabilities at the gen_tcp, Task.Supervisor boundary while allowing the happy path to look correct.
  • Fix: Run a-task-reads-a-socket-it-does-not-own-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix test test/tcp_health_console_integration_test.exs

Problem 2: “Linked session failure kills the acceptor”

  • Why: This breaks one or more observable capabilities at the gen_tcp, Task.Supervisor boundary while allowing the happy path to look correct.
  • Fix: Run linked-session-failure-kills-the-acceptor-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix test test/tcp_health_console_integration_test.exs

Problem 3: “A temporary client is configured for permanent restart”

  • Why: This breaks one or more observable capabilities at the gen_tcp, Task.Supervisor boundary while allowing the happy path to look correct.
  • Fix: Run a-temporary-client-is-configured-for-permanent-restart-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix test test/tcp_health_console_integration_test.exs

Definition of Done

  • Concurrent clients receive independent responses.
  • Socket ownership is transferred before the session reads.
  • Session crashes leave the acceptor and peers alive.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 55: Warehouse Scanner Protocol with Executable Documentation

Official topic: Doctests, patterns, and with — Elixir v1.20.2

Source file: lib/elixir/pages/mix-and-otp/docs-tests-and-with.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 2: Intermediate
  • Knowledge Area: Executable Documentation / Integration Tests
  • Software or Tool: ExUnit, doctest, with, gen_tcp
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build RECEIVE, MOVE, and COUNT scanner commands whose parser and dispatcher use patterns and with, whose docs contain executable examples, and whose integration suite crosses a real TCP boundary.

Why it teaches this official topic: The artifact makes doctests, pattern-driven parsing, with failure pipelines, real-boundary integration tests observable through one bounded build instead of isolated syntax examples.

Scope boundary: Own docs-as-contract, parsing, with, and one real integration boundary; exclude the Phoenix-wide test pyramid.

Core challenges you will face:

  • doctests -> identify the accepted case, the counterexample, and the observable result at the ExUnit, doctest, with, gen_tcp boundary
  • pattern-driven parsing -> identify the accepted case, the counterexample, and the observable result at the ExUnit, doctest, with, gen_tcp boundary
  • with failure pipelines -> identify the accepted case, the counterexample, and the observable result at the ExUnit, doctest, with, gen_tcp boundary
  • real-boundary integration tests -> identify the accepted case, the counterexample, and the observable result at the ExUnit, doctest, with, gen_tcp boundary

Real World Outcome

Build RECEIVE, MOVE, and COUNT scanner commands whose parser and dispatcher use patterns and with, whose docs contain executable examples, and whose integration suite crosses a real TCP boundary. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Published command examples execute as doctests.
  • Every with failure retains a named error.
  • Socket tests cover success, malformed input, and unique resources.

Acceptance transcript:

$ mix test --include integration
SOURCE_TOPIC=mix-and-otp/docs-tests-and-with.md
ARTIFACT=warehouse-scanner-protocol-with-executable-documentation
CHECK 01 PASS :: Published command examples execute as doctests
CHECK 02 PASS :: Every with failure retains a named error
CHECK 03 PASS :: Socket tests cover success, malformed input, and unique resources
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“How can public examples, parser clauses, and end-to-end tests express one executable protocol contract?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. doctests
    • Working rule: Make “doctests” an explicit rule at the ExUnit, doctest, with, gen_tcp boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "doctests-positive", focus: "doctests", mode: :positive, expect: :observable} and %{id: "doctests-negative", focus: "doctests", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Doctests, patterns, and with
  2. pattern-driven parsing
    • Working rule: Make “pattern-driven parsing” an explicit rule at the ExUnit, doctest, with, gen_tcp boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "pattern-driven-parsing-positive", focus: "pattern-driven parsing", mode: :positive, expect: :observable} and %{id: "pattern-driven-parsing-negative", focus: "pattern-driven parsing", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Doctests, patterns, and with
  3. with failure pipelines
    • Working rule: Make “with failure pipelines” an explicit rule at the ExUnit, doctest, with, gen_tcp boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "with-failure-pipelines-positive", focus: "with failure pipelines", mode: :positive, expect: :observable} and %{id: "with-failure-pipelines-negative", focus: "with failure pipelines", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Doctests, patterns, and with
  4. real-boundary integration tests
    • Working rule: Make “real-boundary integration tests” an explicit rule at the ExUnit, doctest, with, gen_tcp boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "real-boundary-integration-tests-positive", focus: "real-boundary integration tests", mode: :positive, expect: :observable} and %{id: "real-boundary-integration-tests-negative", focus: "real-boundary integration tests", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Doctests, patterns, and with

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “doctests” be enforced?
    • Which check catches the risk “Doctest output is nondeterministic”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Published command examples execute as doctests”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Doctests, patterns, and with”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: doctests, pattern-driven parsing, with failure pipelines, real-boundary integration tests. Then trace the named counterexample “Doctest output is nondeterministic” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose doctests, and what does this project prove about it?”
  2. “What interaction between the concept ‘pattern-driven parsing’ and the concept ‘doctests’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘Doctest output is nondeterministic’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with doctests-positive and doctest-output-is-nondeterministic-counterexample. The first must make the concept “doctests” observable and establish “Published command examples execute as doctests”; the second must reproduce “Doctest output is nondeterministic”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for mix-and-otp/docs-tests-and-with.md
evaluate "doctests" through ExUnit, doctest, with, gen_tcp
compare actual evidence with "Published command examples execute as doctests"
run negative fixture for "Doctest output is nondeterministic"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix test --include integration from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Doctests, patterns, and with Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
doctests Elixir in Action, 3rd Edition Ch. 4 and 7: abstractions and testing
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement doctests-positive and prove “Published command examples execute as doctests”.
  3. Topic coverage: add fixtures for pattern-driven parsing, with failure pipelines, real-boundary integration tests.
  4. Failure campaign: reproduce each named risk: “Doctest output is nondeterministic”; “A complex else clause obscures the failing stage”; “Integration tests share a fixed port or process name”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute doctests-positive, pattern-driven-parsing-positive, with-failure-pipelines-positive, real-boundary-integration-tests-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute doctests-negative, pattern-driven-parsing-negative, with-failure-pipelines-negative, real-boundary-integration-tests-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute doctest-output-is-nondeterministic-counterexample, a-complex-else-clause-obscures-the-failing-stage-counterexample, integration-tests-share-a-fixed-port-or-process-name-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix test --include integration through the real ExUnit, doctest, with, gen_tcp boundary from a clean shell.
  • Mutation check: violate “Published command examples execute as doctests” and prove the suite reports fixture doctests-positive as failed.
  • Regression corpus: retain the risks “Doctest output is nondeterministic”; “A complex else clause obscures the failing stage”; “Integration tests share a fixed port or process name” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “Doctest output is nondeterministic”

  • Why: This breaks one or more observable capabilities at the ExUnit, doctest, with, gen_tcp boundary while allowing the happy path to look correct.
  • Fix: Run doctest-output-is-nondeterministic-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix test --include integration

Problem 2: “A complex else clause obscures the failing stage”

  • Why: This breaks one or more observable capabilities at the ExUnit, doctest, with, gen_tcp boundary while allowing the happy path to look correct.
  • Fix: Run a-complex-else-clause-obscures-the-failing-stage-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix test --include integration

Problem 3: “Integration tests share a fixed port or process name”

  • Why: This breaks one or more observable capabilities at the ExUnit, doctest, with, gen_tcp boundary while allowing the happy path to look correct.
  • Fix: Run integration-tests-share-a-fixed-port-or-process-name-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix test --include integration

Definition of Done

  • Published command examples execute as doctests.
  • Every with failure retains a named error.
  • Socket tests cover success, malformed input, and unique resources.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 56: Supervised Multi-Room Chat Service

Source: BEAM-P1. Build process-per-room chat with registration and isolated recovery.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: Level 2: Micro-SaaS / Pro Tool
  • Curriculum Difficulty: Level 2: Intermediate
  • Knowledge Area: Concurrency, Fault Tolerance
  • Software or Tool: OTP/GenServer
  • Main Book: “Programming Erlang”

What you will build: Build process-per-room chat with registration and isolated recovery.

Why it teaches the BEAM ecosystem: It makes you prove that crashing one room restarts only its intended failure domain.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Build process-per-room chat with registration and isolated recovery.

Build a supervised process-per-room chat service. Rooms register by name, sequence messages, isolate failures, and restart without taking unrelated rooms down. The demo must expose the old and new room process identities and prove that the unaffected room retained service.

$ mix chat.demo --fault kill-lobby
room=lobby joined=[alice,bob] pid=old_lobby
room=ops joined=[carol] pid=ops_pid
message room=lobby seq=1 from=alice body=hello
FAULT room=lobby reason=injected_crash
RECOVERY room=lobby old_pid=old_lobby new_pid=new_lobby restarted=true
CHECK room=ops pid=ops_pid responsive=true
CHECK supervisor_alive=true result=PASS

The Core Question You Are Answering

“How do I make this service recover automatically without global failure?”

Concepts You Must Understand First

  • Review the concepts above and ensure you can explain them clearly.

Questions to Guide Your Design

  1. How will you partition work across processes?
  2. Where is state stored and how is it protected?
  3. What happens when a worker crashes?

Thinking Exercise

Sketch the message flow and failure paths before coding.

The Interview Questions They Will Ask

  1. “Why does this design scale better than shared-memory locks?”
  2. “How do you detect and recover from failures?”
  3. “How do you prevent mailbox buildup?”
  4. “Which measurement would tell you that Supervised Multi-Room Chat Service is approaching its operating limit?”

Hints in Layers

Hint 1: Start with one worker process and a single message type.

Hint 2: Add supervision and confirm restart behavior.

Hint 3: Add routing and concurrency only after correctness.

Hint 4: Validate output with scripted test vectors.

Books That Will Help

Topic Book Chapter
Core BEAM “Programming Erlang” Processes chapter
OTP “Designing for Scalability with Erlang/OTP” Supervision chapter

Implementation Milestones

Phase 1: Foundation (2-4 hours)

  • Build a single worker process
  • Define message shapes

Phase 2: Core Functionality (4-8 hours)

  • Add routing and state storage
  • Validate correctness on test cases

Phase 3: Polish & Edge Cases (2-4 hours)

  • Add failure injection tests
  • Document recovery behavior

Testing Strategy

6.1 Test Categories

Category Purpose Examples
Unit Tests Validate core logic message parsing
Integration Tests End-to-end flow demo scenario
Failure Tests Crash recovery kill worker

6.2 Critical Test Cases

  1. Normal path: request -> response
  2. Crash path: worker exit -> restart
  3. Overload: burst input -> bounded queue

6.3 Test Data

inputs: demo messages
expected: stable outputs

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Pitfall Symptom Solution
Missing supervisor app dies on crash add supervisor
Oversized mailbox latency spikes split processes
Unbounded state memory growth add eviction

7.2 Debugging Strategies

  • Use observer to inspect process counts and queues
  • Add structured logs on message receive

7.3 Performance Traps

  • Avoid heavy work in a single process

Definition of Done

  • Each room is its own process
  • Rooms restart on crash without affecting others
  • Messages still flow after a restart
  • Process tree visible in observer

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • crashing one room restarts only its intended failure domain.

Project 57: Supervision Strategy Fault Lab

Sources: BEAM-P6, PHX-P2. Wrap TCP and synthetic workers in supervision trees and inject faults.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: Level 2: Micro-SaaS / Pro Tool
  • Curriculum Difficulty: Level 2: Intermediate
  • Knowledge Area: Fault Tolerance
  • Software or Tool: OTP Supervision
  • Main Book: “Designing for Scalability with Erlang/OTP”

What you will build: Wrap TCP and synthetic workers in supervision trees and inject faults.

Why it teaches the BEAM ecosystem: It makes you prove that traces prove restart strategy, intensity, and child-order effects.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Integrated Scope

This is one consolidated project, not separate source builds. Implement the following contributions as phases of the same artifact:

  • Begin with PHX-P2 supervision of the TCP service and prove basic child isolation.
  • Add BEAM-P6 fault injection, restart-intensity evidence, and strategy comparisons to the same harness.

Real World Outcome

Build target: Wrap TCP and synthetic workers in supervision trees and inject faults.

Build one deterministic supervision laboratory around the TCP service and synthetic workers. Run the same fault script under one_for_one, rest_for_one, and one_for_all, then exceed restart intensity and record exactly which children and supervisors restart.

$ mix supervision_lab.run --fault worker_b --repeat 4
strategy=one_for_one restarted=[worker_b] unaffected=[worker_a,worker_c]
strategy=rest_for_one restarted=[worker_b,worker_c] unaffected=[worker_a]
strategy=one_for_all restarted=[worker_a,worker_b,worker_c]
restart_intensity max=3 window_s=5 observed=4 supervisor_exit=shutdown
result=PASS expected_restart_sets=true

The Core Question You Are Answering

“How do I make this service recover automatically without global failure?”

Concepts You Must Understand First

  • Review the concepts above and ensure you can explain them clearly.

Questions to Guide Your Design

  1. How will you partition work across processes?
  2. Where is state stored and how is it protected?
  3. What happens when a worker crashes?

Thinking Exercise

Sketch the message flow and failure paths before coding.

The Interview Questions They Will Ask

  1. “Why does this design scale better than shared-memory locks?”
  2. “How do you detect and recover from failures?”
  3. “How do you prevent mailbox buildup?”
  4. “Which measurement would tell you that Supervision Strategy Fault Lab is approaching its operating limit?”

Hints in Layers

Hint 1: Start with one worker process and a single message type.

Hint 2: Add supervision and confirm restart behavior.

Hint 3: Add routing and concurrency only after correctness.

Hint 4: Validate output with scripted test vectors.

Books That Will Help

Topic Book Chapter
Core BEAM “Programming Erlang” Processes chapter
OTP “Designing for Scalability with Erlang/OTP” Supervision chapter

Implementation Milestones

Integrated basic-to-advanced progression

  1. Begin with PHX-P2 supervision of the TCP service and prove basic child isolation.
  2. Add BEAM-P6 fault injection, restart-intensity evidence, and strategy comparisons to the same harness.

Milestone 1 — Contract and fixture: define one representative input, output, invariant, and failure case.

Milestone 2 — Core artifact: Wrap TCP and synthetic workers in supervision trees and inject faults.

Milestone 3 — Failure behavior: add timeouts, invalid inputs, crashes, retries, or partitions appropriate to the project.

Milestone 4 — Evidence: automate the definition of done and record a reproducible result.

Phase 1: Foundation (2-4 hours)

  • Build a single worker process
  • Define message shapes

Phase 2: Core Functionality (4-8 hours)

  • Add routing and state storage
  • Validate correctness on test cases

Phase 3: Polish & Edge Cases (2-4 hours)

  • Add failure injection tests
  • Document recovery behavior

Testing Strategy

6.1 Test Categories

Category Purpose Examples
Unit Tests Validate core logic message parsing
Integration Tests End-to-end flow demo scenario
Failure Tests Crash recovery kill worker

6.2 Critical Test Cases

  1. Normal path: request -> response
  2. Crash path: worker exit -> restart
  3. Overload: burst input -> bounded queue

6.3 Test Data

inputs: demo messages
expected: stable outputs

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Pitfall Symptom Solution
Missing supervisor app dies on crash add supervisor
Oversized mailbox latency spikes split processes
Unbounded state memory growth add eviction

7.2 Debugging Strategies

  • Use observer to inspect process counts and queues
  • Add structured logs on message receive

7.3 Performance Traps

  • Avoid heavy work in a single process

Definition of Done

  • Supports multiple strategies
  • Logs restart behavior
  • Demonstrates escalation when intensity exceeded
  • Clear report of recovery time

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • Every merged source contribution is implemented as a phase of this one artifact, not as a separate project.
  • traces prove restart strategy, intensity, and child-order effects.

Project 58: Supervision Tree Visualizer

Source: ERL-P8. Walk applications and supervisors to render child specs and live state.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Erlang
  • Alternative Programming Languages: Elixir (for comparison), Go
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: Level 2: Micro-SaaS / Pro Tool
  • Curriculum Difficulty: Level 2: Intermediate
  • Knowledge Area: OTP / Introspection
  • Software or Tool: OTP Supervisor
  • Main Book: “Designing for Scalability with Erlang/OTP” by Cesarini & Vinoski

What you will build: Walk applications and supervisors to render child specs and live state.

Why it teaches the BEAM ecosystem: It makes you prove that the view updates after crashes and distinguishes configuration from runtime.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Walk applications and supervisors to render child specs and live state.

A tool that introspects a running Erlang application’s supervision tree and outputs an ASCII or Graphviz visualization showing supervisors, workers, their strategies, and current status.

Build Supervision Tree Visualizer as one runnable, observable artifact. Walk applications and supervisors to render child specs and live state.

Produce an evidence bundle containing:

  • one deterministic happy-path run;
  • one rejected or malformed input with an explicit reason;
  • one injected failure or boundary condition;
  • a final verification result proving: the view updates after crashes and distinguishes configuration from runtime.
artifact=supervision_tree_visualizer
happy_path=PASS
invalid_input=REJECTED explicit_reason=true
failure_boundary=EXERCISED recovery_evidence=true
mastery_check=PASS

The Core Question You Are Answering

“How can Supervision Tree Visualizer deliver its observable outcome while proving that the view updates after crashes and distinguishes configuration from runtime.”

Concepts You Must Understand First

  • Introspection (getting supervisor children) → maps to supervisor module API
  • Recursive tree walking → maps to nested supervisor handling
  • Process information (memory, message queue, state) → maps to sys module
  • Output formatting (ASCII tree or DOT format) → maps to string building
  • Registered names vs PIDs → maps to process registration

Questions to Guide Your Design

  1. Which input and output contracts must remain stable across refactoring?
  2. Where should validation happen, and how will expected failures be represented?
  3. Which component owns mutable state or external effects, and what happens when it dies?
  4. What independent evidence proves this mastery condition: the view updates after crashes and distinguishes configuration from runtime.

Thinking Exercise

Draw Supervision Tree Visualizer as an input → decision/state → effect → evidence pipeline.

Mark every failure boundary, retry boundary, and durable state transition. Then inject one failure at each boundary and predict the observable result before implementing it.

The Interview Questions They Will Ask

  1. “What is the hardest invariant in Supervision Tree Visualizer, and where is it enforced?”
  2. “Which parts should be pure transformations and which require BEAM processes?”
  3. “How does the design behave under malformed input, process failure, or retry?”
  4. “What test or runtime evidence proves: the view updates after crashes and distinguishes configuration from runtime.”

Hints in Layers

Getting supervisor children: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Getting process info: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

For nested supervisors, recurse: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Hint 1: Starting Point Implement the narrowest happy path for: Walk applications and supervisors to render child specs and live state.

Hint 2: Next Level Separate parsing, validation, and transition decisions from effects so each can be tested directly.

Hint 3: Technical Details Represent expected failures as tagged outcomes and keep state ownership explicit; write only structural pseudocode before implementation.

Hint 4: Tools and Debugging Inject one failure at a time, correlate it with bounded telemetry, and save a deterministic transcript as evidence.

Books That Will Help

  • Main Book: “Designing for Scalability with Erlang/OTP” by Cesarini & Vinoski

Implementation Milestones

  1. Single-level supervisor visualized → Basic introspection works
  2. Nested trees render correctly → Recursive walking works
  3. Include process health metrics → Deep introspection mastered

Testing Strategy

  • Unit checks: pure parsing, validation, transition, and formatting decisions.
  • Integration checks: the real process, database, socket, notebook, or framework boundary.
  • Failure checks: malformed input plus at least one crash, timeout, duplicate, overload, or partition scenario.
  • Acceptance check: independently demonstrate that the view updates after crashes and distinguishes configuration from runtime.
  • Avoid arbitrary sleeps; use messages, monitors, deterministic clocks, fixtures, and deadlines where applicable.

Common Pitfalls and Debugging

Problem 1: Happy-path output looks correct but failures disappear

  • Why: validation, effects, and reporting share one opaque step.
  • Fix: preserve tagged errors and source identity through every stage.
  • Quick test: inject one invalid record or failed dependency and verify an explicit result.

Problem 2: Tests merely repeat the implementation

  • Why: assertions reuse the same transformation or state assumptions.
  • Fix: check external invariants, golden fixtures, and observable failure behavior.
  • Quick test: introduce a deliberate ordering or boundary bug and confirm the test fails.

Definition of Done

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • the view updates after crashes and distinguishes configuration from runtime.

Project 59: Process Boundary Cost Clinic

Official topic: Process-related anti-patterns — Elixir v1.20.2

Source file: lib/elixir/pages/anti-patterns/process-anti-patterns.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 2: Intermediate
  • Knowledge Area: OTP Architecture / Performance
  • Software or Tool: Telemetry, :erlang memory evidence, Supervisor
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build, profile, and refactor a flawed service that serializes pure calculation in a process, scatters raw calls, copies oversized messages, captures large closures, and starts orphan workers.

Why it teaches this official topic: The artifact makes runtime reasons for processes, encapsulated process interfaces, message-copy cost, supervised lifecycle observable through one bounded build instead of isolated syntax examples.

Scope boundary: Prove architectural boundary improvements with throughput, copied-byte, interface, and lifecycle evidence; do not become a generic pressure lab.

Core challenges you will face:

  • runtime reasons for processes -> identify the accepted case, the counterexample, and the observable result at the Telemetry, :erlang memory evidence, Supervisor boundary
  • encapsulated process interfaces -> identify the accepted case, the counterexample, and the observable result at the Telemetry, :erlang memory evidence, Supervisor boundary
  • message-copy cost -> identify the accepted case, the counterexample, and the observable result at the Telemetry, :erlang memory evidence, Supervisor boundary
  • supervised lifecycle -> identify the accepted case, the counterexample, and the observable result at the Telemetry, :erlang memory evidence, Supervisor boundary

Real World Outcome

Build, profile, and refactor a flawed service that serializes pure calculation in a process, scatters raw calls, copies oversized messages, captures large closures, and starts orphan workers. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Pure work moves out of unnecessary serialization.
  • Process interaction passes identifiers or minimal data.
  • Every long-lived process has a supervised owner.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=anti-patterns/process-anti-patterns.md
ARTIFACT=process-boundary-cost-clinic
CHECK 01 PASS :: Pure work moves out of unnecessary serialization
CHECK 02 PASS :: Process interaction passes identifiers or minimal data
CHECK 03 PASS :: Every long-lived process has a supervised owner
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“Which runtime property justifies each process boundary, and what cost appears when that reason is absent?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. runtime reasons for processes
    • Working rule: Make “runtime reasons for processes” an explicit rule at the Telemetry, :erlang memory evidence, Supervisor boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "runtime-reasons-for-processes-positive", focus: "runtime reasons for processes", mode: :positive, expect: :observable} and %{id: "runtime-reasons-for-processes-negative", focus: "runtime reasons for processes", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Process-related anti-patterns
  2. encapsulated process interfaces
    • Working rule: Make “encapsulated process interfaces” an explicit rule at the Telemetry, :erlang memory evidence, Supervisor boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "encapsulated-process-interfaces-positive", focus: "encapsulated process interfaces", mode: :positive, expect: :observable} and %{id: "encapsulated-process-interfaces-negative", focus: "encapsulated process interfaces", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Process-related anti-patterns
  3. message-copy cost
    • Working rule: Make “message-copy cost” an explicit rule at the Telemetry, :erlang memory evidence, Supervisor boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "message-copy-cost-positive", focus: "message-copy cost", mode: :positive, expect: :observable} and %{id: "message-copy-cost-negative", focus: "message-copy cost", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Process-related anti-patterns
  4. supervised lifecycle
    • Working rule: Make “supervised lifecycle” an explicit rule at the Telemetry, :erlang memory evidence, Supervisor boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "supervised-lifecycle-positive", focus: "supervised lifecycle", mode: :positive, expect: :observable} and %{id: "supervised-lifecycle-negative", focus: "supervised lifecycle", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Process-related anti-patterns

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “runtime reasons for processes” be enforced?
    • Which check catches the risk “A process is used only for code organization”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Pure work moves out of unnecessary serialization”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Process-related anti-patterns”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: runtime reasons for processes, encapsulated process interfaces, message-copy cost, supervised lifecycle. Then trace the named counterexample “A process is used only for code organization” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose runtime reasons for processes, and what does this project prove about it?”
  2. “What interaction between the concept ‘encapsulated process interfaces’ and the concept ‘runtime reasons for processes’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘A process is used only for code organization’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with runtime-reasons-for-processes-positive and a-process-is-used-only-for-code-organization-counterexample. The first must make the concept “runtime reasons for processes” observable and establish “Pure work moves out of unnecessary serialization”; the second must reproduce “A process is used only for code organization”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for anti-patterns/process-anti-patterns.md
evaluate "runtime reasons for processes" through Telemetry, :erlang memory evidence, Supervisor
compare actual evidence with "Pure work moves out of unnecessary serialization"
run negative fixture for "A process is used only for code organization"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Process-related anti-patterns Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
runtime reasons for processes Elixir in Action, 3rd Edition Ch. 5-8: process architecture
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement runtime-reasons-for-processes-positive and prove “Pure work moves out of unnecessary serialization”.
  3. Topic coverage: add fixtures for encapsulated process interfaces, message-copy cost, supervised lifecycle.
  4. Failure campaign: reproduce each named risk: “A process is used only for code organization”; “Callers depend on raw message formats”; “A closure copies a large captured term”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute runtime-reasons-for-processes-positive, encapsulated-process-interfaces-positive, message-copy-cost-positive, supervised-lifecycle-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute runtime-reasons-for-processes-negative, encapsulated-process-interfaces-negative, message-copy-cost-negative, supervised-lifecycle-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute a-process-is-used-only-for-code-organization-counterexample, callers-depend-on-raw-message-formats-counterexample, a-closure-copies-a-large-captured-term-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real Telemetry, :erlang memory evidence, Supervisor boundary from a clean shell.
  • Mutation check: violate “Pure work moves out of unnecessary serialization” and prove the suite reports fixture runtime-reasons-for-processes-positive as failed.
  • Regression corpus: retain the risks “A process is used only for code organization”; “Callers depend on raw message formats”; “A closure copies a large captured term” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “A process is used only for code organization”

  • Why: This breaks one or more observable capabilities at the Telemetry, :erlang memory evidence, Supervisor boundary while allowing the happy path to look correct.
  • Fix: Run a-process-is-used-only-for-code-organization-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “Callers depend on raw message formats”

  • Why: This breaks one or more observable capabilities at the Telemetry, :erlang memory evidence, Supervisor boundary while allowing the happy path to look correct.
  • Fix: Run callers-depend-on-raw-message-formats-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “A closure copies a large captured term”

  • Why: This breaks one or more observable capabilities at the Telemetry, :erlang memory evidence, Supervisor boundary while allowing the happy path to look correct.
  • Fix: Run a-closure-copies-a-large-captured-term-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • Pure work moves out of unnecessary serialization.
  • Process interaction passes identifiers or minimal data.
  • Every long-lived process has a supervised owner.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 60: ETS Cache and Session Service

Source: BEAM-P8. Build a supervised ETS cache with TTLs, atomic updates, and ownership transfer.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Erlang or Elixir
  • Alternative Programming Languages: Gleam
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: Level 2: Micro-SaaS / Pro Tool
  • Curriculum Difficulty: Level 2: Intermediate
  • Knowledge Area: Data Storage
  • Software or Tool: ETS
  • Main Book: “Erlang and OTP in Action”

What you will build: Build a supervised ETS cache with TTLs, atomic updates, and ownership transfer.

Why it teaches the BEAM ecosystem: It makes you prove that cache loss never becomes loss of durable truth.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Build a supervised ETS cache with TTLs, atomic updates, and ownership transfer.

Build a supervised ETS cache and session service with TTLs, atomic counters, a stable table owner, and explicit ownership recovery. A deterministic clock drives expiry tests, and the fault demo kills the owner to prove the table is transferred or reconstructed under the documented policy.

$ mix cache.demo --clock deterministic
put key=session:42 ttl_ms=30000 result=ok
get key=session:42 result=hit value=user_7
counter key=user_7:requests operation=atomic_increment value=2
FAULT owner=cache_owner reason=injected_kill
RECOVERY table=cache successor=cache_heir entries=2 available=true
advance_clock_ms=30001 get key=session:42 result=expired
result=PASS

The Core Question You Are Answering

“How do I make this service recover automatically without global failure?”

Concepts You Must Understand First

  • Review the concepts above and ensure you can explain them clearly.

Questions to Guide Your Design

  1. How will you partition work across processes?
  2. Where is state stored and how is it protected?
  3. What happens when a worker crashes?

Thinking Exercise

Sketch the message flow and failure paths before coding.

The Interview Questions They Will Ask

  1. “Why does this design scale better than shared-memory locks?”
  2. “How do you detect and recover from failures?”
  3. “How do you prevent mailbox buildup?”
  4. “Which measurement would tell you that ETS Cache and Session Service is approaching its operating limit?”

Hints in Layers

Hint 1: Start with one worker process and a single message type.

Hint 2: Add supervision and confirm restart behavior.

Hint 3: Add routing and concurrency only after correctness.

Hint 4: Validate output with scripted test vectors.

Books That Will Help

Topic Book Chapter
Core BEAM “Programming Erlang” Processes chapter
OTP “Designing for Scalability with Erlang/OTP” Supervision chapter

Implementation Milestones

Phase 1: Foundation (2-4 hours)

  • Build a single worker process
  • Define message shapes

Phase 2: Core Functionality (4-8 hours)

  • Add routing and state storage
  • Validate correctness on test cases

Phase 3: Polish & Edge Cases (2-4 hours)

  • Add failure injection tests
  • Document recovery behavior

Testing Strategy

6.1 Test Categories

Category Purpose Examples
Unit Tests Validate core logic message parsing
Integration Tests End-to-end flow demo scenario
Failure Tests Crash recovery kill worker

6.2 Critical Test Cases

  1. Normal path: request -> response
  2. Crash path: worker exit -> restart
  3. Overload: burst input -> bounded queue

6.3 Test Data

inputs: demo messages
expected: stable outputs

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Pitfall Symptom Solution
Missing supervisor app dies on crash add supervisor
Oversized mailbox latency spikes split processes
Unbounded state memory growth add eviction

7.2 Debugging Strategies

  • Use observer to inspect process counts and queues
  • Add structured logs on message receive

7.3 Performance Traps

  • Avoid heavy work in a single process

Definition of Done

  • TTL eviction works
  • Table survives normal load
  • Stats report accurate counts
  • Owner process supervised

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • cache loss never becomes loss of durable truth.

Project 61: Crash-Resilient ETS/DETS Session Store

Source: BEAM-P34. Back a hot ETS index with a DETS journal, rebuild, and compaction.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam with Erlang interop
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: Level 2: Micro-SaaS / Pro Tool
  • Curriculum Difficulty: Level 2: Intermediate
  • Knowledge Area: Stateful Services, Storage Lifecycle, Recovery
  • Software or Tool: ETS, DETS, Supervisor, Telemetry
  • Main Book: “Erlang and OTP in Action”

What you will build: Back a hot ETS index with a DETS journal, rebuild, and compaction.

Why it teaches the BEAM ecosystem: It makes you prove that VM restart recovers valid sessions without replaying partial records.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Back a hot ETS index with a DETS journal, rebuild, and compaction.

Build session-vault, a local HTTP/CLI-compatible service for creating, reading, touching, revoking, and expiring sessions. Reads come from ETS. Every mutation carries a request ID and expected version, is recorded as one DETS event, and updates ETS only after the configured persistence boundary. The service exposes readiness, storage diagnostics, replay reports, and a deterministic crash harness. It is deliberately single-node and bounded; the point is to learn exact local recovery semantics before adding replication.

$ session-vault create --request req-001 --subject customer-42 --ttl 30m
accepted_durable session=sess-f013 version=1 expires_at=2026-07-15T18:30:00Z

$ session-vault touch sess-f013 --request req-002 --expect-version 1 --ttl 60m
accepted_durable session=sess-f013 version=2 expires_at=2026-07-15T19:00:00Z

$ session-vault touch sess-f013 --request req-002 --expect-version 1 --ttl 60m
idempotent_replay session=sess-f013 version=2 original_request=req-002

$ session-vault get sess-f013
active subject=customer-42 version=2 source=ets

The learner starts the service, creates a session, crashes an ordinary worker, crashes the table keeper, and observes uninterrupted reads because the table heir temporarily owns the ETS tables. The learner then kills the whole VM without a graceful stop. On restart, the terminal shows DETS repair status, event-chain validation, replay progress, expiry reconciliation, index validation, and the moment readiness becomes true. The same session returns with the same version. Retrying a command whose response was intentionally dropped returns the original result rather than applying it twice.

$ session-vault crash-drill --scenario vm-after-sync --request req-003
phase=journal_synced request=req-003 action=SIGKILL
process_exit=137

$ session-vault start --journal ./data/session-events.dets
recovery journal_opened repaired=true repair_ms=184
recovery events=3 valid_chains=1 conflicts=0
recovery ets_sessions=1 ets_expiries=1 replay_ms=22
readiness=true generation=17 durability=strict

$ session-vault retry --request req-003
idempotent_replay session=sess-f013 version=3 status=revoked

The Core Question You Are Answering

“When fast state disappears at any crash boundary, what exact durable fact lets the system reconstruct the same answer without applying a caller’s retry twice?”

Do not begin with storage calls. First write a timeline for every mutation and mark when the event is authoritative, when ETS changes, and when the caller can safely receive success.

Concepts You Must Understand First

  1. ETS ownership and protection
    • Who can read and write a protected table?
    • What exactly happens on owner exit?
    • Book Reference: Erlang and OTP in Action — ETS sections.
  2. Supervision versus data durability
    • What can a supervisor restart, and what data can it not recreate by itself?
    • Book Reference: Designing for Scalability with Erlang/OTP — supervision and state sections.
  3. DETS lifecycle
    • When are open, sync, close, auto-save, and repair observable?
    • What does the 2 GB limit imply for retention?
  4. Idempotency and uncertain outcomes
    • How does a client distinguish retry from a second command after a timeout?
  5. Time semantics
    • Which clock persists meaning across VM restarts, and which clock is safe for elapsed intervals?

Questions to Guide Your Design

  1. Which process owns each resource, and which failures restart them together?
  2. Can any module mutate ETS without creating a durable event first?
  3. Is acknowledgement tied to DETS insert, sync, or periodic autosave?
  4. How does the client learn the durability class?
  5. What exact data identifies conflicting reuse of a request ID?
  6. What makes a replay chain invalid, and does startup fail closed?
  7. How are expired sessions represented so a restart cannot resurrect them?
  8. How far below 2 GB does the operator threshold stop writes?
  9. How is a snapshot associated with a journal high-water mark?
  10. How will tests kill the VM at a reproducible protocol phase?

Thinking Exercise

Draw the seven failure windows

Trace one revoke command through validation, duplicate lookup, DETS insert, DETS sync, ETS update, response construction, and response delivery. At each boundary, kill the VM on paper. For every restart, write whether the event exists, what ETS contains after replay, and what an identical retry returns. If any cell says “unknown” or “probably,” the protocol is not specified enough to implement.

The Interview Questions They Will Ask

  1. “What happens to an ETS table when its owner terminates, and what can an heir actually protect?”
  2. “Why is tab2file not equivalent to a durable journal?”
  3. “How does DETS differ from ETS in performance, table types, concurrency, and capacity?”
  4. “How would you prevent a timeout retry from revoking or extending a session twice?”
  5. “Why must readiness wait after the supervisor has restarted every child?”
  6. “Where is the linearization or authority point in your mutation protocol?”

Hints in Layers

Hint 1: Make ownership boring

Give table lifecycle, journal lifecycle, and business mutation to different components. A process with fewer responsibilities is easier to restart safely.

Hint 2: Start with strict writes

Implement insert, sync, ETS apply, and acknowledgement in that order. Add a weaker batch mode only after its loss window can be demonstrated.

Hint 3: Store results with request identity

One event should be sufficient to decide whether a retry is identical and what original result it receives. Avoid a second idempotency table in the core.

Hint 4: Make crashes external

A test that calls a graceful stop does not prove abrupt recovery. Launch a child OS process, wait for a named phase marker, send an untrappable termination, then restart on the same copied data directory.

Books That Will Help

Topic Book Chapter/Section
ETS and shared runtime data Erlang and OTP in Action — Logan, Merritt, Carlsson ETS and data-storage sections
OTP ownership and failure boundaries Designing for Scalability with Erlang/OTP — Cesarini, Vinoski Supervision and state-management sections
Elixir process architecture Elixir in Action — Saša Jurić Server processes and fault tolerance chapters
Idempotent distributed operations Designing Data-Intensive Applications — Martin Kleppmann Replication/fault and stream-processing discussions

Implementation Milestones

Phase 1: Hot projection and ownership (6-8 hours)

  • Build the session and expiry table shapes.
  • Implement protected direct reads and serialized mutations without persistence.
  • Add keeper/heir transfer and prove the table identifier remains valid or is republished safely.
  • Checkpoint: a table-keeper crash does not lose an active session, while a whole-VM restart deliberately does.

Phase 2: Durable protocol and replay (10-14 hours)

  • Define the versioned event and command fingerprint.
  • Implement strict DETS append/sync before ETS mutation.
  • Restore both projections and handle already-expired sessions.
  • Checkpoint: kill -9 after sync returns the original result on retry after restart.

Phase 3: Failure honesty and operations (8-14 hours)

  • Add readiness phases, repair diagnostics, capacity threshold, metrics, and redaction.
  • Build the crash matrix and corrupted-copy tests.
  • Benchmark reads, strict writes, replay, and repair fixtures.
  • Checkpoint: a written recovery report accounts for every fault and states any remaining loss window.

Testing Strategy

6.1 Test Categories

Category Purpose Examples
Pure model tests Validate transitions and replay independently of storage create/touch/revoke/expire version chains
ETS lifecycle tests Validate ownership and projection integrity keeper death, heir transfer, index rebuild
DETS integration tests Validate disk lifecycle sync, close, reopen, repair fixture, capacity refusal
Idempotency tests Validate uncertain response handling exact retry and conflicting key reuse
Crash-process tests Validate whole-VM recovery kill before insert, after sync, after ETS apply
Time tests Validate TTL across restart already expired, future expiry, injected skew
Performance tests Establish honest service limits lookup latency, synced-write latency, replay duration

6.2 Critical Test Cases

  1. Worker crash: Killing an API worker changes neither ETS ownership nor stored sessions.
  2. Keeper crash: The heir receives both tables and the replacement keeper reclaims them without cold replay.
  3. Whole-VM crash before sync: Result matches the documented durability mode; strict mode never reports a success that lacks the event.
  4. Whole-VM crash after sync: Replay applies the event even if ETS never saw it before death.
  5. Lost response retry: Same request and fingerprint returns the same session/version; it creates no second event.
  6. Conflicting retry: Same request ID with different TTL or session is rejected and reported.
  7. Expired during downtime: Restart does not expose the session as active.
  8. Forked journal fixture: Two events claim the same next version; readiness remains false with a precise conflict.
  9. Repair fixture: An unclean copied DETS file is repaired or rejected, and replay validation still executes.
  10. Capacity threshold: Writes stop before the configured safe ceiling and reads/recovery diagnostics remain available.
  11. Snapshot mismatch: A stale or unverifiable ETS snapshot is ignored and full replay succeeds.
  12. Index drift: Missing expiry entry is detected and rebuilt from current session state.

6.3 Test Data

session A: create(v1) -> touch(v2) -> revoke(v3)
session B: create(v1, expiry during shutdown)
session C: create(v1) -> two competing touch(v2) events [invalid fixture]
request req-dup: same command twice [idempotent]
request req-conflict: same ID, different TTL [reject]
journal files: graceful-close, unclean-close copy, truncated copy, near-threshold fixture

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Pitfall Symptom Solution
API worker owns ETS Ordinary request crash empties cache Use a dedicated lifecycle owner
ETS updated before DETS Successful session disappears after VM crash Persist/sync before projection update
Heir called persistence Host restart loses inherited table Explain local transfer boundary and replay DETS
Named table recreated blindly Startup badarg or stale table reference Handshake with heir and generation token
Two durable records per command Event exists without idempotency record Put request identity and result in one event
DETS traversal treated as ordered Replay differs between runs Store explicit per-session version and validate
Autosave described as strict durability Last acknowledged updates vanish in kill test Use sync or name the weaker loss window
Repair accepted as correctness proof Readable file contains broken version chains Run business-level replay validation
Full expiry scan Latency spikes and scheduler pressure Ordered derived index and bounded batches
Unbounded journal Approaches 2 GB and replay becomes operationally unsafe Thresholds, retention, verified compaction plan

7.2 Debugging Strategies

  • Inspect ownership first: Report ETS owner, heir, table identifiers, generation, protection, sizes, and transfer messages.
  • Trace one request ID: Follow it through validation, journal lookup/append/sync, ETS apply, and response without logging secret payloads.
  • Separate file repair from replay validation: Record both outcomes and durations.
  • Reproduce on copied data: Preserve the original DETS file before force-repair or truncation experiments.
  • Compare journal and projection counts carefully: They need not match one-to-one because many events reduce to one current session.
  • Use phase markers in crash tests: Kill on an externally observable marker rather than a timing sleep.

7.3 Performance Traps

Strict sync per mutation can dominate latency, DETS scans make full replay grow with history, and ordered_set maintenance adds write cost. ETS concurrency flags can consume more memory or harm alternating workloads. Benchmark p50/p95/p99 for reads and strict writes separately. Measure replay and repair with realistic journal sizes. Do not improve benchmark numbers by weakening the acknowledgement guarantee without changing the reported durability class.

Definition of Done

  • ETS sessions and ordered expiry projection have explicit owners, access modes, and invariants.
  • Keeper failure transfers tables through an heir and returns to a valid owner generation.
  • Whole-VM termination reconstructs the same session versions from DETS.
  • Strict success is emitted only after the event crosses the documented sync boundary.
  • Exact retries return the original result; conflicting request-ID reuse is rejected.
  • Expired and revoked sessions never resurrect after downtime.
  • Startup remains unready during open/repair/validation/replay/index checks.
  • DETS 2 GB limit, no ordered_set, repair cost, and local-only durability are documented and tested where practical.
  • tab2file is treated only as a validated optional snapshot accelerator.
  • Crash tests use a separate OS process and cover every named protocol phase.
  • No destructive test modifies the only copy of journal data.
  • The runbook states recovery, capacity, backup, and fail-closed procedures.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • VM restart recovers valid sessions without replaying partial records.

Project 62: Fault-Tolerant Livebook Telemetry Lab

Source: LIVE-P4. Start supervised telemetry producers and visualize controlled failures in Livebook.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang; Python for telemetry-analysis comparison
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: Level 2: Micro-SaaS / Pro Tool
  • Curriculum Difficulty: Level 2: Intermediate
  • Knowledge Area: BEAM processes, supervision, backpressure, interactive observability
  • Software or Tool: Livebook, Kino.Control, Kino.Frame, Supervisor
  • Main Book: Elixir in Action, Third Edition

What you will build: Start supervised telemetry producers and visualize controlled failures in Livebook.

Why it teaches the BEAM ecosystem: It makes you prove that re-evaluation leaks no processes or duplicate subscriptions.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Start supervised telemetry producers and visualize controlled failures in Livebook.

Create telemetry-supervision-lab.livemd, a supervised simulation with four logical sensors. Each producer emits synthetic temperature readings. A registry/coordinator tracks the current incarnation of every sensor. One aggregator owns latest values, bounded history, and load counters. A dashboard observer renders snapshots to Kino frames and records lifecycle events.

The notebook provides:

  • A supervisor-tree diagram and failure matrix before startup.
  • Start, orderly stop, injection-target, and fault-injection controls.
  • Four sensor cards showing logical ID, current PID/generation, reading, sequence, age, and status.
  • A bounded time-series view or tabular frame containing the last 120 accepted points.
  • Mailbox, lag, received, accepted, coalesced/dropped, and stale-generation counters.
  • A bounded event transcript showing startup, injected exit, DOWN, restart, new identity, and recovery.
  • A high-rate overload fixture and a restart-intensity fixture.
  • An idempotent lifecycle handle suitable for notebook re-evaluation.

Select sensor-2 and activate the fault control. The bounded event transcript shows one example:

14:32:10 sensor-2 PID<0.241.0> generation=1 temperature=21.8°C seq=43
14:32:12 action=inject_fault target=sensor-2 generation=1
14:32:12 DOWN PID<0.241.0> reason=simulated_failure
14:32:12 supervisor restart sensor-2 -> PID<0.255.0> generation=2
14:32:13 sensor-2 PID<0.255.0> generation=2 temperature=21.7°C seq=1

Stream continuity: PASS
Window: last 120 points
Dropped/coalesced events: 34 (reported)
Stale-generation events rejected: 1
Recovery time: 684 ms

The overload fixture produces an explicit degraded state rather than hiding lag:

LOAD STATUS: DEGRADED — COALESCING ACTIVE
received_per_second=400
rendered_snapshots_per_second=1
aggregator_mailbox=18 threshold=50
accepted_readings=2,410
coalesced_readings=1,936
dropped_readings=0
oldest_visible_age_ms=812
history_points=120/120

Open the notebook and study the supervisor tree and failure matrix before running the lab. Evaluate the startup section once. Four sensor cards become ready, each with a logical ID and current PID/generation. A time-series frame begins replacing its bounded dataset at the render cadence. A metrics strip reveals ingestion rate, render rate, mailbox size, lag, history occupancy, and loss/coalescing counters.

Choose sensor-2 and inject a fault. Its card changes to RECOVERING; the other three continue changing. The event transcript records the intentional action, old process exit, supervisor restart, new PID/generation, and first accepted new reading. The continuity and recovery checks move to PASS. A deliberately delayed generation-1 message is rejected after generation 2 registers, proving that logical identity alone is insufficient.

Increase the producer rate. The chart still displays at its human-scale cadence; counters show how many values were coalesced or dropped under the declared policy. History remains exactly bounded. Trigger the rapid-crash fixture and observe the supervisor exceed restart intensity, after which the lab renders an escalated terminal state and requires deliberate restart rather than looping invisibly.

Activate “Orderly stop.” Cards become stopped, timers cease, and a process audit confirms no lab-owned process remains. Evaluate startup twice and confirm it returns the existing system or replaces it cleanly—never two copies. Reconnect to a new runtime, replay from the top, and observe entirely new PIDs with the same logical architecture and tests.

The Core Question You Are Answering

“What does fault tolerance actually preserve, restart, discard, and reveal?”

Do not answer “the supervisor restarts the process.” Name the logical identity, PID, generation, in-memory state, downstream window, observer state, pending messages, counters, and durable evidence. For each, say whether it survives, is rebuilt, is deliberately lost, or must be rejected.

Concepts You Must Understand First

  1. Processes and mailboxes
    • Who owns aggregate state, and why should there be one writer?
    • What makes mailbox growth a form of unbounded queueing?
    • Book Reference: Elixir in Action, 3rd ed., Chapters 5–6.
  2. Links, monitors, and exit signals
    • Which relation observes failure and which couples it?
    • What changes when a process traps exits?
    • Primary References: Process and GenServer.
  3. Supervisors and restart strategy
    • What does one_for_one preserve compared with one_for_all?
    • What happens when restart intensity is exceeded?
    • Primary Reference: Supervisor.
  4. Identity and protocol design
    • Why are sensor ID, PID, generation, and sequence all different?
    • Which delayed messages must be rejected after restart?
  5. Kino event and frame lifecycle
    • What happens when production is faster than rendering?
    • How do you stop a listener created by a re-evaluated cell?
    • Primary References: Kino.Control and Kino.Frame.

Questions to Guide Your Design

  1. Which process owns current incarnation mappings?
  2. Which child processes belong under the same supervisor, and why?
  3. Should an aggregator crash restart producers, or remain independently recoverable?
  4. What exact reading message shape is accepted?
  5. How will the aggregator reject a valid-shaped but obsolete message?
  6. Which state is derived and safe to lose on aggregator restart?
  7. Which state, if any, would need durable persistence in a real system?
  8. What input rate, render rate, mailbox threshold, window bound, and drop/coalescing policy are declared?
  9. How does the UI learn about child exit without sharing the child’s failure fate?
  10. What happens after restart intensity is exceeded?
  11. How will startup discover and stop an older lab instance?
  12. What exact process evidence proves orderly stop completed?

Thinking Exercise

Draw the supervisor tree and complete this failure matrix before implementation:

process            crash result       restarted?   state preserved?   UI evidence
sensor-2           learner predicts   predict      predict            predict
aggregator         learner predicts   predict      predict            predict
dashboard observer learner predicts   predict      predict            predict
lab supervisor     learner predicts   predict      predict            predict

Then trace this sequence:

  1. sensor-2 generation 1 sends sequence 43.
  2. Fault injection terminates its PID.
  3. A delayed generation-1 sequence 44 is already in transit.
  4. The supervisor starts generation 2 with sequence 1.
  5. The delayed old message reaches the aggregator.
  6. Generation 2’s first reading arrives.

Predict accepted/stale counters, card state, history entries, PIDs, and recovery duration at every step.

The Interview Questions They Will Ask

  1. “How do links and monitors differ?”
  2. “Why does supervision not equal persistence?”
  3. “What causes mailbox growth, and how would you detect it?”
  4. “Why distinguish logical identity from PID?”
  5. “How do you prevent delayed messages from an old process incarnation?”
  6. “How do you avoid duplicated notebook listeners?”

Hints in Layers

Hint 1: One state owner. Make the aggregator the sole owner of latest readings, bounded history, and stream counters.

Hint 2: Start with one sensor. Prove protocol, normal stop, abnormal exit, and restart identity before scaling to four.

Hint 3: Version producers. Register each sensor incarnation and include both generation and PID in messages.

Hint 4: Separate measurement and rendering. Aggregate fast readings and render compact snapshots less often.

Hint 5: Make loss visible. A coalesced or dropped value must increment a named counter.

Hint 6: Preserve a complete handle. Startup should return everything required for idempotent orderly stop.

Hint 7: Test the terminal path. Repeated fault injection must eventually exercise restart-intensity escalation rather than only happy recovery.

Books That Will Help

Topic Book Chapter
Processes and servers Elixir in Action, 3rd ed. Chapters 5–6
Fault tolerance and supervision Elixir in Action, 3rd ed. Chapters 7–9
Supervision-oriented design Designing Elixir Systems with OTP Chapters 3–8
Load and stability Release It!, 2nd ed. Stability, queues, timeouts, and capacity chapters
Distributed/actor reasoning Programming Erlang, 2nd ed. Concurrency and OTP chapters

Implementation Milestones

Phase 1: Foundation (4–6 hours)

Goals: Define topology, protocols, state ownership, and one supervised sensor.

Tasks:

  1. Draw the supervisor tree and complete the failure matrix.
  2. Define reading, registration, snapshot, lifecycle, and recovery schemas.
  3. Build one producer and aggregator with a fixed bounded window.
  4. Inject one crash and observe old/new PID without Kino rendering.

Checkpoint: A transcript proves new process identity, explicit state loss, and one accepted post-restart reading.

Phase 2: Core Functionality (7–10 hours)

Goals: Add four sensors, generation gating, snapshots, dashboard, and controls.

Tasks:

  1. Scale to four supervised logical sensors with independent generations.
  2. Add delayed-old-generation rejection and counters.
  3. Add slower snapshot cadence and bounded Kino frames.
  4. Add client controls for target selection, fault injection, rate, start, and stop.
  5. Correlate exit/restart/first-reading evidence into recovery events.

Checkpoint: One injected producer fault shows continuity, old/new identities, stale-message rejection, and bounded frames.

Phase 3: Polish & Edge Cases (5–8 hours)

Goals: Prove overload, terminal escalation, lifecycle, soak stability, and replay.

Tasks:

  1. Add overload fixture, explicit coalescing/drop policy, and mailbox/lag display.
  2. Add restart-intensity fixture and terminal-state rendering.
  3. Make startup/stop idempotent and audit all owned processes/timers.
  4. Run a ten-minute high-rate soak and clean-runtime replay.
  5. Record evidence for duplicate startup, reconnect, and orderly stop.

Checkpoint: All critical tests and Definition of Done checks pass with a saved evidence transcript.

Testing Strategy

6.1 Test Categories

Category Purpose Examples
Protocol tests Validate accepted/rejected messages wrong version, unit, sensor ID, generation
Process tests Verify state ownership and replies sequence, latest value, bounded history
Supervision tests Prove restart behavior abnormal exit, normal stop, restart intensity
Concurrency tests Exercise message timing delayed old generation, interleaved sensors
Load tests Verify bounded behavior high producer rate, mailbox threshold, coalescing counters
UI integration tests Verify observable state recovering card, PID change, continuity, terminal state
Lifecycle tests Detect leaks/duplicates start twice, stop twice, reconnect, process audit

6.2 Critical Test Cases

  1. Normal stream: Four sensors emit accepted readings; sequence/generation and units are valid; window never exceeds 120.
  2. Single injected crash: Old PID exits with simulated_failure, new PID/generation appears, and first new reading meets recovery objective.
  3. Continuity: Other three sensors, aggregator, and dashboard retain PID continuity and keep advancing during one producer restart.
  4. Delayed old message: A generation-1 reading arriving after generation 2 registration is rejected and counted.
  5. High-rate overload: History and frame remain bounded; coalesced/dropped counters increase according to policy; lag remains visible.
  6. Restart intensity: Rapid repeated crashes exceed policy, terminate/escalate the subtree, and render a terminal state without an infinite loop.
  7. Duplicate startup: Two start actions produce one active supervisor tree, one observer, and one event per producer interval.
  8. Orderly stop: Two stop actions are safe; process/timer audit finds no lab-owned survivors.
  9. Clean replay: Reconnect yields new PIDs and empty ephemeral state while reconstructing the same logical topology and tests.

6.3 Test Data

NORMAL
sensors=[sensor-1,sensor-2,sensor-3,sensor-4]
producer_interval_ms=250 snapshot_interval_ms=1000 history_limit=120
expected active_sensors=4 invalid_messages=0

FAULT
target=sensor-2 old_generation=1 exit_reason=simulated_failure
expected new_generation=2 new_pid_different=true
expected other_sensor_sequence_continues=true

STALE
message sensor=sensor-2 generation=1 sequence=44 arrives_after_generation=2_registration
expected accepted=false stale_generation_count_delta=1

OVERLOAD
combined_input_per_second=400 snapshot_per_second=1 duration_seconds=60
expected history_size_max=120
expected coalesced_or_dropped_count_positive=true
expected unbounded_growth=false

LIFECYCLE
actions=[start,start,stop,stop]
expected active_lab_supervisors_after_start=1
expected lab_owned_processes_after_stop=0

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Pitfall Symptom Solution
Duplicate startup Every reading or event appears twice Stop prior handle or return the existing initialized lab
Unbounded history/frame Memory and browser cost grow during demo Ring-buffer data, replace frame, cap event transcript
PID treated as logical ID Restart appears as a new sensor or old messages pass Track stable sensor ID plus current generation/PID
UI linked to producer Dashboard dies with injected sensor Observe via monitors and intended supervisor boundaries
Supervision assumed persistence Sequence/window unexpectedly resets Declare ephemeral state and reconstruct only from explicit sources
Rendering every event Listener/browser falls behind Aggregate fast, snapshot slowly, report loss/coalescing
No terminal-state design Crash loop consumes resources Configure/test restart intensity and render escalation

7.2 Debugging Strategies

  • Display identities: Include logical ID, PID, generation, and sequence in the bounded transcript.
  • Inspect mailbox length and lag together: A small mailbox can still contain old work; age reveals freshness.
  • Trace one failure timeline: Record injection, exit detection, restart registration, and first accepted reading with monotonic times.
  • Audit process ownership: Tag/namescope lab processes so startup/stop counts can be checked without scanning unrelated runtime work.
  • Inject deterministic stale messages: Do not wait for a rare race; schedule an old-generation fixture explicitly.
  • Test without UI first: If supervision/protocol tests pass headlessly, investigate Kino routing/render cadence separately.

7.3 Performance Traps

Unbounded mailboxes and frame histories are the central traps. Avoid expensive formatting in the aggregator receive loop; snapshot immutable compact state and render elsewhere. Do not calculate chart history from all events on every tick. A very small render interval can serialize the listener behind browser work. Monitoring every ephemeral process without demonitoring can leak references/messages. During soak tests, observe process count, mailbox length, history size, snapshot duration, and browser responsiveness together.

Definition of Done

Minimum Viable Completion:

  • Four logical sensors run under a documented supervisor and feed one bounded aggregator.
  • Fault injection restarts one producer with a new PID while other producers continue.
  • The dashboard displays current identity, bounded history, and one recovery transcript.
  • Startup and stop are safe to execute repeatedly.

Full Completion:

  • All minimum criteria plus:
  • Reading protocol includes version, logical ID, PID/generation, sequence, time, value, and unit.
  • Delayed old-generation rejection, overload counters, render cadence, and 120-point bound are proven.
  • Restart-intensity terminal behavior, ten-minute soak, cleanup audit, and clean-runtime replay pass.
  • Evidence names what supervision restarted, discarded, preserved, and exposed.

Excellence (Going Above & Beyond):

  • Headless ExUnit/property tests cover process protocols, ring-buffer bounds, and generation safety.
  • An OTP application package separates production-grade process logic from the Livebook observer.
  • A demand-driven ingestion extension compares throughput, latency, and loss with the raw-message design.
  • A disposable distributed-node extension demonstrates node loss, reconnect, and incarnation handling without production access.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • re-evaluation leaks no processes or duplicate subscriptions.

Source: BEAM-P17. Build a bounded Task crawler with deadlines, retries, and partial failure.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: Level 2: Micro-SaaS / Pro Tool
  • Curriculum Difficulty: Level 2: Intermediate
  • Knowledge Area: Bounded Concurrency, HTTP, TLS
  • Software or Tool: Task.Supervisor, Finch, :ssl, :public_key
  • Main Book: “Elixir in Action”

What you will build: Build a bounded Task crawler with deadlines, retries, and partial failure.

Why it teaches the BEAM ecosystem: It makes you prove that throughput rises without unbounded tasks or nondeterministic reporting.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Build a bounded Task crawler with deadlines, retries, and partial failure.

Build “url-audit”, a CLI that reads URLs, checks them with bounded concurrency, records redirect chains and latency, and reports TLS validation, subject/issuer, SANs, fingerprint, expiry, and days remaining for HTTPS origins.

Scope boundary: This is a one-shot finite audit. Do not build a scheduler, monitoring daemon, LiveView dashboard, GenStage pipeline, distributed crawler, or general-purpose web spider.

$ mix url_audit fixtures/urls.txt --max-concurrency 8 --timeout 5000 --warn-days 30
inputs=12 completed=12 elapsed_ms=1842 max_in_flight=8
ok=7 warnings=2 failures=3
WARN https://docs.example expiry_days=12 status=200 latency_ms=91
FAIL https://old.example category=tls_invalid reason=hostname_mismatch
FAIL https://loop.example category=redirect_loop hops=5
reports=tmp/url-audit.{json,csv}

3.7.1 How to Run

Run against deterministic local HTTP/TLS fixtures first, including slow, redirecting, and invalid-certificate endpoints. Use public endpoints only with conservative concurrency and permission.

3.7.2 Golden Path Demo

The fixture inventory produces OK, expiring-soon, 404, redirect-loop, hostname mismatch, connection refusal, and timeout outcomes. Exactly one result exists per line despite out-of-order completion.

3.7.3 Exact Terminal Transcript

$ mix url_audit test/fixtures/urls.txt --max-concurrency 3 --timeout 1000
inputs=7 completed=7 max_in_flight=3
ok=2 warnings=1 failures=4
by_category=http_404:1,tls_expiring:1,tls_invalid:1,timeout:1,redirect_loop:1
$ echo $?
2

The Core Question You Are Answering

How do I make finite concurrent network work faster without losing capacity control, failure detail, or deterministic results?

Concepts You Must Understand First

Understand Task results/exits, async_stream options, supervision ownership, monotonic timing, URL origins, TLS validation versus decoding, and deterministic aggregation.

Questions to Guide Your Design

  1. What owns and terminates workers?
  2. Which timeout fired, and how is it represented?
  3. Is certificate evidence gathered per URL or per origin?
  4. How do global and per-host limits interact?
  5. Which outcomes make CI fail versus warn?

Thinking Exercise

Schedule ten URLs with a concurrency of three, where the first task hangs and later tasks finish quickly. Draw active tasks and emitted results over time. Then add six URLs on one host and propose a fairness policy.

The Interview Questions They Will Ask

  1. What does Task.async_stream return when a task exits?
  2. How does ordered output differ from completion order?
  3. Why do bounded tasks differ from GenStage backpressure?
  4. How would you distinguish connect, receive, and task timeouts?
  5. What is the difference between decoding and validating a certificate?
  6. How do you prevent a link checker from overloading a target?

Hints in Layers

Hint 1: Make a sequential worker return one complete AuditResult first.

Hint 2: Wrap the existing worker with async_stream rather than putting aggregation inside tasks.

Hint 3: Convert every “ok” and “exit” stream item to the same result schema.

Hint 4: Instrument in-flight count and per-category latency before tuning concurrency.

Books That Will Help

Topic Book Chapter
Task concurrency “Elixir in Action” by Saša Jurić Ch. 9, Isolating Error Effects; Ch. 10, Beyond GenServer
Resilient network calls “Release It!, 2nd Edition” by Michael Nygard Ch. 4, Stability Antipatterns; Ch. 5, Stability Patterns
Service boundaries “Building Microservices, 2nd Edition” by Sam Newman Ch. 9, Communication Styles; Ch. 12, Resiliency

Implementation Milestones

Phase 1: Foundation (3-5 hours)

Build sequential checks, URL normalization, layered outcomes, local fixtures, and deterministic rendering.

Phase 2: Core Functionality (4-6 hours)

Add supervised Task.async_stream, limits/timeouts, redirect policy, TLS decoding, and origin evidence.

Phase 3: Polish & Edge Cases (3-5 hours)

Add host fairness, redaction, atomic reports, CI exit policy, load measurements, and help documentation.

Testing Strategy

6.1 Test Categories

  • URL/inventory unit tests
  • Deterministic local HTTP/TLS integration tests
  • Task exit/timeout normalization tests
  • Concurrency-bound tests using instrumented fixtures
  • Redirect state-machine tests
  • Certificate date/identity decoding tests
  • End-to-end report and exit-code tests

6.2 Critical Test Cases

  1. Active worker count never exceeds the limit.
  2. A hung request times out without blocking later work indefinitely.
  3. Task exit still yields one correlated result.
  4. Redirect loop stops at policy and records hops.
  5. Invalid certificate is not accepted as healthy.
  6. Out-of-order completion produces input-ordered reports.
  7. Query secrets are redacted.

6.3 Test Data

Use local endpoints for 200, 404, redirects, loops, delayed response, dropped connection, expiring certificate, hostname mismatch, and untrusted issuer. Freeze observation time in certificate-policy tests.

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Caller exits: Tasks are linked without an ownership plan. Use the supervised boundary and normalize exits.

Everything says timeout: Inner and outer deadlines share one reason. Tag each boundary.

TLS looks healthy: Verification was disabled or only dates were decoded. Preserve transport validation.

Output changes order: Results were rendered as tasks completed. Sort by stable input id.

7.2 Debugging Strategies

Log safe lifecycle events keyed by input id: queued, started, DNS/connect/TLS/HTTP boundary, finished. Track in-flight and per-host counts. Reproduce certificate problems with local fixtures and structured decoded fields.

7.3 Performance Traps

Unlimited concurrency, one HTTP pool bottleneck, repeated TLS probes per URL, downloading full bodies, serial DNS work, and storing verbose bodies dominate performance. Measure boundary timings before tuning.

Definition of Done

  • Every valid input has exactly one terminal result.
  • Concurrency and timeout limits are measured and enforced.
  • DNS, transport, TLS, HTTP, redirect, and worker failures are distinct.
  • Certificate validation mode and observation time are explicit.
  • Reports are deterministic despite out-of-order execution.
  • Local fixtures cover slow and invalid endpoints.
  • P17 is explicitly distinguished from P05’s long-lived GenStage pipeline.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • throughput rises without unbounded tasks or nondeterministic reporting.

Project 64: Legacy Billing Refactoring Certification Lab

Official topic: Code-related anti-patterns — Elixir v1.20.2

Source file: lib/elixir/pages/anti-patterns/code-anti-patterns.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 2: Intermediate
  • Knowledge Area: Refactoring / Language Safety
  • Software or Tool: ExUnit, StreamData optional, :erts_debug
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Refactor an intentionally flawed billing subsystem while preserving golden and property-test behavior, eliminating dynamic atom risk, comments that narrate obvious code, complex clause extractions, namespace trespassing, non-assertive truthiness, broad with failures, and oversized-struct memory.

Why it teaches this official topic: The artifact makes assertive pattern matching, bounded atoms, cohesive parameters and structs, simple with failure paths, comments versus expressive code, simple extraction in clauses, namespace ownership, strict booleans versus truthiness observable through one bounded build instead of isolated syntax examples.

Scope boundary: This is behavioral refactoring with runtime evidence, not a static-analysis project.

Core challenges you will face:

  • assertive pattern matching -> identify the accepted case, the counterexample, and the observable result at the ExUnit, StreamData optional, :erts_debug boundary
  • bounded atoms -> identify the accepted case, the counterexample, and the observable result at the ExUnit, StreamData optional, :erts_debug boundary
  • cohesive parameters and structs -> identify the accepted case, the counterexample, and the observable result at the ExUnit, StreamData optional, :erts_debug boundary
  • simple with failure paths -> identify the accepted case, the counterexample, and the observable result at the ExUnit, StreamData optional, :erts_debug boundary
  • comments versus expressive code -> identify the accepted case, the counterexample, and the observable result at the ExUnit, StreamData optional, :erts_debug boundary
  • simple extraction in clauses -> identify the accepted case, the counterexample, and the observable result at the ExUnit, StreamData optional, :erts_debug boundary
  • namespace ownership -> identify the accepted case, the counterexample, and the observable result at the ExUnit, StreamData optional, :erts_debug boundary
  • strict booleans versus truthiness -> identify the accepted case, the counterexample, and the observable result at the ExUnit, StreamData optional, :erts_debug boundary

Real World Outcome

Refactor an intentionally flawed billing subsystem while preserving golden and property-test behavior, eliminating dynamic atom risk, comments that narrate obvious code, complex clause extractions, namespace trespassing, non-assertive truthiness, broad with failures, and oversized-struct memory. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Missing required data fails at the pattern or access boundary.
  • Untrusted labels cannot create atoms.
  • Before-and-after structure and memory evidence are recorded.
  • Every with failure keeps its original named error.
  • Obvious comments are replaced by names that reveal intent.
  • Complex extraction moves behind a pattern-matched helper.
  • Extension modules remain under an owned namespace.
  • Boolean APIs reject non-boolean truthy values.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=anti-patterns/code-anti-patterns.md
ARTIFACT=legacy-billing-refactoring-certification-lab
CHECK 01 PASS :: Missing required data fails at the pattern or access boundary
CHECK 02 PASS :: Untrusted labels cannot create atoms
CHECK 03 PASS :: Before-and-after structure and memory evidence are recorded
CHECK 04 PASS :: Every with failure keeps its original named error
CHECK 05 PASS :: Obvious comments are replaced by names that reveal intent
CHECK 06 PASS :: Complex extraction moves behind a pattern-matched helper
CHECK 07 PASS :: Extension modules remain under an owned namespace
CHECK 08 PASS :: Boolean APIs reject non-boolean truthy values
FAILURE_CASES=8 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“How can code become more idiomatic and safer while proving that intended external behavior did not change?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. assertive pattern matching
    • Working rule: Make “assertive pattern matching” an explicit rule at the ExUnit, StreamData optional, :erts_debug boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "assertive-pattern-matching-positive", focus: "assertive pattern matching", mode: :positive, expect: :observable} and %{id: "assertive-pattern-matching-negative", focus: "assertive pattern matching", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Code-related anti-patterns
  2. bounded atoms
    • Working rule: Make “bounded atoms” an explicit rule at the ExUnit, StreamData optional, :erts_debug boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "bounded-atoms-positive", focus: "bounded atoms", mode: :positive, expect: :observable} and %{id: "bounded-atoms-negative", focus: "bounded atoms", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Code-related anti-patterns
  3. cohesive parameters and structs
    • Working rule: Make “cohesive parameters and structs” an explicit rule at the ExUnit, StreamData optional, :erts_debug boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "cohesive-parameters-and-structs-positive", focus: "cohesive parameters and structs", mode: :positive, expect: :observable} and %{id: "cohesive-parameters-and-structs-negative", focus: "cohesive parameters and structs", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Code-related anti-patterns
  4. simple with failure paths
    • Working rule: Make “simple with failure paths” an explicit rule at the ExUnit, StreamData optional, :erts_debug boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "simple-with-failure-paths-positive", focus: "simple with failure paths", mode: :positive, expect: :observable} and %{id: "simple-with-failure-paths-negative", focus: "simple with failure paths", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Code-related anti-patterns
  5. comments versus expressive code
    • Working rule: Make “comments versus expressive code” an explicit rule at the ExUnit, StreamData optional, :erts_debug boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "comments-versus-expressive-code-positive", focus: "comments versus expressive code", mode: :positive, expect: :observable} and %{id: "comments-versus-expressive-code-negative", focus: "comments versus expressive code", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Code-related anti-patterns
  6. simple extraction in clauses
    • Working rule: Make “simple extraction in clauses” an explicit rule at the ExUnit, StreamData optional, :erts_debug boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "simple-extraction-in-clauses-positive", focus: "simple extraction in clauses", mode: :positive, expect: :observable} and %{id: "simple-extraction-in-clauses-negative", focus: "simple extraction in clauses", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Code-related anti-patterns
  7. namespace ownership
    • Working rule: Make “namespace ownership” an explicit rule at the ExUnit, StreamData optional, :erts_debug boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "namespace-ownership-positive", focus: "namespace ownership", mode: :positive, expect: :observable} and %{id: "namespace-ownership-negative", focus: "namespace ownership", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Code-related anti-patterns
  8. strict booleans versus truthiness
    • Working rule: Make “strict booleans versus truthiness” an explicit rule at the ExUnit, StreamData optional, :erts_debug boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "strict-booleans-versus-truthiness-positive", focus: "strict booleans versus truthiness", mode: :positive, expect: :observable} and %{id: "strict-booleans-versus-truthiness-negative", focus: "strict booleans versus truthiness", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Code-related anti-patterns

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “assertive pattern matching” be enforced?
    • Which check catches the risk “Required data is accessed with a nil-producing lookup”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Missing required data fails at the pattern or access boundary”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Code-related anti-patterns”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: assertive pattern matching, bounded atoms, cohesive parameters and structs, simple with failure paths, comments versus expressive code, simple extraction in clauses, namespace ownership, strict booleans versus truthiness. Then trace the named counterexample “Required data is accessed with a nil-producing lookup” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose assertive pattern matching, and what does this project prove about it?”
  2. “What interaction between the concept ‘bounded atoms’ and the concept ‘assertive pattern matching’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘Required data is accessed with a nil-producing lookup’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with assertive-pattern-matching-positive and required-data-is-accessed-with-a-nil-producing-lookup-counterexample. The first must make the concept “assertive pattern matching” observable and establish “Missing required data fails at the pattern or access boundary”; the second must reproduce “Required data is accessed with a nil-producing lookup”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for anti-patterns/code-anti-patterns.md
evaluate "assertive pattern matching" through ExUnit, StreamData optional, :erts_debug
compare actual evidence with "Missing required data fails at the pattern or access boundary"
run negative fixture for "Required data is accessed with a nil-producing lookup"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Code-related anti-patterns Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
assertive pattern matching Elixir in Action, 3rd Edition Ch. 3-4: patterns and abstractions
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement assertive-pattern-matching-positive and prove “Missing required data fails at the pattern or access boundary”.
  3. Topic coverage: add fixtures for bounded atoms, cohesive parameters and structs, simple with failure paths, comments versus expressive code, simple extraction in clauses, namespace ownership, strict booleans versus truthiness.
  4. Failure campaign: reproduce each named risk: “Required data is accessed with a nil-producing lookup”; “String.to_atom receives external input”; “Unrelated parameters remain bundled in an oversized struct”; “A broad else branch hides which step failed”; “Comments paraphrase the next line and become stale”; “Nested field extraction obscures the clause contract”; “A module is defined inside another library’s namespace”; “A policy branch accepts any truthy term”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute assertive-pattern-matching-positive, bounded-atoms-positive, cohesive-parameters-and-structs-positive, simple-with-failure-paths-positive, comments-versus-expressive-code-positive, simple-extraction-in-clauses-positive, namespace-ownership-positive, strict-booleans-versus-truthiness-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute assertive-pattern-matching-negative, bounded-atoms-negative, cohesive-parameters-and-structs-negative, simple-with-failure-paths-negative, comments-versus-expressive-code-negative, simple-extraction-in-clauses-negative, namespace-ownership-negative, strict-booleans-versus-truthiness-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute required-data-is-accessed-with-a-nil-producing-lookup-counterexample, string-to-atom-receives-external-input-counterexample, unrelated-parameters-remain-bundled-in-an-oversized-struct-counterexample, a-broad-else-branch-hides-which-step-failed-counterexample, comments-paraphrase-the-next-line-and-become-stale-counterexample, nested-field-extraction-obscures-the-clause-contract-counterexample, a-module-is-defined-inside-another-library-s-namespace-counterexample, a-policy-branch-accepts-any-truthy-term-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real ExUnit, StreamData optional, :erts_debug boundary from a clean shell.
  • Mutation check: violate “Missing required data fails at the pattern or access boundary” and prove the suite reports fixture assertive-pattern-matching-positive as failed.
  • Regression corpus: retain the risks “Required data is accessed with a nil-producing lookup”; “String.to_atom receives external input”; “Unrelated parameters remain bundled in an oversized struct”; “A broad else branch hides which step failed”; “Comments paraphrase the next line and become stale”; “Nested field extraction obscures the clause contract”; “A module is defined inside another library’s namespace”; “A policy branch accepts any truthy term” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “Required data is accessed with a nil-producing lookup”

  • Why: This breaks one or more observable capabilities at the ExUnit, StreamData optional, :erts_debug boundary while allowing the happy path to look correct.
  • Fix: Run required-data-is-accessed-with-a-nil-producing-lookup-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “String.to_atom receives external input”

  • Why: This breaks one or more observable capabilities at the ExUnit, StreamData optional, :erts_debug boundary while allowing the happy path to look correct.
  • Fix: Run string-to-atom-receives-external-input-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “Unrelated parameters remain bundled in an oversized struct”

  • Why: This breaks one or more observable capabilities at the ExUnit, StreamData optional, :erts_debug boundary while allowing the happy path to look correct.
  • Fix: Run unrelated-parameters-remain-bundled-in-an-oversized-struct-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 4: “A broad else branch hides which step failed”

  • Why: This breaks one or more observable capabilities at the ExUnit, StreamData optional, :erts_debug boundary while allowing the happy path to look correct.
  • Fix: Run a-broad-else-branch-hides-which-step-failed-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 5: “Comments paraphrase the next line and become stale”

  • Why: This breaks one or more observable capabilities at the ExUnit, StreamData optional, :erts_debug boundary while allowing the happy path to look correct.
  • Fix: Run comments-paraphrase-the-next-line-and-become-stale-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 6: “Nested field extraction obscures the clause contract”

  • Why: This breaks one or more observable capabilities at the ExUnit, StreamData optional, :erts_debug boundary while allowing the happy path to look correct.
  • Fix: Run nested-field-extraction-obscures-the-clause-contract-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 7: “A module is defined inside another library’s namespace”

  • Why: This breaks one or more observable capabilities at the ExUnit, StreamData optional, :erts_debug boundary while allowing the happy path to look correct.
  • Fix: Run a-module-is-defined-inside-another-library-s-namespace-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 8: “A policy branch accepts any truthy term”

  • Why: This breaks one or more observable capabilities at the ExUnit, StreamData optional, :erts_debug boundary while allowing the happy path to look correct.
  • Fix: Run a-policy-branch-accepts-any-truthy-term-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • Missing required data fails at the pattern or access boundary.
  • Untrusted labels cannot create atoms.
  • Before-and-after structure and memory evidence are recorded.
  • Every with failure keeps its original named error.
  • Obvious comments are replaced by names that reveal intent.
  • Complex extraction moves behind a pattern-matched helper.
  • Extension modules remain under an owned namespace.
  • Boolean APIs reject non-boolean truthy values.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 65: Mix Dependency SBOM and License Auditor

Source: BEAM-P19. Inspect the dependency graph, package metadata, licenses, and policy exceptions before publishing libraries.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: Level 2: Micro-SaaS / Pro Tool
  • Curriculum Difficulty: Level 2: Intermediate
  • Knowledge Area: Build Tooling, Supply Chain
  • Software or Tool: Mix.Task, Mix.Project, Hex, CycloneDX
  • Main Book: “The Pragmatic Programmer”

What you will build: Inspect the dependency graph, package metadata, licenses, and policy exceptions before publishing libraries.

Why it teaches the BEAM ecosystem: It makes you prove that every transitive dependency has provenance and a repeatable policy result.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Inspect the dependency graph, package metadata, licenses, and policy exceptions before publishing libraries.

Build “mix supply_chain.sbom”, a reusable task that emits a CycloneDX-compatible JSON BOM and a license/source policy report. It supports a normal project and one documented aggregate umbrella strategy.

Scope boundary: Do not implement vulnerability scanning, package installation, signature verification, release upgrading, or a hosted dashboard. Do not execute dependency code to infer metadata.

$ mix supply_chain.sbom --format cyclonedx-json --output tmp/bom.json \
    --policy config/supply-chain-policy.json --reproducible
project=storefront env=prod components=37 relationships=52
sources=hex:34,git:1,path:2 licenses_known=33 unknown=4
findings=warning:3,error:1
ERROR package=legacy_codec rule=license.deny evidence=GPL-3.0-only
bom=tmp/bom.json policy_report=tmp/bom.policy.json
status=policy_failed

3.7.1 How to Run

Run against small fixture Mix projects representing Hex, Git, path, shared-transitive, and umbrella shapes. Validate BOM files with the pinned official schema and compare reproducible checksums.

3.7.2 Golden Path Demo

A fixture diamond graph emits four components and four relationships, not a duplicated shared node. A denied license fails policy after writing both BOM and findings.

3.7.3 Exact Terminal Transcript

$ mix supply_chain.sbom --fixture test/fixtures/diamond --output tmp/a.json --reproducible
components=4 relationships=4 findings=0 status=ok
$ mix supply_chain.sbom --fixture test/fixtures/diamond --output tmp/b.json --reproducible
components=4 relationships=4 findings=0 status=ok
$ shasum -a 256 tmp/a.json tmp/b.json
9ca2... tmp/a.json
9ca2... tmp/b.json

The Core Question You Are Answering

How can a Mix extension turn resolved build metadata into reproducible, standards-shaped evidence and enforce policy without obscuring uncertainty?

Concepts You Must Understand First

Understand Mix task lifecycle, Mix project/dependency metadata, lock semantics, graph traversal, Version/requirements, deterministic sorting, JSON schema validation, SPDX expression boundaries, and shell exit semantics.

Questions to Guide Your Design

  1. What is the stable identity for each source type?
  2. Which evidence is requested versus resolved?
  3. How are shared nodes and all edges preserved?
  4. What makes reproducible output byte-stable?
  5. What is unknown, and may policy fail on it?
  6. How are exceptions reviewed and expired?

Thinking Exercise

Draw root A depending on B and C, both depending on D. Add D under a different OTP application name than package name. Show requested constraints, locked versions, component refs, and four graph edges.

The Interview Questions They Will Ask

  1. How do you create and test a custom Mix task?
  2. Why is the dependency model a graph rather than a tree?
  3. What information comes from mix.exs versus mix.lock?
  4. How do you make JSON generation reproducible?
  5. Why should unknown license metadata remain explicit?
  6. How should a CI task behave when policy fails after report generation?

Hints in Layers

Hint 1: Make one fixture project emit canonical components before CycloneDX.

Hint 2: Separate component discovery from edge preservation.

Hint 3: Build deterministic bom-ref values and assert graph closure.

Hint 4: Render/validate the BOM before evaluating policy and deciding process status.

Books That Will Help

Topic Book Chapter
Mix project organization “Programming Elixir >= 1.6” by Dave Thomas Ch. 13, Organizing a Project
Software supply chains “Building Secure and Reliable Systems” by Google Ch. 14, Configuration Design; Ch. 18, Recovery and Aftercare
Evolution and compatibility “Building Evolutionary Architectures, 2nd Edition” Ch. 3, Engineering Incremental Change; Ch. 4, Architectural Coupling

Implementation Milestones

Phase 1: Foundation (4-5 hours)

Implement task shell, run context, fixture projects, evidence types, source sanitization, and direct dependency inventory.

Phase 2: Core Functionality (4-7 hours)

Add transitive graph traversal, stable refs, CycloneDX mapping, deterministic serialization, and schema validation.

Phase 3: Polish & Edge Cases (4-6 hours)

Add licenses/policy/exceptions, umbrella mode, Git/path fixtures, reproducibility, atomic output, and task re-enable tests.

Testing Strategy

6.1 Test Categories

  • Strict CLI/task lifecycle tests
  • Evidence adapter tests
  • Graph closure/shared-node/cycle tests
  • CycloneDX schema and deterministic snapshot tests
  • Source credential-redaction tests
  • License policy decision-table tests
  • Fixture project/umbrella end-to-end tests

6.2 Critical Test Cases

  1. Diamond graph emits shared component once and every edge.
  2. Git requested branch and locked revision remain distinct.
  3. Local path source does not receive a fake checksum/package URL.
  4. Unknown license follows configured policy.
  5. Compound unsupported expression is not guessed.
  6. Policy failure still leaves valid BOM/report files.
  7. Reproducible runs are byte-identical.
  8. Source credentials never appear in output.

6.3 Test Data

Create miniature Mix fixtures for direct/transitive/diamond, Git, path, missing metadata, umbrella, optional/dev-only, and sanitized credential-looking URLs. Pin BOM expected data independently of runtime map order.

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Missing relationships: Traversal stopped when a node was visited. Skip expansion but retain the edge.

Duplicate components: Identity used application name in one path and package name in another. Centralize refs.

Nondeterministic BOM: Maps, timestamps, or random serials leaked into output. Normalize and sort all collections.

License false confidence: Free text was mapped aggressively. Preserve raw evidence and unknown status.

7.2 Debugging Strategies

Render a canonical graph table before CycloneDX mapping. For each field, expose evidence origin in debug mode. Validate graph closure and unique refs separately from JSON schema. Compare normalized documents when hashes differ.

7.3 Performance Traps

Repeated dependency expansion, repeated lock parsing, network metadata fetches, and quadratic list membership checks waste work. Index evidence once and use MapSet for traversal state.

Definition of Done

  • A custom Mix task documents options and exit behavior.
  • Component identities and all graph edges are stable and complete.
  • Hex, Git, and path evidence are represented honestly.
  • Output validates against a pinned CycloneDX schema.
  • Reproducible mode produces byte-identical BOMs.
  • Unknown licenses and exceptions remain explicit.
  • Policy failures emit complete artifacts before nonzero exit.
  • Tests cover ordinary and umbrella fixtures.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • every transitive dependency has provenance and a repeatable policy result.

Project 66: SBOM Release Attestation and Incident-Response Gate

Official topic: Software Bill of Materials — Elixir v1.20.2

Source file: lib/elixir/pages/references/sbom.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 2: Intermediate
  • Knowledge Area: Software Supply Chain
  • Software or Tool: mix_sbom, CycloneDX, SPDX, ORT
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build a release gate that consumes CycloneDX output, diffs two releases, answers a simulated CVE exposure question, enforces procurement and license policy, and attaches deeper ORT evidence.

Why it teaches this official topic: The artifact makes SBOM component inventory, release attestation, vulnerability response, file-level dependency analysis observable through one bounded build instead of isolated syntax examples.

Scope boundary: Consume and operationalize SBOM output; leave generation and basic license inventory to the existing auditor.

Core challenges you will face:

  • SBOM component inventory -> identify the accepted case, the counterexample, and the observable result at the mix_sbom, CycloneDX, SPDX, ORT boundary
  • release attestation -> identify the accepted case, the counterexample, and the observable result at the mix_sbom, CycloneDX, SPDX, ORT boundary
  • vulnerability response -> identify the accepted case, the counterexample, and the observable result at the mix_sbom, CycloneDX, SPDX, ORT boundary
  • file-level dependency analysis -> identify the accepted case, the counterexample, and the observable result at the mix_sbom, CycloneDX, SPDX, ORT boundary

Real World Outcome

Build a release gate that consumes CycloneDX output, diffs two releases, answers a simulated CVE exposure question, enforces procurement and license policy, and attaches deeper ORT evidence. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Release components and hashes are attestable.
  • A CVE query identifies affected and unaffected releases.
  • Policy failures block the gate with component evidence.

Acceptance transcript:

$ mix sbom.gate --fixture release-b
SOURCE_TOPIC=references/sbom.md
ARTIFACT=sbom-release-attestation-and-incident-response-gate
CHECK 01 PASS :: Release components and hashes are attestable
CHECK 02 PASS :: A CVE query identifies affected and unaffected releases
CHECK 03 PASS :: Policy failures block the gate with component evidence
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“How does an SBOM become operational evidence for release approval and incident response rather than a static file?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. SBOM component inventory
    • Working rule: Make “SBOM component inventory” an explicit rule at the mix_sbom, CycloneDX, SPDX, ORT boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "sbom-component-inventory-positive", focus: "SBOM component inventory", mode: :positive, expect: :observable} and %{id: "sbom-component-inventory-negative", focus: "SBOM component inventory", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Software Bill of Materials
  2. release attestation
    • Working rule: Make “release attestation” an explicit rule at the mix_sbom, CycloneDX, SPDX, ORT boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "release-attestation-positive", focus: "release attestation", mode: :positive, expect: :observable} and %{id: "release-attestation-negative", focus: "release attestation", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Software Bill of Materials
  3. vulnerability response
    • Working rule: Make “vulnerability response” an explicit rule at the mix_sbom, CycloneDX, SPDX, ORT boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "vulnerability-response-positive", focus: "vulnerability response", mode: :positive, expect: :observable} and %{id: "vulnerability-response-negative", focus: "vulnerability response", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Software Bill of Materials
  4. file-level dependency analysis
    • Working rule: Make “file-level dependency analysis” an explicit rule at the mix_sbom, CycloneDX, SPDX, ORT boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "file-level-dependency-analysis-positive", focus: "file-level dependency analysis", mode: :positive, expect: :observable} and %{id: "file-level-dependency-analysis-negative", focus: "file-level dependency analysis", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Software Bill of Materials

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “SBOM component inventory” be enforced?
    • Which check catches the risk “An inventory is described as a security certification”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Release components and hashes are attestable”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Software Bill of Materials”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: SBOM component inventory, release attestation, vulnerability response, file-level dependency analysis. Then trace the named counterexample “An inventory is described as a security certification” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose SBOM component inventory, and what does this project prove about it?”
  2. “What interaction between the concept ‘release attestation’ and the concept ‘SBOM component inventory’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘An inventory is described as a security certification’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with sbom-component-inventory-positive and an-inventory-is-described-as-a-security-certification-counterexample. The first must make the concept “SBOM component inventory” observable and establish “Release components and hashes are attestable”; the second must reproduce “An inventory is described as a security certification”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for references/sbom.md
evaluate "SBOM component inventory" through mix_sbom, CycloneDX, SPDX, ORT
compare actual evidence with "Release components and hashes are attestable"
run negative fixture for "An inventory is described as a security certification"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix sbom.gate --fixture release-b from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Software Bill of Materials Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
SBOM component inventory Elixir in Action, 3rd Edition Ch. 9-10: releases and operations
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement sbom-component-inventory-positive and prove “Release components and hashes are attestable”.
  3. Topic coverage: add fixtures for release attestation, vulnerability response, file-level dependency analysis.
  4. Failure campaign: reproduce each named risk: “An inventory is described as a security certification”; “Transitive components disappear from the diff”; “License policy lacks package provenance”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute sbom-component-inventory-positive, release-attestation-positive, vulnerability-response-positive, file-level-dependency-analysis-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute sbom-component-inventory-negative, release-attestation-negative, vulnerability-response-negative, file-level-dependency-analysis-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute an-inventory-is-described-as-a-security-certification-counterexample, transitive-components-disappear-from-the-diff-counterexample, license-policy-lacks-package-provenance-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix sbom.gate --fixture release-b through the real mix_sbom, CycloneDX, SPDX, ORT boundary from a clean shell.
  • Mutation check: violate “Release components and hashes are attestable” and prove the suite reports fixture sbom-component-inventory-positive as failed.
  • Regression corpus: retain the risks “An inventory is described as a security certification”; “Transitive components disappear from the diff”; “License policy lacks package provenance” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “An inventory is described as a security certification”

  • Why: This breaks one or more observable capabilities at the mix_sbom, CycloneDX, SPDX, ORT boundary while allowing the happy path to look correct.
  • Fix: Run an-inventory-is-described-as-a-security-certification-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix sbom.gate --fixture release-b

Problem 2: “Transitive components disappear from the diff”

  • Why: This breaks one or more observable capabilities at the mix_sbom, CycloneDX, SPDX, ORT boundary while allowing the happy path to look correct.
  • Fix: Run transitive-components-disappear-from-the-diff-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix sbom.gate --fixture release-b

Problem 3: “License policy lacks package provenance”

  • Why: This breaks one or more observable capabilities at the mix_sbom, CycloneDX, SPDX, ORT boundary while allowing the happy path to look correct.
  • Fix: Run license-policy-lacks-package-provenance-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix sbom.gate --fixture release-b

Definition of Done

  • Release components and hashes are attestable.
  • A CVE query identifies affected and unaffected releases.
  • Policy failures block the gate with component evidence.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 67: Third-Party Encoder Behaviour SDK

Official topic: Typespecs reference — Elixir v1.20.2

Source file: lib/elixir/pages/references/typespecs.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 2: Intermediate
  • Knowledge Area: Library Contracts / Static Analysis
  • Software or Tool: typespecs, behaviours, Dialyzer
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build a process-free callback SDK with public and opaque types, required and optional callbacks, two external implementations, impl annotations, ExDoc contracts, Dialyzer checks, and a conformance suite.

Why it teaches this official topic: The artifact makes types and specs, public, private, and opaque types, behaviour callbacks, optional callbacks and introspection observable through one bounded build instead of isolated syntax examples.

Scope boundary: Keep the SDK process-free and type-centered; exclude GenServer mechanics and storage adapters.

Core challenges you will face:

  • types and specs -> identify the accepted case, the counterexample, and the observable result at the typespecs, behaviours, Dialyzer boundary
  • public, private, and opaque types -> identify the accepted case, the counterexample, and the observable result at the typespecs, behaviours, Dialyzer boundary
  • behaviour callbacks -> identify the accepted case, the counterexample, and the observable result at the typespecs, behaviours, Dialyzer boundary
  • optional callbacks and introspection -> identify the accepted case, the counterexample, and the observable result at the typespecs, behaviours, Dialyzer boundary

Real World Outcome

Build a process-free callback SDK with public and opaque types, required and optional callbacks, two external implementations, impl annotations, ExDoc contracts, Dialyzer checks, and a conformance suite. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Both implementations satisfy one callback conformance suite.
  • Opaque state is not coupled to consumers.
  • Optional capability discovery is explicit.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=references/typespecs.md
ARTIFACT=third-party-encoder-behaviour-sdk
CHECK 01 PASS :: Both implementations satisfy one callback conformance suite
CHECK 02 PASS :: Opaque state is not coupled to consumers
CHECK 03 PASS :: Optional capability discovery is explicit
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“How can typespecs and behaviours define an evolvable contract for implementations maintained by other teams?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. types and specs
    • Working rule: Make “types and specs” an explicit rule at the typespecs, behaviours, Dialyzer boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "types-and-specs-positive", focus: "types and specs", mode: :positive, expect: :observable} and %{id: "types-and-specs-negative", focus: "types and specs", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Typespecs reference
  2. public, private, and opaque types
    • Working rule: Make “public, private, and opaque types” an explicit rule at the typespecs, behaviours, Dialyzer boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "public-private-and-opaque-types-positive", focus: "public, private, and opaque types", mode: :positive, expect: :observable} and %{id: "public-private-and-opaque-types-negative", focus: "public, private, and opaque types", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Typespecs reference
  3. behaviour callbacks
    • Working rule: Make “behaviour callbacks” an explicit rule at the typespecs, behaviours, Dialyzer boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "behaviour-callbacks-positive", focus: "behaviour callbacks", mode: :positive, expect: :observable} and %{id: "behaviour-callbacks-negative", focus: "behaviour callbacks", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Typespecs reference
  4. optional callbacks and introspection
    • Working rule: Make “optional callbacks and introspection” an explicit rule at the typespecs, behaviours, Dialyzer boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "optional-callbacks-and-introspection-positive", focus: "optional callbacks and introspection", mode: :positive, expect: :observable} and %{id: "optional-callbacks-and-introspection-negative", focus: "optional callbacks and introspection", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Typespecs reference

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “types and specs” be enforced?
    • Which check catches the risk “A spec is treated as runtime enforcement”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Both implementations satisfy one callback conformance suite”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Typespecs reference”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: types and specs, public, private, and opaque types, behaviour callbacks, optional callbacks and introspection. Then trace the named counterexample “A spec is treated as runtime enforcement” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose types and specs, and what does this project prove about it?”
  2. “What interaction between the concept ‘public, private, and opaque types’ and the concept ‘types and specs’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘A spec is treated as runtime enforcement’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with types-and-specs-positive and a-spec-is-treated-as-runtime-enforcement-counterexample. The first must make the concept “types and specs” observable and establish “Both implementations satisfy one callback conformance suite”; the second must reproduce “A spec is treated as runtime enforcement”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for references/typespecs.md
evaluate "types and specs" through typespecs, behaviours, Dialyzer
compare actual evidence with "Both implementations satisfy one callback conformance suite"
run negative fixture for "A spec is treated as runtime enforcement"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Typespecs reference Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
types and specs Elixir in Action, 3rd Edition Ch. 4: abstractions; Dialyzer documentation
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement types-and-specs-positive and prove “Both implementations satisfy one callback conformance suite”.
  3. Topic coverage: add fixtures for public, private, and opaque types, behaviour callbacks, optional callbacks and introspection.
  4. Failure campaign: reproduce each named risk: “A spec is treated as runtime enforcement”; “String type is confused with charlist”; “A raising function is given an impossible no-return contract”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute types-and-specs-positive, public-private-and-opaque-types-positive, behaviour-callbacks-positive, optional-callbacks-and-introspection-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute types-and-specs-negative, public-private-and-opaque-types-negative, behaviour-callbacks-negative, optional-callbacks-and-introspection-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute a-spec-is-treated-as-runtime-enforcement-counterexample, string-type-is-confused-with-charlist-counterexample, a-raising-function-is-given-an-impossible-no-return-contract-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real typespecs, behaviours, Dialyzer boundary from a clean shell.
  • Mutation check: violate “Both implementations satisfy one callback conformance suite” and prove the suite reports fixture types-and-specs-positive as failed.
  • Regression corpus: retain the risks “A spec is treated as runtime enforcement”; “String type is confused with charlist”; “A raising function is given an impossible no-return contract” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “A spec is treated as runtime enforcement”

  • Why: This breaks one or more observable capabilities at the typespecs, behaviours, Dialyzer boundary while allowing the happy path to look correct.
  • Fix: Run a-spec-is-treated-as-runtime-enforcement-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “String type is confused with charlist”

  • Why: This breaks one or more observable capabilities at the typespecs, behaviours, Dialyzer boundary while allowing the happy path to look correct.
  • Fix: Run string-type-is-confused-with-charlist-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “A raising function is given an impossible no-return contract”

  • Why: This breaks one or more observable capabilities at the typespecs, behaviours, Dialyzer boundary while allowing the happy path to look correct.
  • Fix: Run a-raising-function-is-given-an-impossible-no-return-contract-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • Both implementations satisfy one callback conformance suite.
  • Opaque state is not coupled to consumers.
  • Optional capability discovery is explicit.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 68: Stable Invoice SDK Contract Redesign

Official topic: Design-related anti-patterns — Elixir v1.20.2

Source file: lib/elixir/pages/anti-patterns/design-anti-patterns.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 2: Intermediate
  • Knowledge Area: API Design / Domain Modeling
  • Software or Tool: ExUnit and compatibility fixtures
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Redesign a reusable invoice SDK around named return APIs, tagged errors and bang variants, role states instead of booleans, Money and Address types, cohesive modules, and caller-owned configuration.

Why it teaches this official topic: The artifact makes stable return contracts, domain types over primitives, cohesive function clauses, library configuration ownership observable through one bounded build instead of isolated syntax examples.

Scope boundary: Grade API semantics and multi-consumer configuration, not adapter mechanics or Phoenix endpoints.

Core challenges you will face:

  • stable return contracts -> identify the accepted case, the counterexample, and the observable result at the ExUnit and compatibility fixtures boundary
  • domain types over primitives -> identify the accepted case, the counterexample, and the observable result at the ExUnit and compatibility fixtures boundary
  • cohesive function clauses -> identify the accepted case, the counterexample, and the observable result at the ExUnit and compatibility fixtures boundary
  • library configuration ownership -> identify the accepted case, the counterexample, and the observable result at the ExUnit and compatibility fixtures boundary

Real World Outcome

Redesign a reusable invoice SDK around named return APIs, tagged errors and bang variants, role states instead of booleans, Money and Address types, cohesive modules, and caller-owned configuration. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Existing consumers receive a documented migration path.
  • Boolean states become an explicit finite domain.
  • Multiple consumers configure independent instances.

Acceptance transcript:

$ mix run scripts/verify_topic.exs
SOURCE_TOPIC=anti-patterns/design-anti-patterns.md
ARTIFACT=stable-invoice-sdk-contract-redesign
CHECK 01 PASS :: Existing consumers receive a documented migration path
CHECK 02 PASS :: Boolean states become an explicit finite domain
CHECK 03 PASS :: Multiple consumers configure independent instances
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“How do return shapes, domain types, module cohesion, and configuration ownership determine whether a library remains composable?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. stable return contracts
    • Working rule: Make “stable return contracts” an explicit rule at the ExUnit and compatibility fixtures boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "stable-return-contracts-positive", focus: "stable return contracts", mode: :positive, expect: :observable} and %{id: "stable-return-contracts-negative", focus: "stable return contracts", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Design-related anti-patterns
  2. domain types over primitives
    • Working rule: Make “domain types over primitives” an explicit rule at the ExUnit and compatibility fixtures boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "domain-types-over-primitives-positive", focus: "domain types over primitives", mode: :positive, expect: :observable} and %{id: "domain-types-over-primitives-negative", focus: "domain types over primitives", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Design-related anti-patterns
  3. cohesive function clauses
    • Working rule: Make “cohesive function clauses” an explicit rule at the ExUnit and compatibility fixtures boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "cohesive-function-clauses-positive", focus: "cohesive function clauses", mode: :positive, expect: :observable} and %{id: "cohesive-function-clauses-negative", focus: "cohesive function clauses", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Design-related anti-patterns
  4. library configuration ownership
    • Working rule: Make “library configuration ownership” an explicit rule at the ExUnit and compatibility fixtures boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "library-configuration-ownership-positive", focus: "library configuration ownership", mode: :positive, expect: :observable} and %{id: "library-configuration-ownership-negative", focus: "library configuration ownership", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Design-related anti-patterns

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “stable return contracts” be enforced?
    • Which check catches the risk “One function returns unrelated success shapes”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Existing consumers receive a documented migration path”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Design-related anti-patterns”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: stable return contracts, domain types over primitives, cohesive function clauses, library configuration ownership. Then trace the named counterexample “One function returns unrelated success shapes” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose stable return contracts, and what does this project prove about it?”
  2. “What interaction between the concept ‘domain types over primitives’ and the concept ‘stable return contracts’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘One function returns unrelated success shapes’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with stable-return-contracts-positive and one-function-returns-unrelated-success-shapes-counterexample. The first must make the concept “stable return contracts” observable and establish “Existing consumers receive a documented migration path”; the second must reproduce “One function returns unrelated success shapes”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for anti-patterns/design-anti-patterns.md
evaluate "stable return contracts" through ExUnit and compatibility fixtures
compare actual evidence with "Existing consumers receive a documented migration path"
run negative fixture for "One function returns unrelated success shapes"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_topic.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Design-related anti-patterns Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
stable return contracts Elixir in Action, 3rd Edition Ch. 4: data abstractions
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement stable-return-contracts-positive and prove “Existing consumers receive a documented migration path”.
  3. Topic coverage: add fixtures for domain types over primitives, cohesive function clauses, library configuration ownership.
  4. Failure campaign: reproduce each named risk: “One function returns unrelated success shapes”; “Exceptions drive ordinary branching”; “Library behavior depends on global application environment”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute stable-return-contracts-positive, domain-types-over-primitives-positive, cohesive-function-clauses-positive, library-configuration-ownership-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute stable-return-contracts-negative, domain-types-over-primitives-negative, cohesive-function-clauses-negative, library-configuration-ownership-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute one-function-returns-unrelated-success-shapes-counterexample, exceptions-drive-ordinary-branching-counterexample, library-behavior-depends-on-global-application-environment-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_topic.exs through the real ExUnit and compatibility fixtures boundary from a clean shell.
  • Mutation check: violate “Existing consumers receive a documented migration path” and prove the suite reports fixture stable-return-contracts-positive as failed.
  • Regression corpus: retain the risks “One function returns unrelated success shapes”; “Exceptions drive ordinary branching”; “Library behavior depends on global application environment” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “One function returns unrelated success shapes”

  • Why: This breaks one or more observable capabilities at the ExUnit and compatibility fixtures boundary while allowing the happy path to look correct.
  • Fix: Run one-function-returns-unrelated-success-shapes-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 2: “Exceptions drive ordinary branching”

  • Why: This breaks one or more observable capabilities at the ExUnit and compatibility fixtures boundary while allowing the happy path to look correct.
  • Fix: Run exceptions-drive-ordinary-branching-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Problem 3: “Library behavior depends on global application environment”

  • Why: This breaks one or more observable capabilities at the ExUnit and compatibility fixtures boundary while allowing the happy path to look correct.
  • Fix: Run library-behavior-depends-on-global-application-environment-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_topic.exs

Definition of Done

  • Existing consumers receive a documented migration path.
  • Boolean states become an explicit finite domain.
  • Multiple consumers configure independent instances.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 69: Pluggable Object Storage Library

Source: BEAM-P23. Build behaviours, protocols, multiple adapters, and shared contract tests.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: Level 2: Micro-SaaS / Pro Tool
  • Curriculum Difficulty: Level 2: Intermediate
  • Knowledge Area: Library Design, Packaging
  • Software or Tool: Behaviours, Protocols, ExUnit, Hex
  • Main Book: “The Pragmatic Programmer”

What you will build: Build behaviours, protocols, multiple adapters, and shared contract tests.

Why it teaches the BEAM ecosystem: It makes you prove that a third adapter requires no caller changes and passes the same contract.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Build behaviours, protocols, multiple adapters, and shared contract tests.

Create a library tentatively named ObjectDock with a public storage reference, required adapter behaviour, upload-source protocol, canonical structs/errors, and three adapters: memory, safe local disk, and a simulated S3-compatible HTTP service. Prepare—but do not actually publish—a Hex package.

$ objectdock put local:photos portraits/a.bin --from fixture.bin
stored key=portraits/a.bin bytes=4096 etag=sha256:9d... adapter=local

$ objectdock stat memory:test portraits/a.bin
error=not_found

$ objectdock capabilities http:staging
core=[put,get,stat,delete,list]
optional=[range_read,conditional_put]

3.7.1 How to Run (Copy/Paste)

$ mix deps.get
$ mix test
$ mix docs
$ mix hex.build --unpack
$ objectdock-contract --all-adapters

3.7.2 Golden Path Demo (Deterministic)

The contract runner stores the same fixture through all three adapters, verifies byte/content metadata round-trip, replacement, listing, and deletion, then inspects the unpacked package allow-list.

3.7.3 Exact terminal transcript

$ objectdock-contract --all-adapters
adapter=memory cases=24 passed=24 failed=0
adapter=local cases=24 passed=24 failed=0
adapter=http_compatible cases=24 passed=24 failed=0
optional range_read memory=unsupported local=supported http_compatible=supported
package files=31 forbidden_files=0 docs=true license=true
CONTRACT PASS

The Core Question You Are Answering

“How do I publish an Elixir abstraction whose adapters can differ internally without surprising callers externally?”

Concepts You Must Understand First

  1. Behaviours and typespecs — Elixir in Action, 3rd Edition, Chapter 5, “Higher-level abstractions”.
  2. Protocol dispatch — Programming Elixir 1.6, Chapter 20, “Protocols”.
  3. Package compatibility — Semantic Versioning 2.0.0 specification.
  4. Contract testing — Growing Object-Oriented Software, Guided by Tests, Chapter 8, adapted to adapters.

Questions to Guide Your Design

  1. What is the smallest useful required API?
  2. Which backend differences are genuine capabilities?
  3. Who owns processes, streams, temporary files, and HTTP bodies?
  4. Can a third party author an adapter using only public documentation and tests?
  5. What observable changes would break consumers?

Thinking Exercise

Compare a disk rename, an in-memory map replacement, and an HTTP conditional put. Write the exact guarantee the common put can promise. Move stronger behavior into a capability rather than quietly overstating the core contract.

The Interview Questions They Will Ask

  1. What is the difference between an Elixir behaviour and protocol?
  2. How do optional callbacks differ from runtime capabilities?
  3. How do you keep a test adapter faithful to production semantics?
  4. What does @impl check, and what does it not check?
  5. How would you evolve a callback without breaking external adapters?
  6. What should be inspected before publishing a Hex package?

Hints in Layers

Hint 1: Write the contract prose first — Decide key, overwrite, delete, and missing semantics before callbacks.

Hint 2: Let memory expose ambiguity — Build the simplest adapter and make every vague behavior a test decision.

Hint 3: Treat disk as hostile — Test traversal and symlink boundaries before happy-path performance.

Hint 4: Consume your package — Unpack the artifact and run a tiny external fixture project against its public API.

Books That Will Help

Topic Book Chapter
Elixir abstractions Elixir in Action, 3rd Edition Ch. 5
Protocols Programming Elixir 1.6 Ch. 20
API evolution Building Evolutionary Architectures, 2nd Edition Ch. 4–5
Testing contracts Growing Object-Oriented Software, Guided by Tests Ch. 8

Implementation Milestones

Phase 1: Contract and Memory Adapter (4-6 hours)

  • Define canonical types, behaviour, memory implementation, and first contract cases.

Phase 2: Real Boundaries (6-10 hours)

  • Build safe-disk and HTTP-compatible adapters; add capabilities and ownership tests.

Phase 3: Publishability (4-6 hours)

  • Complete docs, doctests, adapter guide, changelog policy, Hex metadata, and artifact inspection.

Testing Strategy

6.1 Test Categories

Category Purpose Examples
Conformance Same semantics for all adapters round-trip, overwrite, delete
Key security Protect disk and canonical identity traversal, absolute, Unicode
Ownership Close resources and isolate instances stream failure, HTTP body cleanup
Capability Keep optional behavior truthful declared/implemented agreement
Documentation Keep examples executable doctests and external consumer
Package Verify published artifact unpacked allow-list and metadata

6.2 Critical Test Cases

  1. Each adapter round-trips arbitrary binary content and normalized metadata.
  2. Missing-object and idempotent-delete policy is identical everywhere.
  3. Disk keys cannot escape the root through traversal, separators, or symlinks.
  4. Midstream source failure leaves no successful partial object under the target key.
  5. Page continuation yields every object exactly once in stable order.
  6. Every declared capability executes; undeclared features return unsupported.
  7. Two storage instances with different configuration do not share state accidentally.
  8. Unpacked Hex artifact contains source, docs, README, and license but no credentials, build artifacts, or large fixtures.

6.3 Test Data

Use empty and multi-megabyte binaries, iodata-like chunks, Unicode metadata, path-like malicious keys, hundreds of sorted keys, forced HTTP failures, and temporary roots with symlink traps.

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Problem: “Tests pass in memory and fail in production.”

  • Why: The fake invents friendlier overwrite, ordering, or missing-object behavior.
  • Fix: Run the exact same contract cases against every adapter.
  • Quick test: Produce a per-adapter contract matrix and compare case names.

Problem: “Disk keys write outside the root.”

  • Why: Untrusted keys are concatenated into paths.
  • Fix: Validate/encode keys and verify resolved containment; test symlinks.
  • Quick test: Attempt absolute, .., mixed-separator, and symlink escape cases.

Problem: “External adapters break after a minor release.”

  • Why: A callback became required or a return shape changed.
  • Fix: Treat implementers as consumers and follow semantic versioning.
  • Quick test: Compile an adapter fixture written against the prior contract.

7.2 Debugging Strategies

  • Log canonical operation, adapter module, key digest, and stable error—never credentials.
  • Re-run one failing contract case with adapter-specific transport tracing.
  • Inspect the storage reference to confirm the intended adapter instance.
  • Unpack the Hex tarball rather than assuming repository contents equal package contents.

7.3 Performance Traps

  • Converting streamed bodies into one large binary without declaring a limit.
  • Listing an entire bucket to implement one page.
  • Starting a new HTTP pool per operation.
  • Serializing all memory operations through one process when ETS semantics would suffice.

Definition of Done

  • Required behaviour and all canonical return/error types are documented and typed.
  • Memory, safe-disk, and HTTP-compatible adapters pass one shared contract suite.
  • Capabilities accurately represent optional operations.
  • Disk adapter passes traversal and symlink-escape tests.
  • Multiple adapter instances have explicit supervised ownership and isolation.
  • Public examples pass as doctests and from an external fixture project.
  • mix hex.build --unpack yields only intended files and valid metadata.
  • Semantic-version policy identifies callback and result-shape breaking changes.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • a third adapter requires no caller changes and passes the same contract.

Project 70: Hex Package Consumer-Compatibility Factory

Official topic: Library guidelines — Elixir v1.20.2

Source file: lib/elixir/pages/references/library-guidelines.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: Level 1: Resume Gold
  • Curriculum Difficulty: Level 2: Intermediate
  • Knowledge Area: Library Engineering / Packaging
  • Software or Tool: Mix, Hex, ExDoc, CI matrix
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build a publishable package candidate with license, semantic version, formatting, tests, doctests, ExDoc, Hex dry-run evidence, optional dependency behavior, and locked, unlocked-latest, and minimal CI lanes.

Why it teaches this official topic: The artifact makes package structure and licensing, semantic versioning and publishing, dependency environments, consumer compatibility testing observable through one bounded build instead of isolated syntax examples.

Scope boundary: Own packaging and consumer compatibility; leave storage adapter design and dependency inventory to other projects.

Core challenges you will face:

  • package structure and licensing -> identify the accepted case, the counterexample, and the observable result at the Mix, Hex, ExDoc, CI matrix boundary
  • semantic versioning and publishing -> identify the accepted case, the counterexample, and the observable result at the Mix, Hex, ExDoc, CI matrix boundary
  • dependency environments -> identify the accepted case, the counterexample, and the observable result at the Mix, Hex, ExDoc, CI matrix boundary
  • consumer compatibility testing -> identify the accepted case, the counterexample, and the observable result at the Mix, Hex, ExDoc, CI matrix boundary

Real World Outcome

Build a publishable package candidate with license, semantic version, formatting, tests, doctests, ExDoc, Hex dry-run evidence, optional dependency behavior, and locked, unlocked-latest, and minimal CI lanes. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Hex build and docs checks pass without publishing.
  • Locked and latest-dependency lanes both pass.
  • Optional dependencies are absent in the minimal lane.

Acceptance transcript:

$ mix package.verify
SOURCE_TOPIC=references/library-guidelines.md
ARTIFACT=hex-package-consumer-compatibility-factory
CHECK 01 PASS :: Hex build and docs checks pass without publishing
CHECK 02 PASS :: Locked and latest-dependency lanes both pass
CHECK 03 PASS :: Optional dependencies are absent in the minimal lane
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“What evidence proves an Elixir library is safe to publish and remains usable across realistic consumer dependency states?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. package structure and licensing
    • Working rule: Make “package structure and licensing” an explicit rule at the Mix, Hex, ExDoc, CI matrix boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "package-structure-and-licensing-positive", focus: "package structure and licensing", mode: :positive, expect: :observable} and %{id: "package-structure-and-licensing-negative", focus: "package structure and licensing", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Library guidelines
  2. semantic versioning and publishing
    • Working rule: Make “semantic versioning and publishing” an explicit rule at the Mix, Hex, ExDoc, CI matrix boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "semantic-versioning-and-publishing-positive", focus: "semantic versioning and publishing", mode: :positive, expect: :observable} and %{id: "semantic-versioning-and-publishing-negative", focus: "semantic versioning and publishing", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Library guidelines
  3. dependency environments
    • Working rule: Make “dependency environments” an explicit rule at the Mix, Hex, ExDoc, CI matrix boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "dependency-environments-positive", focus: "dependency environments", mode: :positive, expect: :observable} and %{id: "dependency-environments-negative", focus: "dependency environments", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Library guidelines
  4. consumer compatibility testing
    • Working rule: Make “consumer compatibility testing” an explicit rule at the Mix, Hex, ExDoc, CI matrix boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "consumer-compatibility-testing-positive", focus: "consumer compatibility testing", mode: :positive, expect: :observable} and %{id: "consumer-compatibility-testing-negative", focus: "consumer compatibility testing", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Library guidelines

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “package structure and licensing” be enforced?
    • Which check catches the risk “A library commits assumptions from its local lockfile”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Hex build and docs checks pass without publishing”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Library guidelines”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: package structure and licensing, semantic versioning and publishing, dependency environments, consumer compatibility testing. Then trace the named counterexample “A library commits assumptions from its local lockfile” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose package structure and licensing, and what does this project prove about it?”
  2. “What interaction between the concept ‘semantic versioning and publishing’ and the concept ‘package structure and licensing’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘A library commits assumptions from its local lockfile’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with package-structure-and-licensing-positive and a-library-commits-assumptions-from-its-local-lockfile-counterexample. The first must make the concept “package structure and licensing” observable and establish “Hex build and docs checks pass without publishing”; the second must reproduce “A library commits assumptions from its local lockfile”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for references/library-guidelines.md
evaluate "package structure and licensing" through Mix, Hex, ExDoc, CI matrix
compare actual evidence with "Hex build and docs checks pass without publishing"
run negative fixture for "A library commits assumptions from its local lockfile"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix package.verify from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Library guidelines Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
package structure and licensing Elixir in Action, 3rd Edition Ch. 4 and 10: libraries and release discipline
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement package-structure-and-licensing-positive and prove “Hex build and docs checks pass without publishing”.
  3. Topic coverage: add fixtures for semantic versioning and publishing, dependency environments, consumer compatibility testing.
  4. Failure campaign: reproduce each named risk: “A library commits assumptions from its local lockfile”; “A dependency is forced into prod for development tooling”; “Version constraints reject compatible consumer upgrades”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute package-structure-and-licensing-positive, semantic-versioning-and-publishing-positive, dependency-environments-positive, consumer-compatibility-testing-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute package-structure-and-licensing-negative, semantic-versioning-and-publishing-negative, dependency-environments-negative, consumer-compatibility-testing-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute a-library-commits-assumptions-from-its-local-lockfile-counterexample, a-dependency-is-forced-into-prod-for-development-tooling-counterexample, version-constraints-reject-compatible-consumer-upgrades-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix package.verify through the real Mix, Hex, ExDoc, CI matrix boundary from a clean shell.
  • Mutation check: violate “Hex build and docs checks pass without publishing” and prove the suite reports fixture package-structure-and-licensing-positive as failed.
  • Regression corpus: retain the risks “A library commits assumptions from its local lockfile”; “A dependency is forced into prod for development tooling”; “Version constraints reject compatible consumer upgrades” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “A library commits assumptions from its local lockfile”

  • Why: This breaks one or more observable capabilities at the Mix, Hex, ExDoc, CI matrix boundary while allowing the happy path to look correct.
  • Fix: Run a-library-commits-assumptions-from-its-local-lockfile-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix package.verify

Problem 2: “A dependency is forced into prod for development tooling”

  • Why: This breaks one or more observable capabilities at the Mix, Hex, ExDoc, CI matrix boundary while allowing the happy path to look correct.
  • Fix: Run a-dependency-is-forced-into-prod-for-development-tooling-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix package.verify

Problem 3: “Version constraints reject compatible consumer upgrades”

  • Why: This breaks one or more observable capabilities at the Mix, Hex, ExDoc, CI matrix boundary while allowing the happy path to look correct.
  • Fix: Run version-constraints-reject-compatible-consumer-upgrades-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix package.verify

Definition of Done

  • Hex build and docs checks pass without publishing.
  • Locked and latest-dependency lanes both pass.
  • Optional dependencies are absent in the minimal lane.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 71: Contract-Aware Phoenix Event Hub

Sources: PUB-P3, PUB-P4. Deliver versioned tenant event envelopes through Phoenix.PubSub.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: Level 2: Micro-SaaS / Pro Tool
  • Curriculum Difficulty: Level 2: Intermediate
  • Knowledge Area: Framework Pub/Sub, supervision, API design
  • Software or Tool: Phoenix.PubSub 2.2, ExUnit
  • Main Book: “Real-Time Phoenix” by Stephen Bussey

What you will build: Deliver versioned tenant event envelopes through Phoenix.PubSub.

Why it teaches the BEAM ecosystem: It makes you prove that unsupported versions and forged routes fail closed while valid delivery remains explicitly transient.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Integrated Scope

This is one consolidated project, not separate source builds. Implement the following contributions as phases of the same artifact:

  • Define the PUB-P3 versioned domain-event envelope and tenant/topic contract.
  • Deliver that contract through the PUB-P4 Phoenix.PubSub hub with explicit transient-delivery semantics.

Real World Outcome

Build target: Deliver versioned tenant event envelopes through Phoenix.PubSub.

Build a supervised Demo.PubSub instance and a NotificationHub wrapper carrying the versioned order/alert envelope defined in this project’s first phase. Three terminal clients demonstrate:

  • An operator process that publishes and is also subscribed.
  • A UI subscriber receiving tenant alert events.
  • A node-local cache observer receiving local invalidation events.

The scenario sends one ordinary cluster broadcast, one sender-excluding cluster broadcast, and one local-only cache notification. It then restarts the UI process and proves the replacement receives future events but not the event broadcast while it was absent.

The project also includes explicit pool and Registry configuration, idempotent subscription semantics, wrapper Telemetry, API contract tests, and a two-stage pool-size migration runbook with a mixed-release configuration matrix.

$ mix pubsub.demo
pubsub=Demo.PubSub adapter=PG2 pool_size=2 registry_size=4 status=ready
subscribe pid=<0.210.0> topic=tenant:42:alerts result=new
subscribe pid=<0.211.0> topic=tenant:42:alerts result=new
subscribe pid=<0.210.0> topic=tenant:42:alerts result=already_subscribed
broadcast event=evt-31 scope=cluster include_sender=true route_us=38 result=ok
handled pid=<0.210.0> event=evt-31 age_us=74
handled pid=<0.211.0> event=evt-31 age_us=81
broadcast_from event=evt-32 sender=<0.210.0> sender_echo=excluded result=ok
handled pid=<0.211.0> event=evt-32 copies=1
local_broadcast event=cache-9 scope=node_local recipients_observed=1
stop subscriber old=<0.211.0>
broadcast event=evt-33 while_subscriber_absent result=ok
restart subscriber old=<0.211.0> new=<0.225.0> subscribe=result_new
replay event=evt-33 available=false
broadcast event=evt-34 handled_by=<0.225.0>

Run the demo and observe each API decision as a distinct line. The first broadcast reaches the subscribed operator and UI. The sender-excluding publication reaches the UI once while the operator receives zero echo. The cache event is explicitly labeled node_local and reaches only the local cache fixture.

After the UI subscriber exits, an event is broadcast successfully while it is absent. The replacement PID subscribes and receives the next event, but the report shows replay available=false for the missed one. The final diagnostic separates PubSub routing result from explicit handler receipts.

The accompanying migration report shows three configuration stages. A validation task rejects a simulated mixed cluster whose PG2 pool sizes cannot interoperate safely and accepts the documented transition using broadcast_pool_size.

The Core Question You Are Answering

“Which parts of a production Pub/Sub system does Phoenix.PubSub provide, and which contracts still belong to my application?”

List the concerns before implementation. Place local membership, adapter exchange, and fanout under Phoenix.PubSub. Place authorization, topic derivation, event schema, revision policy, backpressure strategy, durability, and business acknowledgement under application or other infrastructure.

Concepts You Must Understand First

  1. Local Registry fanout
    • Which mailbox and Registry ideas from consolidated Project 47 remain underneath?
    • Why does subscribe belong to the calling PID?
    • Reference: Phoenix.PubSub and Elixir Registry docs.
  2. Adapter boundary
    • Which work crosses nodes?
    • Which discovery/network concerns are outside PubSub?
    • Reference: Phoenix.PubSub.Adapter and PG2 docs.
  3. Echo semantics
    • Has the publisher already applied the change locally?
    • Which supplied PID is excluded?
    • Book: “Real-Time Phoenix,” PubSub and Channels.
  4. Ephemeral lifecycle
    • What does a restarted subscriber miss?
    • How does it recover current state?
    • Book: “Enterprise Integration Patterns,” Durable Subscriber contrast.
  5. Pool compatibility
    • Why must cluster broadcast partitions be compatible?
    • What does broadcast_pool_size do during migration?
    • Reference: official Phoenix.PubSub safe pool migration.
  6. Routing versus handling
    • What exactly does an ok result prove?
    • Which protocol would produce business acknowledgement?

Questions to Guide Your Design

  1. Which application module owns all PubSub calls?
  2. Which functions accept domain IDs rather than topics?
  3. When is sender inclusion required?
  4. When is local-only delivery a correctness property?
  5. How does each subscriber resubscribe after restart?
  6. How does the wrapper detect repeated logical subscription?
  7. Which labels are safe for Telemetry metrics?
  8. How are raising and non-raising broadcast variants handled?
  9. Who owns the pool-size configuration and runbook?
  10. How will mixed-release compatibility be validated before deployment?

Thinking Exercise

For each event, choose a delivery mode and explain the consequence of every wrong choice:

  • Local cache table was cleared.
  • Tenant order status changed.
  • Chat composer already inserted its own optimistic message.
  • A node-specific diagnostic sampler changed configuration.
  • A fleet-wide authorization policy changed.

Then draw a rolling deployment from pool_size one to two. Mark which shards each release can receive from and which shards it may broadcast on.

The Interview Questions They Will Ask

  1. How does Phoenix.PubSub deliver locally?
  2. What does broadcast returning ok prove?
  3. What is the difference between broadcast and broadcast_from?
  4. When should local_broadcast be used?
  5. Why is the default adapter still named PG2?
  6. How do you safely change PubSub pool size?

Hints in Layers

Hint 1: Wrap, do not scatter

Centralize topic derivation, envelope validation, mode selection, and instrumentation.

Hint 2: Subscribe the publisher in tests

You cannot prove echo inclusion or exclusion if the sender is not subscribed.

Hint 3: Restart the actual subscriber process

Use a new PID and publish once while it is absent. Do not simulate restart with local state reset.

Hint 4: Treat migration as topology

Represent every release stage explicitly and verify that send shards are understood by all receiving nodes.

Books That Will Help

Topic Book Chapter or Section
Phoenix real-time architecture “Real-Time Phoenix” PubSub and Channels
Pub/Sub contracts “Enterprise Integration Patterns” Ch. 3–4
Durable subscriber contrast “Enterprise Integration Patterns” Messaging endpoint patterns
Stability and rollout “Release It!, 2nd Edition” Stability Patterns and Operations
Distributed assumptions “Designing Data-Intensive Applications” Distributed Systems chapters

Implementation Milestones

Integrated basic-to-advanced progression

  1. Define the PUB-P3 versioned domain-event envelope and tenant/topic contract.
  2. Deliver that contract through the PUB-P4 Phoenix.PubSub hub with explicit transient-delivery semantics.

Milestone 1 — Contract and fixture: define one representative input, output, invariant, and failure case.

Milestone 2 — Core artifact: Deliver versioned tenant event envelopes through Phoenix.PubSub.

Milestone 3 — Failure behavior: add timeouts, invalid inputs, crashes, retries, or partitions appropriate to the project.

Milestone 4 — Evidence: automate the definition of done and record a reproducible result.

Phase 1: Supervised PubSub — 2 hours

  • Add Phoenix.PubSub as an explicitly configured child.
  • Start one subscriber and one publisher.
  • Record a routing observation separately from handler receipt.

Checkpoint: One cluster-class broadcast works on the local node and output labels its limits.

Phase 2: Domain Wrapper — 3–4 hours

  • Reuse the envelope and topic rules completed in this project’s first phase.
  • Add closed delivery-mode selection.
  • Instrument the wrapper.

Checkpoint: Application fixtures do not call Phoenix.PubSub directly.

Phase 3: Duplicate and Echo Semantics — 3 hours

  • Make ordinary subscription idempotent.
  • Test include-sender and exclude-sender modes.
  • Test all duplicates are removed by explicit unsubscribe behavior.

Checkpoint: Each operation’s sender copy count matches the matrix exactly.

Phase 4: Local Scope and Restart — 2–3 hours

  • Add cache observer and local modes.
  • Restart UI PID and resubscribe.
  • Publish during absence to prove no replay.

Checkpoint: Replacement receives the next event but never the missed event.

Phase 5: Pool Migration Runbook — 2–4 hours

  • Document initial, transition, and final configurations.
  • Add a compatibility validator.
  • Include reverse procedure for decreasing pool size.

Checkpoint: Unsafe single-stage mixed release is rejected; staged transition is accepted.

Phase 6: Quality Pass — 1–2 hours

  • Add failure-path tests and bounded metric labels.
  • Confirm exact CLI transcript.
  • Verify official 2.2 API references.

Checkpoint: The full suite and documentation distinguish infrastructure guarantees from domain guarantees.

Testing Strategy

6.1 Test Categories

Category Purpose Examples
Subscription Validate PID/topic lifecycle Subscribe once, duplicate attempt, unsubscribe
Delivery mode Validate scope and echo Four-operation matrix
Contract Validate wrapper boundary Unauthorized ID and malformed envelope
Lifecycle Validate restart and no replay Publish during subscriber absence
Instrumentation Validate routing observations Bounded labels and result
Configuration Validate explicit pool/Registry values Startup report
Migration Validate mixed-release compatibility Initial, transition, final stages

6.2 Critical Test Cases

  1. Two subscriber PIDs receive one cluster broadcast.
  2. Subscribed publisher receives ordinary broadcast.
  3. Supplied sender receives zero copies from broadcast_from; peer receives one.
  4. local_broadcast reaches local subscriber and is marked node-local.
  5. local_broadcast_from excludes the supplied local sender.
  6. Repeated wrapper subscribe produces one copy.
  7. Raw duplicate behavior is demonstrated in an isolated educational test and hidden from application API.
  8. Unsubscribe removes the current PID’s topic subscriptions.
  9. Dead subscriber membership disappears.
  10. Replacement PID resubscribes and receives future events.
  11. Replacement does not receive event broadcast while absent.
  12. Routing ok and handler receipt are different evidence records.
  13. Unauthorized topic derivation yields no PubSub call.
  14. Unsafe pool-size rollout stage fails validation.
  15. Two-stage pool-size migration passes validation.

6.3 Test Data

topic:
  tenant:42:alerts

subscribers:
  operator: <0.210.0>, subscribed
  ui:       <0.211.0>, subscribed
  cache:    <0.212.0>, local cache topic

events:
  evt-31: cluster include sender
  evt-32: cluster exclude operator
  cache-9: node-local include sender
  evt-33: broadcast while UI absent
  evt-34: broadcast after replacement subscribes

expected copies:
  evt-31 operator=1 ui=1
  evt-32 operator=0 ui=1
  cache-9 cache=1 remote_fixture=0
  evt-33 replacement_ui=0
  evt-34 replacement_ui=1

6.4 Migration Matrix

stage 0:
  every node pool_size=1
  every node broadcast_pool_size=1

stage 1:
  every upgraded node pool_size=2
  every upgraded node broadcast_pool_size=1
  old nodes remain pool_size=1 during rollout
  outbound broadcasts stay in old compatible range

stage 2:
  only after every node can receive pool_size=2
  remove broadcast_pool_size override
  outbound broadcasts use pool_size=2

Test the configuration model separately from message delivery tests so a runbook regression fails with a precise explanation.

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Pitfall Symptom Solution
Duplicate subscribe One PID receives two copies Make wrapper subscribe idempotent
Ordinary broadcast after optimistic update Publisher applies update twice Use sender-excluding mode deliberately
local_broadcast used for shared cache Other nodes stay stale Use cluster scope when correctness requires
Routing ok called delivered Lost work after process crash surprises team Track handler evidence separately
Subscriber restarts without subscribe New PID receives nothing Subscribe during process initialization
Replay assumed UI remains stale after downtime Reload authoritative state
Pool size changed in one rolling step Mixed nodes miss shard traffic Use broadcast_pool_size transition
Per-node CPU-derived pool Heterogeneous nodes disagree Configure cluster-wide value
Raw tenant topic accepted Forged cross-tenant route Authorize and derive internally
Raw IDs in metrics Cardinality explosion Use operation and topic-family labels

7.2 Debugging Strategies

  • Inspect the subscriber PID’s mailbox and confirm the exact event copy count.
  • Log operation class, scope, sender policy, and event ID at the wrapper.
  • Check whether a restarted process actually called subscribe.
  • Reproduce duplicate delivery by counting raw subscribe calls for the same PID/topic.
  • Compare PubSub config across every node before investigating random cluster misses.
  • During migration, print both pool_size and broadcast_pool_size for every release.
  • Reduce cluster-class behavior to one node to isolate domain wrapper bugs from distribution bugs.

7.3 Performance Traps

Custom dispatchers can perform specialized local delivery, but expensive dispatch logic remains on a critical path. Large event terms cost copying and cross-node serialization. More shards and Registry partitions add overhead as well as concurrency. Measure representative subscriber counts, broadcast rates, and churn; do not maximize knobs by default. Keep validation and Telemetry bounded and move subscriber work out of dispatch.

Definition of Done

Minimum Viable Completion

  • A supervised Phoenix.PubSub instance has two subscribers.
  • Ordinary broadcast reaches both.
  • Sender-excluding broadcast omits the supplied subscribed PID.

Full Completion

  • Domain wrapper owns authorization, topics, envelopes, mode selection, and Telemetry.
  • Repeated logical subscription produces one copy.
  • Cluster, local, and both sender-excluding modes are demonstrated.
  • Subscriber restart proves no offline replay.
  • Output distinguishes routing completion from handler receipt.
  • pool_size and registry_size are explicit.
  • Safe pool-size migration has a tested initial, transition, and final runbook.

Excellence

  • A mixed-release fixture validates the migration matrix.
  • Representative profiles compare broadcast and Registry sizing independently.
  • Documentation maps every application use case to an explicit delivery mode and recovery strategy.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • Every merged source contribution is implemented as a phase of this one artifact, not as a separate project.
  • unsupported versions and forged routes fail closed while valid delivery remains explicitly transient.

Project 72: OTP Rate Limiter and Circuit Breaker

Source: BEAM-P2. Add supervised state, ETS acceleration, dependency failure thresholds, cooldown, and half-open probes.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: Level 2: Micro-SaaS / Pro Tool
  • Curriculum Difficulty: Level 2: Intermediate
  • Knowledge Area: State, Fault Tolerance
  • Software or Tool: ETS + GenServer
  • Main Book: “Erlang and OTP in Action”

What you will build: Add supervised state, ETS acceleration, dependency failure thresholds, cooldown, and half-open probes.

Why it teaches the BEAM ecosystem: It makes you prove that a failing dependency produces bounded, observable load.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Add supervised state, ETS acceleration, dependency failure thresholds, cooldown, and half-open probes.

Build one supervised dependency guard that combines token-bucket admission with a circuit breaker. ETS provides concurrent reads while one process owns state transitions, cooldown deadlines, and the single half-open probe.

$ mix dependency_guard.demo
rate_limit subject=acct_7 allowed=5 rejected=1 retry_after_ms=200
breaker dependency=payments failures=3 transition=closed_to_open
request dependency=payments result=rejected reason=circuit_open
clock_advance_ms=5000 transition=open_to_half_open probe_owner=req_9
probe result=success transition=half_open_to_closed
result=PASS concurrent_probe_count=1

The Core Question You Are Answering

“How do I make this service recover automatically without global failure?”

Concepts You Must Understand First

  • Review the concepts above and ensure you can explain them clearly.

Questions to Guide Your Design

  1. How will you partition work across processes?
  2. Where is state stored and how is it protected?
  3. What happens when a worker crashes?

Thinking Exercise

Sketch the message flow and failure paths before coding.

The Interview Questions They Will Ask

  1. “Why does this design scale better than shared-memory locks?”
  2. “How do you detect and recover from failures?”
  3. “How do you prevent mailbox buildup?”
  4. “Which measurement would tell you that OTP Rate Limiter and Circuit Breaker is approaching its operating limit?”

Hints in Layers

Hint 1: Start with one worker process and a single message type.

Hint 2: Add supervision and confirm restart behavior.

Hint 3: Add routing and concurrency only after correctness.

Hint 4: Validate output with scripted test vectors.

Books That Will Help

Topic Book Chapter
Core BEAM “Programming Erlang” Processes chapter
OTP “Designing for Scalability with Erlang/OTP” Supervision chapter

Implementation Milestones

Phase 1: Foundation (2-4 hours)

  • Build a single worker process
  • Define message shapes

Phase 2: Core Functionality (4-8 hours)

  • Add routing and state storage
  • Validate correctness on test cases

Phase 3: Polish & Edge Cases (2-4 hours)

  • Add failure injection tests
  • Document recovery behavior

Testing Strategy

6.1 Test Categories

Category Purpose Examples
Unit Tests Validate core logic message parsing
Integration Tests End-to-end flow demo scenario
Failure Tests Crash recovery kill worker

6.2 Critical Test Cases

  1. Normal path: request -> response
  2. Crash path: worker exit -> restart
  3. Overload: burst input -> bounded queue

6.3 Test Data

inputs: demo messages
expected: stable outputs

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Pitfall Symptom Solution
Missing supervisor app dies on crash add supervisor
Oversized mailbox latency spikes split processes
Unbounded state memory growth add eviction

7.2 Debugging Strategies

  • Use observer to inspect process counts and queues
  • Add structured logs on message receive

7.3 Performance Traps

  • Avoid heavy work in a single process

Definition of Done

  • Limits enforced per user and window
  • ETS table lifecycle documented
  • Circuit breaker transitions documented
  • Supervisor restarts without global failure

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • a failing dependency produces bounded, observable load.

Phase 3 - Phoenix, Ecto, Web Security, and Durable Work

Project 73: Plug-to-Phoenix Request Stack

Sources: PHX-P3, PHX-P4. Evolve a minimal Plug router into a Phoenix application.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: N/A
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: Level 3: Service & Support
  • Curriculum Difficulty: Level 3: Applied
  • Knowledge Area: Web Framework
  • Software or Tool: Phoenix Framework
  • Main Book: “Programming Phoenix 1.4” by Chris McCord

What you will build: Evolve a minimal Plug router into a Phoenix application.

Why it teaches the BEAM ecosystem: It makes you prove that every request can be traced through plugs, endpoint, router, controller, and application supervision.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Integrated Scope

This is one consolidated project, not separate source builds. Implement the following contributions as phases of the same artifact:

  • Build the PHX-P3 Plug request pipeline and trace every request-stage decision.
  • Evolve the same endpoint into PHX-P4 Phoenix routing, controllers, and application supervision.

Real World Outcome

Build target: Evolve a minimal Plug router into a Phoenix application.

$ mix phx.new blog
$ cd blog
$ mix ecto.create
$ mix phx.gen.html Content Post posts title:string body:text
$ mix ecto.migrate
$ mix phx.server

# Browser: http://localhost:4000/posts
# Full CRUD interface for blog posts!

# You understand:
# - Why files are organized this way
# - How the router dispatches to controllers
# - How Ecto persists data
# - How templates render HTML
# - How the whole request flows through the stack

The Core Question You Are Answering

“How can Plug-to-Phoenix Request Stack deliver its observable outcome while proving that every request can be traced through plugs, endpoint, router, controller, and application supervision.”

Concepts You Must Understand First

  • Phoenix project structure → maps to where things live and why
  • Contexts (Phoenix 1.3+) → maps to domain-driven design
  • Ecto basics → maps to database interactions
  • Templates (HEEx) → maps to HTML generation

Questions to Guide Your Design

  1. Which input and output contracts must remain stable across refactoring?
  2. Where should validation happen, and how will expected failures be represented?
  3. Which component owns mutable state or external effects, and what happens when it dies?
  4. What independent evidence proves this mastery condition: every request can be traced through plugs, endpoint, router, controller, and application supervision.

Thinking Exercise

Draw Plug-to-Phoenix Request Stack as an input → decision/state → effect → evidence pipeline.

Mark every failure boundary, retry boundary, and durable state transition. Then inject one failure at each boundary and predict the observable result before implementing it.

The Interview Questions They Will Ask

  1. “What is the hardest invariant in Plug-to-Phoenix Request Stack, and where is it enforced?”
  2. “Which parts should be pure transformations and which require BEAM processes?”
  3. “How does the design behave under malformed input, process failure, or retry?”
  4. “What test or runtime evidence proves: every request can be traced through plugs, endpoint, router, controller, and application supervision.”

Hints in Layers

Phoenix project structure:

blog/
├── lib/
│   ├── blog/              # Business logic (contexts)
│   │   ├── content.ex     # Content context
│   │   └── content/
│   │       └── post.ex    # Post schema
│   ├── blog_web/          # Web interface
│   │   ├── controllers/
│   │   ├── components/    # (Phoenix 1.7+) or templates/
│   │   ├── router.ex
│   │   └── endpoint.ex
│   ├── blog.ex            # Application module
│   └── blog_web.ex        # Web module macros
├── config/                # Configuration
├── priv/
│   └── repo/
│       └── migrations/    # Database migrations
└── test/                  # Tests

The request flow for GET /posts:

1. Endpoint receives HTTP request
2. Router matches "/posts" to PostController.index
3. Pipeline `:browser` applies session, flash, CSRF plugs
4. PostController.index calls Content.list_posts()
5. Context queries database via Ecto
6. Controller renders "index.html" with posts
7. Template generates HTML
8. Response sent to browser

Hint 1: Starting Point Implement the narrowest happy path for: Evolve a minimal Plug router into a Phoenix application.

Hint 2: Next Level Separate parsing, validation, and transition decisions from effects so each can be tested directly.

Hint 3: Technical Details Represent expected failures as tagged outcomes and keep state ownership explicit; write only structural pseudocode before implementation.

Hint 4: Tools and Debugging Inject one failure at a time, correlate it with bounded telemetry, and save a deterministic transcript as evidence.

Books That Will Help

  • Main Book: “Programming Phoenix 1.4” by Chris McCord

Implementation Milestones

Integrated basic-to-advanced progression

  1. Build the PHX-P3 Plug request pipeline and trace every request-stage decision.
  2. Evolve the same endpoint into PHX-P4 Phoenix routing, controllers, and application supervision.

Milestone 1 — Contract and fixture: define one representative input, output, invariant, and failure case.

Milestone 2 — Core artifact: Evolve a minimal Plug router into a Phoenix application.

Milestone 3 — Failure behavior: add timeouts, invalid inputs, crashes, retries, or partitions appropriate to the project.

Milestone 4 — Evidence: automate the definition of done and record a reproducible result.

  1. Generated app runs → You understand project structure
  2. You can trace a request through the stack → You understand the flow
  3. You modify a context function → You understand the boundary
  4. You add a new route and controller → You understand the patterns

Testing Strategy

  • Unit checks: pure parsing, validation, transition, and formatting decisions.
  • Integration checks: the real process, database, socket, notebook, or framework boundary.
  • Failure checks: malformed input plus at least one crash, timeout, duplicate, overload, or partition scenario.
  • Acceptance check: independently demonstrate that every request can be traced through plugs, endpoint, router, controller, and application supervision.
  • Avoid arbitrary sleeps; use messages, monitors, deterministic clocks, fixtures, and deadlines where applicable.

Common Pitfalls and Debugging

Problem 1: Happy-path output looks correct but failures disappear

  • Why: validation, effects, and reporting share one opaque step.
  • Fix: preserve tagged errors and source identity through every stage.
  • Quick test: inject one invalid record or failed dependency and verify an explicit result.

Problem 2: Tests merely repeat the implementation

  • Why: assertions reuse the same transformation or state assumptions.
  • Fix: check external invariants, golden fixtures, and observable failure behavior.
  • Quick test: introduce a deliberate ordering or boundary bug and confirm the test fails.

Definition of Done

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • Every merged source contribution is implemented as a phase of this one artifact, not as a separate project.
  • every request can be traced through plugs, endpoint, router, controller, and application supervision.

Project 74: Ecto Persistence Deep Dive

Source: PHX-P5. Model schemas, changesets, queries, associations, migrations, constraints, and transactions.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: N/A
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: Level 3: Service & Support
  • Curriculum Difficulty: Level 3: Applied
  • Knowledge Area: Database / Functional
  • Software or Tool: Ecto, PostgreSQL
  • Main Book: “Programming Ecto” by Darin Wilson

What you will build: Model schemas, changesets, queries, associations, migrations, constraints, and transactions.

Why it teaches the BEAM ecosystem: It makes you prove that application validation and database constraints agree under concurrency.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Model schemas, changesets, queries, associations, migrations, constraints, and transactions.

A data-intensive application that uses Ecto’s advanced features: complex queries, associations, transactions, custom types, and understanding why Ecto is NOT an ORM.

Build Ecto Persistence Deep Dive as one runnable, observable artifact. Model schemas, changesets, queries, associations, migrations, constraints, and transactions.

Produce an evidence bundle containing:

  • one deterministic happy-path run;
  • one rejected or malformed input with an explicit reason;
  • one injected failure or boundary condition;
  • a final verification result proving: application validation and database constraints agree under concurrency.
artifact=ecto_persistence_deep_dive
happy_path=PASS
invalid_input=REJECTED explicit_reason=true
failure_boundary=EXERCISED recovery_evidence=true
mastery_check=PASS

The Core Question You Are Answering

“How can Ecto Persistence Deep Dive deliver its observable outcome while proving that application validation and database constraints agree under concurrency.”

Concepts You Must Understand First

  • Changesets → maps to validating and casting data
  • Composable queries → maps to building queries piece by piece
  • Associations → maps to has_many, belongs_to, many_to_many
  • Transactions → maps to multi-step database operations

Questions to Guide Your Design

  1. Which input and output contracts must remain stable across refactoring?
  2. Where should validation happen, and how will expected failures be represented?
  3. Which component owns mutable state or external effects, and what happens when it dies?
  4. What independent evidence proves this mastery condition: application validation and database constraints agree under concurrency.

Thinking Exercise

Draw Ecto Persistence Deep Dive as an input → decision/state → effect → evidence pipeline.

Mark every failure boundary, retry boundary, and durable state transition. Then inject one failure at each boundary and predict the observable result before implementing it.

The Interview Questions They Will Ask

  1. “What is the hardest invariant in Ecto Persistence Deep Dive, and where is it enforced?”
  2. “Which parts should be pure transformations and which require BEAM processes?”
  3. “How does the design behave under malformed input, process failure, or retry?”
  4. “What test or runtime evidence proves: application validation and database constraints agree under concurrency.”

Hints in Layers

Ecto is NOT an ORM - key differences:

ActiveRecord (ORM)                    Ecto (Functional Toolkit)
──────────────────                    ──────────────────────────

user.save                             Repo.insert(changeset)
  ↓                                     ↓
Object tracks its own                 Changeset is passed
dirty state                           explicitly to Repo

user.posts.build(...)                 build_assoc(user, :posts, ...)
  ↓                                     ↓
Implicit association                  Explicit function call
magic

User.find(1)                          Repo.get(User, 1)
  ↓                                     ↓
Model has class methods               Repo handles all queries

user.posts                            Repo.preload(user, :posts)
  ↓                                     ↓
Lazy loading (N+1 trap)               Explicit preloading

Hint 1: Starting Point Implement the narrowest happy path for: Model schemas, changesets, queries, associations, migrations, constraints, and transactions.

Hint 2: Next Level Separate parsing, validation, and transition decisions from effects so each can be tested directly.

Hint 3: Technical Details Represent expected failures as tagged outcomes and keep state ownership explicit; write only structural pseudocode before implementation.

Hint 4: Tools and Debugging Inject one failure at a time, correlate it with bounded telemetry, and save a deterministic transcript as evidence.

Books That Will Help

  • Main Book: “Programming Ecto” by Darin Wilson

Implementation Milestones

  1. You write composable queries → You understand Ecto.Query
  2. Changeset validates and transforms → You understand the pattern
  3. Associations load explicitly → You understand preloading
  4. Transaction handles failures → You understand Multi and rollbacks

Testing Strategy

  • Unit checks: pure parsing, validation, transition, and formatting decisions.
  • Integration checks: the real process, database, socket, notebook, or framework boundary.
  • Failure checks: malformed input plus at least one crash, timeout, duplicate, overload, or partition scenario.
  • Acceptance check: independently demonstrate that application validation and database constraints agree under concurrency.
  • Avoid arbitrary sleeps; use messages, monitors, deterministic clocks, fixtures, and deadlines where applicable.

Common Pitfalls and Debugging

Problem 1: Happy-path output looks correct but failures disappear

  • Why: validation, effects, and reporting share one opaque step.
  • Fix: preserve tagged errors and source identity through every stage.
  • Quick test: inject one invalid record or failed dependency and verify an explicit result.

Problem 2: Tests merely repeat the implementation

  • Why: assertions reuse the same transformation or state assumptions.
  • Fix: check external invariants, golden fixtures, and observable failure behavior.
  • Quick test: introduce a deliberate ordering or boundary bug and confirm the test fails.

Definition of Done

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • application validation and database constraints agree under concurrency.

Project 75: Multi-Provider Webhook Authenticity Gateway

Source: BEAM-P21. Preserve raw bodies, verify signatures, prevent replay, and record rejection evidence.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: Level 3: Service & Support
  • Curriculum Difficulty: Level 3: Applied
  • Knowledge Area: HTTP Security, API Integration
  • Software or Tool: Plug, Plug.Crypto, :crypto
  • Main Book: “Serious Cryptography”

What you will build: Preserve raw bodies, verify signatures, prevent replay, and record rejection evidence.

Why it teaches the BEAM ecosystem: It makes you prove that tampered, stale, duplicate, or wrong-tenant requests never reach handlers.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Preserve raw bodies, verify signatures, prevent replay, and record rejection evidence.

Build a small HTTP gateway with three simulated provider routes. Each adapter verifies a distinct signing format and emits one normalized event envelope. The service offers an audit query command for accepted and rejected deliveries and a downstream test sink that receives only authenticated events.

$ gatewayctl verify-fixture stripe_like valid-payment.json
request=req_01JY provider=stripe_like delivery=evt_1042
authentic=true fresh=true duplicate=false key=key_2026_q3
normalized_type=payment.settled forwarded=true

$ gatewayctl verify-fixture github_like replayed-push.json
request=req_01JZ provider=github_like delivery=del_778
authentic=true fresh=true duplicate=true
decision=rejected reason=duplicate_delivery forwarded=false

3.7.1 How to Run (Copy/Paste)

$ mix deps.get
$ mix test
$ mix run priv/demo_gateway.exs
$ gatewayctl audit --last 5

3.7.2 Golden Path Demo (Deterministic)

The fixture runner calculates provider signatures from fixed secrets and timestamps anchored to a fake clock. One event is accepted once, its normalized envelope reaches the test sink, and an immediate repeat is rejected as a duplicate.

3.7.3 Exact terminal transcript

$ mix run priv/demo_gateway.exs
gateway listening=127.0.0.1:4101 max_body=1048576 replay_window=300s
POST /hooks/acme status=202 request=req_demo_1 decision=accepted
POST /hooks/acme status=409 request=req_demo_2 decision=duplicate_delivery
POST /hooks/acme status=401 request=req_demo_3 decision=signature_mismatch
sink accepted=1 rejected=2 leaked_secrets=0
DEMO PASS

The Core Question You Are Answering

“How can an Elixir HTTP boundary prove that a webhook is authentic, fresh, and unique before any business handler trusts it?”

Concepts You Must Understand First

  1. Raw-body lifecycle — Programming Phoenix 1.4, Chapter 10, “Plug”.
  2. Pattern matching and withElixir in Action, 3rd Edition, Chapters 3–4.
  3. MACs and timing-safe verification — Serious Cryptography, 2nd Edition, Chapter 7, “Keyed Hashing”.
  4. Behaviours — Designing for Scalability with Erlang/OTP, Chapter 2, OTP design principles.

Questions to Guide Your Design

  1. Which bytes are authenticated, and where could they be changed or consumed?
  2. Which rules belong to the gateway versus a provider adapter?
  3. What claim operation remains correct under two simultaneous requests?
  4. Which audit fields help incident response without increasing data exposure?

Thinking Exercise

Trace an authentic event through these failures: key rotation overlap, replay-store timeout, invalid JSON, and sink outage. Decide the HTTP response, audit reason, retry behavior, and whether the delivery ID remains claimed in each case.

The Interview Questions They Will Ask

  1. Why is decoded JSON unsuitable for webhook signature verification?
  2. What does constant-time comparison protect, and what preconditions does it require?
  3. How would you rotate webhook secrets without downtime?
  4. How do you prevent concurrent replays?
  5. Why might an authentic event still be rejected?
  6. What should be included in a safe audit record?

Hints in Layers

Hint 1: Establish the boundary — Write a body-reader test that proves chunks reassemble into the original fixture bytes.

Hint 2: One provider end-to-end — Implement one signing grammar and a fake signer before adding the behaviour.

Hint 3: Normalize decisions, not algorithms — Provider callbacks should return the same accepted/rejected shape while retaining different header rules.

Hint 4: Race the claim — Release many concurrent tasks with one delivery ID and assert exactly one success.

Books That Will Help

Topic Book Chapter
Plug boundaries Programming Phoenix 1.4 Ch. 10, Plug
Elixir control flow Elixir in Action, 3rd Edition Ch. 3–4
Message authentication Serious Cryptography, 2nd Edition Ch. 7
Operational failure Release It!, 2nd Edition Ch. 4, Stability Patterns

Implementation Milestones

Phase 1: Byte and Crypto Contract (3-4 hours)

  • Build raw-body fixtures and one verifier.
  • Establish stable error atoms and redacted evidence.

Phase 2: Provider Adapters and Replay State (5-8 hours)

  • Extract the behaviour and add two distinct signing grammars.
  • Add fake-clock freshness and atomic claims.

Phase 3: Gateway Operations (4-6 hours)

  • Add normalization, audit queries, telemetry, load limits, and deterministic demo.

Testing Strategy

6.1 Test Categories

Category Purpose Examples
Contract Every adapter obeys common result semantics valid, malformed, mismatched
Cryptographic fixture Match provider signing grammar fixed official-style vectors
Concurrency Prove atomic replay claims 50 simultaneous duplicates
Boundary Bound body and header work chunking, oversized body, huge tag
Redaction Prevent evidence leakage capture logs and telemetry
Integration Prove accepted-only forwarding real Plug request to test sink

6.2 Critical Test Cases

  1. Raw bytes containing harmless JSON whitespace validate only against their own signature.
  2. Valid tag with stale signed timestamp is rejected.
  3. Valid tag and time arriving concurrently 50 times yields one forwarded event.
  4. Wrong-length decoded tag never reaches secure comparison.
  5. Old and new rotation keys both verify during overlap; only new verifies afterward.
  6. Authentic invalid JSON is audited as payload_invalid and never crashes the request process.
  7. Secret-store and replay-store outages fail closed with distinct retry behavior.
  8. Search captured logs for every fixture secret and full signature; find zero matches.

6.3 Test Data

Maintain per-provider valid, tampered-body, tampered-time, malformed-header, rotation, and duplicate fixtures. Use a deterministic clock and fixed non-production secrets.

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Problem: “Official signatures never match.”

  • Why: The JSON parser consumed or reconstructed the body.
  • Fix: Capture exact bounded bytes in the Plug body-reader boundary.
  • Quick test: Hash captured bytes and fixture bytes; digests must match.

Problem: “Duplicates occasionally forward twice.”

  • Why: Deduplication uses separate lookup and insert operations.
  • Fix: Use one atomic unique claim.
  • Quick test: Start 50 requests behind a barrier and count sink events.

Problem: “Logs expose secrets during errors.”

  • Why: Context or request headers are inspected wholesale.
  • Fix: Construct allow-listed audit fields and custom inspected representations.
  • Quick test: Scan captured output for all fixture credentials.

7.2 Debugging Strategies

  • Log the signed-material digest and length, never the secret or complete signature.
  • Compare fake-signer and verifier grammars byte-by-byte in a local fixture tool.
  • Attach low-cardinality telemetry to decision category, provider, and latency.
  • Inspect body-reader chunk counts when only large requests fail.

7.3 Performance Traps

  • Trying an unbounded historical key set for every request.
  • Parsing large JSON before authentication.
  • Synchronously storing full payloads in the request path.
  • High-cardinality telemetry keyed by delivery ID.

Definition of Done

  • Three materially different provider signing grammars pass a shared contract suite.
  • Exact request bytes are authenticated before payload decoding.
  • Timestamp and atomic delivery-ID replay defenses are independently tested.
  • Oversized bodies and malformed signatures are bounded and rejected.
  • Key rotation overlap is observable by opaque key ID.
  • Only accepted events reach the downstream sink.
  • Audit records contain stable reasons and no fixture secret or full signature.
  • Deterministic CLI demo ends with DEMO PASS.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • tampered, stale, duplicate, or wrong-tenant requests never reach handlers.

Project 76: Transactional Inventory Ledger and Reservation API

Source: BEAM-P22. Build an Ecto stock ledger with reservations, expiration, and no-oversell constraints.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: Level 3: Service & Support
  • Curriculum Difficulty: Level 3: Applied
  • Knowledge Area: Relational Integrity, Concurrency
  • Software or Tool: Ecto, PostgreSQL, Ecto.Multi
  • Main Book: “Designing Data-Intensive Applications”

What you will build: Build an Ecto stock ledger with reservations, expiration, and no-oversell constraints.

Why it teaches the BEAM ecosystem: It makes you prove that concurrent races preserve stock and audit history.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Build an Ecto stock ledger with reservations, expiration, and no-oversell constraints.

Build a JSON API and operator CLI supporting receipt, reserve, release, commit, reservation lookup, stock summary, ledger history, and reconciliation. Seed one contested SKU and demonstrate concurrent requests without overselling.

$ inventoryctl receive SKU-RED-42 10 --key receipt-001
movement=mov_1 on_hand=10 reserved=0 available=10

$ inventoryctl reserve SKU-RED-42 7 --order ORD-9 --key reserve-009
reservation=res_9 status=active available=3

$ inventoryctl reserve SKU-RED-42 4 --order ORD-10 --key reserve-010
error=insufficient_availability requested=4 observed_available=3

3.7.1 How to Run (Copy/Paste)

$ mix ecto.create
$ mix ecto.migrate
$ mix test
$ mix run priv/demo_inventory.exs

3.7.2 Golden Path Demo (Deterministic)

The demo receives 25 units, releases 20 concurrent reservations of two units through a barrier, and proves exactly 12 succeed. The projection ends at 24 reserved and one available, while ledger reconciliation reports zero drift.

3.7.3 Exact terminal transcript

$ mix run priv/demo_inventory.exs
seed sku=DEMO-1 on_hand=25 reserved=0
race attempts=20 quantity_each=2
result accepted=12 rejected=8 accepted_quantity=24
projection on_hand=25 reserved=24 available=1
ledger expected_on_hand=25 expected_reserved=24 drift=0
idempotency_duplicates=0 negative_rows=0
DEMO PASS

The Core Question You Are Answering

“Where must an inventory invariant live so it survives concurrent requests, process crashes, and uncertain client retries?”

Concepts You Must Understand First

  1. Changesets and constraints — Programming Ecto, Chapters 3–5.
  2. Transactions and Ecto.MultiProgramming Ecto, Chapter 6.
  3. Isolation and consistency — Designing Data-Intensive Applications, 2nd Edition, transactions chapter.
  4. Idempotency and integration — Enterprise Integration Patterns, “Idempotent Receiver”.

Questions to Guide Your Design

  1. What exact quantities must never become negative?
  2. What operation makes the availability decision atomic?
  3. Which unique keys encode one business effect?
  4. How can projection drift be detected and repaired?
  5. Which errors are domain conflicts versus temporary infrastructure failures?

Thinking Exercise

Draw a timeline for a commit, expiry release, and client retry arriving together for one reservation. Identify the lock or predicate, unique constraints, successful terminal state, and expected API result for each loser.

The Interview Questions They Will Ask

  1. Why is changeset validation insufficient to prevent overselling?
  2. Compare pessimistic locking, conditional updates, and optimistic locking.
  3. How does Ecto.Multi report failure, and what is rolled back?
  4. How do idempotency keys differ from reservation IDs?
  5. Why keep both a ledger and a projection?
  6. How would you test a concurrency invariant reliably?

Hints in Layers

Hint 1: Start with algebra — Write transition tables for each movement before creating schemas.

Hint 2: Protect one SKU — Implement one transaction and prove it with a two-caller race.

Hint 3: Add durable identity — Put idempotency and terminal-transition uniqueness in constraints.

Hint 4: Recompute truth — Fold the ledger into expected projection values and compare.

Books That Will Help

Topic Book Chapter
Ecto modeling Programming Ecto Ch. 3–6
Transactions Designing Data-Intensive Applications, 2nd Edition Transactions chapter
Idempotency Enterprise Integration Patterns Idempotent Receiver
Stability Release It!, 2nd Edition Ch. 4

Implementation Milestones

Phase 1: Ledger and Projection (5-7 hours)

  • Define transition algebra, schemas, migrations, constraints, and reconciliation.

Phase 2: Atomic Reservation Lifecycle (7-11 hours)

  • Build named transactions, contention strategy, error mapping, and idempotency.

Phase 3: API and Evidence (6-10 hours)

  • Add endpoints, outbox, concurrent tests, query-plan review, and demo report.

Testing Strategy

6.1 Test Categories

Category Purpose Examples
Transition unit Prove movement algebra receive/reserve/release/commit
Constraint Prove database backstops duplicate key, negative quantity
Transaction Prove all-or-nothing writes injected failure before projection
Concurrency Prove contention invariant barrier-released reservation race
Idempotency Prove stable retry result same and conflicting payload
Reconciliation Detect projection drift intentional corruption

6.2 Critical Test Cases

  1. One hundred requests contend for less stock; accepted total never exceeds on-hand.
  2. Same idempotency key sent concurrently creates one movement and one outcome.
  3. Same key with a different payload returns conflict.
  4. Commit and expiry race produces one terminal movement.
  5. Injected failure after movement insertion rolls back ledger, projection, and outbox.
  6. Deadlock or optimistic conflict follows the documented retry policy.
  7. Reconciliation detects and describes an intentionally corrupted projection.
  8. Every database constraint maps to a stable domain/API error.

6.3 Test Data

Use SKUs with zero, one, and high stock; reservations at exact boundary; repeated command keys; expired reservations; and randomized sequences whose ledger fold must equal the projection.

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Problem: “Rare load tests oversell.”

  • Why: Availability is checked outside the transaction or without a serialization point.
  • Fix: Put comparison and update behind a row lock, conditional write, or version check.
  • Quick test: Barrier-release many requests against one SKU.

Problem: “A retry duplicates a movement.”

  • Why: Idempotency uses an application lookup without a unique constraint.
  • Fix: Claim the key transactionally and persist its input digest/outcome.
  • Quick test: Submit the same key concurrently from two connections.

Problem: “Ledger and balance disagree.”

  • Why: Writes happen in different transactions or an operator mutates the projection directly.
  • Fix: Compose both writes in one Multi and restrict mutation paths.
  • Quick test: Run reconciliation after every fault-injection point.

7.2 Debugging Strategies

  • Include failed Ecto.Multi operation names in structured internal logs.
  • Inspect database locks and slow transaction duration under contention.
  • Query all rows by command ID to detect partial or duplicate effects.
  • Recompute one SKU from its movement history before blaming cached availability.

7.3 Performance Traps

  • Holding locks while calling HTTP or message brokers.
  • Missing indexes on idempotency scope, SKU, or active reservation expiry.
  • Recalculating all ledger history on every command.
  • Retrying deadlocks without a limit or jitter.

Definition of Done

  • Receipt, reserve, release, and commit produce immutable movements.
  • Ledger and projection update atomically.
  • Database constraints prevent negative quantities and duplicate effects.
  • Concurrent contention test proves no overselling.
  • Retry with the same idempotency key returns one stable outcome.
  • Commit/expiry races yield one valid terminal transition.
  • Reconciliation detects zero drift after normal workloads and finds injected drift.
  • Deterministic demo produces the documented transcript.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • concurrent races preserve stock and audit history.

Project 77: Authentication from Scratch

Source: PHX-P8. Implement password storage, sessions, confirmation, reset, and authorization boundaries.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: N/A
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: Level 3: Service & Support
  • Curriculum Difficulty: Level 3: Applied
  • Knowledge Area: Security / Web
  • Software or Tool: Phoenix, Argon2, JWT (optional)
  • Main Book: “Programming Phoenix 1.4” by Chris McCord

What you will build: Implement password storage, sessions, confirmation, reset, and authorization boundaries.

Why it teaches the BEAM ecosystem: It makes you prove that fixation, replay, escalation, and enumeration scenarios have tests.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Implement password storage, sessions, confirmation, reset, and authorization boundaries.

A complete authentication system with registration, login, logout, password hashing, session management, and protected routes. You’ll understand both how phx.gen.auth works and build the key pieces manually.

Build Authentication from Scratch as one runnable, observable artifact. Implement password storage, sessions, confirmation, reset, and authorization boundaries.

Produce an evidence bundle containing:

  • one deterministic happy-path run;
  • one rejected or malformed input with an explicit reason;
  • one injected failure or boundary condition;
  • a final verification result proving: fixation, replay, escalation, and enumeration scenarios have tests.
artifact=authentication_from_scratch
happy_path=PASS
invalid_input=REJECTED explicit_reason=true
failure_boundary=EXERCISED recovery_evidence=true
mastery_check=PASS

The Core Question You Are Answering

“How can Authentication from Scratch deliver its observable outcome while proving that fixation, replay, escalation, and enumeration scenarios have tests.”

Concepts You Must Understand First

  • Password hashing → maps to bcrypt/argon2, never store plaintext
  • Session management → maps to cookies, tokens, security
  • Auth plugs → maps to protecting routes
  • LiveView auth → maps to socket assigns, on_mount

Questions to Guide Your Design

  1. Which input and output contracts must remain stable across refactoring?
  2. Where should validation happen, and how will expected failures be represented?
  3. Which component owns mutable state or external effects, and what happens when it dies?
  4. What independent evidence proves this mastery condition: fixation, replay, escalation, and enumeration scenarios have tests.

Thinking Exercise

Draw Authentication from Scratch as an input → decision/state → effect → evidence pipeline.

Mark every failure boundary, retry boundary, and durable state transition. Then inject one failure at each boundary and predict the observable result before implementing it.

The Interview Questions They Will Ask

  1. “What is the hardest invariant in Authentication from Scratch, and where is it enforced?”
  2. “Which parts should be pure transformations and which require BEAM processes?”
  3. “How does the design behave under malformed input, process failure, or retry?”
  4. “What test or runtime evidence proves: fixation, replay, escalation, and enumeration scenarios have tests.”

Hints in Layers

Auth plug for protecting routes: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Password hashing with Argon2: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Hint 1: Starting Point Implement the narrowest happy path for: Implement password storage, sessions, confirmation, reset, and authorization boundaries.

Hint 2: Next Level Separate parsing, validation, and transition decisions from effects so each can be tested directly.

Hint 3: Technical Details Represent expected failures as tagged outcomes and keep state ownership explicit; write only structural pseudocode before implementation.

Hint 4: Tools and Debugging Inject one failure at a time, correlate it with bounded telemetry, and save a deterministic transcript as evidence.

Books That Will Help

  • Main Book: “Programming Phoenix 1.4” by Chris McCord

Implementation Milestones

  1. Passwords are hashed correctly → You understand security basics
  2. Sessions persist across requests → You understand session management
  3. Protected routes redirect → You understand auth plugs
  4. LiveView pages are protected → You understand on_mount hooks

Testing Strategy

  • Unit checks: pure parsing, validation, transition, and formatting decisions.
  • Integration checks: the real process, database, socket, notebook, or framework boundary.
  • Failure checks: malformed input plus at least one crash, timeout, duplicate, overload, or partition scenario.
  • Acceptance check: independently demonstrate that fixation, replay, escalation, and enumeration scenarios have tests.
  • Avoid arbitrary sleeps; use messages, monitors, deterministic clocks, fixtures, and deadlines where applicable.

Common Pitfalls and Debugging

Problem 1: Happy-path output looks correct but failures disappear

  • Why: validation, effects, and reporting share one opaque step.
  • Fix: preserve tagged errors and source identity through every stage.
  • Quick test: inject one invalid record or failed dependency and verify an explicit result.

Problem 2: Tests merely repeat the implementation

  • Why: assertions reuse the same transformation or state assumptions.
  • Fix: check external invariants, golden fixtures, and observable failure behavior.
  • Quick test: introduce a deliberate ordering or boundary bug and confirm the test fails.

Definition of Done

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • fixation, replay, escalation, and enumeration scenarios have tests.

Project 78: Phoenix REST and GraphQL API

Source: PHX-P9. Expose one domain through versioned JSON and GraphQL interfaces.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: N/A
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: Level 3: Service & Support
  • Curriculum Difficulty: Level 3: Applied
  • Knowledge Area: API Design
  • Software or Tool: Phoenix, Absinthe (for GraphQL), or JSON:API
  • Main Book: “Craft GraphQL APIs in Elixir with Absinthe” by Bruce Williams

What you will build: Expose one domain through versioned JSON and GraphQL interfaces.

Why it teaches the BEAM ecosystem: It makes you prove that both share domain rules while preserving transport contracts and query limits.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Expose one domain through versioned JSON and GraphQL interfaces.

# REST API
$ curl -H "Authorization: Bearer <token>" \
       http://localhost:4000/api/posts
{
  "data": [
    {"id": 1, "title": "Hello Phoenix", "author": "Alice"},
    {"id": 2, "title": "Elixir Rocks", "author": "Bob"}
  ],
  "meta": {"total": 42, "page": 1, "per_page": 10}
}

# GraphQL API
$ curl -X POST http://localhost:4000/graphql \
       -H "Content-Type: application/json" \
       -d '{"query": "{ posts { title author { name } } }"}'
{
  "data": {
    "posts": [
      {"title": "Hello Phoenix", "author": {"name": "Alice"}},
      {"title": "Elixir Rocks", "author": {"name": "Bob"}}
    ]
  }
}

The Core Question You Are Answering

“How can Phoenix REST and GraphQL API deliver its observable outcome while proving that both share domain rules while preserving transport contracts and query limits.”

Concepts You Must Understand First

  • API pipeline → maps to JSON rendering, no session
  • Error handling → maps to fallback controllers
  • GraphQL types → maps to Absinthe schema
  • Pagination → maps to cursor vs offset pagination

Questions to Guide Your Design

  1. Which input and output contracts must remain stable across refactoring?
  2. Where should validation happen, and how will expected failures be represented?
  3. Which component owns mutable state or external effects, and what happens when it dies?
  4. What independent evidence proves this mastery condition: both share domain rules while preserving transport contracts and query limits.

Thinking Exercise

Draw Phoenix REST and GraphQL API as an input → decision/state → effect → evidence pipeline.

Mark every failure boundary, retry boundary, and durable state transition. Then inject one failure at each boundary and predict the observable result before implementing it.

The Interview Questions They Will Ask

  1. “What is the hardest invariant in Phoenix REST and GraphQL API, and where is it enforced?”
  2. “Which parts should be pure transformations and which require BEAM processes?”
  3. “How does the design behave under malformed input, process failure, or retry?”
  4. “What test or runtime evidence proves: both share domain rules while preserving transport contracts and query limits.”

Hints in Layers

API pipeline (no session, HTML rendering): Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

FallbackController for error handling: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Hint 1: Starting Point Implement the narrowest happy path for: Expose one domain through versioned JSON and GraphQL interfaces.

Hint 2: Next Level Separate parsing, validation, and transition decisions from effects so each can be tested directly.

Hint 3: Technical Details Represent expected failures as tagged outcomes and keep state ownership explicit; write only structural pseudocode before implementation.

Hint 4: Tools and Debugging Inject one failure at a time, correlate it with bounded telemetry, and save a deterministic transcript as evidence.

Books That Will Help

  • Main Book: “Craft GraphQL APIs in Elixir with Absinthe” by Bruce Williams

Implementation Milestones

  1. API returns JSON → You understand the api pipeline
  2. Auth protects endpoints → You understand token auth
  3. Errors return proper status codes → You understand FallbackController
  4. GraphQL queries work → You understand Absinthe

Testing Strategy

  • Unit checks: pure parsing, validation, transition, and formatting decisions.
  • Integration checks: the real process, database, socket, notebook, or framework boundary.
  • Failure checks: malformed input plus at least one crash, timeout, duplicate, overload, or partition scenario.
  • Acceptance check: independently demonstrate that both share domain rules while preserving transport contracts and query limits.
  • Avoid arbitrary sleeps; use messages, monitors, deterministic clocks, fixtures, and deadlines where applicable.

Common Pitfalls and Debugging

Problem 1: Happy-path output looks correct but failures disappear

  • Why: validation, effects, and reporting share one opaque step.
  • Fix: preserve tagged errors and source identity through every stage.
  • Quick test: inject one invalid record or failed dependency and verify an explicit result.

Problem 2: Tests merely repeat the implementation

  • Why: assertions reuse the same transformation or state assumptions.
  • Fix: check external invariants, golden fixtures, and observable failure behavior.
  • Quick test: introduce a deliberate ordering or boundary bug and confirm the test fails.

Definition of Done

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • both share domain rules while preserving transport contracts and query limits.

Project 79: Phoenix Channels Chat

Source: PHX-P6. Build browser chat with sockets, topics, joins, broadcasts, Presence, and reconnects.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir + JavaScript
  • Alternative Programming Languages: N/A
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: Level 3: Service & Support
  • Curriculum Difficulty: Level 3: Applied
  • Knowledge Area: Real-Time / WebSockets
  • Software or Tool: Phoenix Channels, JavaScript client
  • Main Book: “Programming Phoenix 1.4” by Chris McCord

What you will build: Build browser chat with sockets, topics, joins, broadcasts, Presence, and reconnects.

Why it teaches the BEAM ecosystem: It makes you prove that multiple clients exchange messages while every topic boundary rechecks authorization.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Build browser chat with sockets, topics, joins, broadcasts, Presence, and reconnects.

┌─────────────────────────────────────────────────────────────────┐
│  Phoenix Chat - Room: #general                                  │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  Alice: Hey everyone!                              10:30 AM     │
│  Bob: Hi Alice! How's it going?                    10:31 AM     │
│  Charlie: Great to see you both!                   10:31 AM     │
│                                                                 │
│  ─────────────────────────────────────────────────────────────  │
│  Online: Alice, Bob, Charlie (3 users)                          │
│  ─────────────────────────────────────────────────────────────  │
│                                                                 │
│  [Type a message...]                                    [Send]  │
└─────────────────────────────────────────────────────────────────┘

# Messages appear INSTANTLY for all connected users
# User list updates in real-time as people join/leave
# Each user is a separate BEAM process on the server

The Core Question You Are Answering

“How can Phoenix Channels Chat deliver its observable outcome while proving that multiple clients exchange messages while every topic boundary rechecks authorization.”

Concepts You Must Understand First

  • Socket lifecycle → maps to connect, join, handle_in, terminate
  • Topics and rooms → maps to pub-sub patterns
  • Presence → maps to tracking who’s online
  • JavaScript client → maps to browser-side integration

Questions to Guide Your Design

  1. Which input and output contracts must remain stable across refactoring?
  2. Where should validation happen, and how will expected failures be represented?
  3. Which component owns mutable state or external effects, and what happens when it dies?
  4. What independent evidence proves this mastery condition: multiple clients exchange messages while every topic boundary rechecks authorization.

Thinking Exercise

Draw Phoenix Channels Chat as an input → decision/state → effect → evidence pipeline.

Mark every failure boundary, retry boundary, and durable state transition. Then inject one failure at each boundary and predict the observable result before implementing it.

The Interview Questions They Will Ask

  1. “What is the hardest invariant in Phoenix Channels Chat, and where is it enforced?”
  2. “Which parts should be pure transformations and which require BEAM processes?”
  3. “How does the design behave under malformed input, process failure, or retry?”
  4. “What test or runtime evidence proves: multiple clients exchange messages while every topic boundary rechecks authorization.”

Hints in Layers

Channel lifecycle:

Browser                                         Phoenix
   │                                               │
   │── WebSocket connect ─────────────────────────►│
   │                                    UserSocket.connect/3
   │◄───────────────────── :ok ────────────────────│
   │                                               │
   │── channel.join("room:lobby") ────────────────►│
   │                                    RoomChannel.join/3
   │◄───────────────────── :ok ────────────────────│
   │                                               │
   │── channel.push("new_msg", {body: "Hi"}) ─────►│
   │                                    RoomChannel.handle_in/3
   │                                    broadcast!(socket, "new_msg", ...)
   │◄─────────── broadcast to all in room ─────────│
   │                                               │

Channel module structure: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Hint 1: Starting Point Implement the narrowest happy path for: Build browser chat with sockets, topics, joins, broadcasts, Presence, and reconnects.

Hint 2: Next Level Separate parsing, validation, and transition decisions from effects so each can be tested directly.

Hint 3: Technical Details Represent expected failures as tagged outcomes and keep state ownership explicit; write only structural pseudocode before implementation.

Hint 4: Tools and Debugging Inject one failure at a time, correlate it with bounded telemetry, and save a deterministic transcript as evidence.

Books That Will Help

  • Main Book: “Programming Phoenix 1.4” by Chris McCord

Implementation Milestones

  1. WebSocket connects → You understand Socket
  2. Messages broadcast to all → You understand pub-sub
  3. Presence tracks online users → You understand Presence
  4. Multiple rooms work → You understand topics

Testing Strategy

  • Unit checks: pure parsing, validation, transition, and formatting decisions.
  • Integration checks: the real process, database, socket, notebook, or framework boundary.
  • Failure checks: malformed input plus at least one crash, timeout, duplicate, overload, or partition scenario.
  • Acceptance check: independently demonstrate that multiple clients exchange messages while every topic boundary rechecks authorization.
  • Avoid arbitrary sleeps; use messages, monitors, deterministic clocks, fixtures, and deadlines where applicable.

Common Pitfalls and Debugging

Problem 1: Happy-path output looks correct but failures disappear

  • Why: validation, effects, and reporting share one opaque step.
  • Fix: preserve tagged errors and source identity through every stage.
  • Quick test: inject one invalid record or failed dependency and verify an explicit result.

Problem 2: Tests merely repeat the implementation

  • Why: assertions reuse the same transformation or state assumptions.
  • Fix: check external invariants, golden fixtures, and observable failure behavior.
  • Quick test: introduce a deliberate ordering or boundary bug and confirm the test fails.

Definition of Done

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • multiple clients exchange messages while every topic boundary rechecks authorization.

Project 80: Correct-by-Reconnect LiveView Operations Board

Sources: BEAM-P4, PHX-P7, PUB-P5. Combine interactive LiveView, diff updates, Pub/Sub refresh, and authoritative reload.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: JavaScript/TypeScript client, Erlang backend
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: Level 3: Service & Support
  • Curriculum Difficulty: Level 3: Applied
  • Knowledge Area: LiveView lifecycle, real-time projections, reconnect recovery
  • Software or Tool: Phoenix 1.8, LiveView, Phoenix.PubSub
  • Main Book: “Programming Phoenix LiveView” by Tate & DeBenedetto

What you will build: Combine interactive LiveView, diff updates, Pub/Sub refresh, and authoritative reload.

Why it teaches the BEAM ecosystem: It makes you prove that disconnected browsers converge without treating Pub/Sub as history.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Integrated Scope

This is one consolidated project, not separate source builds. Implement the following contributions as phases of the same artifact:

  • Use PHX-P7 to establish LiveView lifecycle, validation, events, and diff rendering.
  • Apply BEAM-P4 operations-domain filtering and telemetry to the same board.
  • Finish with PUB-P5 transient refresh plus authoritative reload so reconnects converge.

Real World Outcome

Build target: Combine interactive LiveView, diff updates, Pub/Sub refresh, and authoritative reload.

Build an incident operations application with two simultaneous views:

  • Operator view: authorized controls for acknowledging, mitigating, resolving, assigning, and annotating an incident.
  • Wallboard view: read-only status cards grouped by severity and lifecycle state.
  • Diagnostics drawer: connection status, local revision, repository revision, last event age, duplicate/stale/gap counts, reconnect count, render count, and recovery reason.
  • Fault controls in development: disconnect one browser, delay its handler, inject duplicate notices, inject a stale revision, and create a revision jump.

The incident store is authoritative. Every successful mutation increments a board revision in the same database transaction as the incident change. Only after commit does the application broadcast a compact change notice.

Start the server, open /boards/operations in two browser profiles, and label one window Operator and the other Wallboard. Resolve INC-104 in the operator window. The operator button becomes disabled while the transaction commits, then both windows show RESOLVED, revision 23, and a green LIVE badge. The diagnostics drawer on the wallboard reports an event age below the target SLO.

Next, use browser developer tools to switch the wallboard network offline. Perform three more incident mutations in the operator window, producing revisions 24–26. Bring the wallboard online. It must not animate through imaginary intermediate events. It reloads revision 26, shows a temporary RECOVERED badge, and records gap 23→26; recovered_by=repository_reload.

The reference transcript should look exactly like this:

Browser A — Operator                 Browser B — Wallboard
INC-104 API latency [MITIGATING]     revision=22 age=84ms LIVE
action: resolve -> committed r23     update r23 applied without refresh

[Browser B network offline]
commits r24, r25, r26                no transient delivery
[Browser B reconnect]
mount revision=26 source=database    gap 23->26 recovered_by=reload PASS

The Core Question You Are Answering

“How does a real-time UI remain correct after it inevitably misses transient notifications?”

Before implementing, explain in writing why “subscribe and update assigns” is insufficient. Your answer must cover initial render, the read/subscribe race, duplicate subscriptions, missed events, role revocation, and render overload.

Concepts You Must Understand First

  1. Disconnected versus connected mount
    • Which phase owns a persistent process?
    • Why can subscribing in both phases duplicate delivery?
    • Reference: Phoenix LiveView lifecycle documentation.
  2. PubSub delivery semantics
    • What does broadcast acknowledge?
    • What happens while a subscriber is disconnected?
    • Reference: Phoenix.PubSub 2.2 documentation.
  3. Derived projections
    • Why is a wallboard a projection rather than a source of truth?
    • How is a projection repaired?
    • Book: “Designing Data-Intensive Applications, 2nd Edition,” derived data and stream processing chapters.
  4. Long-lived authorization
    • Which permissions can change after mount?
    • How is protected socket state removed?
  5. Render pressure
    • Which updates supersede older display states?
    • Which domain events may never be discarded from the durable record?
    • Book: “Release It!, 2nd Edition,” stability patterns.

Questions to Guide Your Design

  1. Does the notice carry only identifiers and revision, or a projection snapshot? Why?
  2. What exact rule distinguishes stale, duplicate, contiguous, and gapped events?
  3. Which query reloads one incident and which reloads the whole board?
  4. What prevents two render timers from being scheduled concurrently?
  5. What will the wallboard display during recovery instead of falsely claiming LIVE?
  6. How will a revoked operator lose topic access and cached socket data?

Thinking Exercise

Draw five columns labeled Browser, LiveView Process, Mailbox, PubSub Registry, and Database. Trace this sequence:

  1. Disconnected mount reads revision 20.
  2. Connected mount subscribes.
  3. Revision 21 commits while the connected process loads.
  4. A duplicate revision 21 arrives.
  5. The socket disconnects and misses revisions 22–24.
  6. It reconnects with a new process and loads revision 24.
  7. The user’s role is revoked before revision 25.

For every step, mark where truth exists, where a transient message can exist, and which authorization check applies.

The Interview Questions They Will Ask

  1. “Why subscribe only during connected mount?”
  2. “How do you close the read-versus-subscribe race?”
  3. “Why isn’t a PubSub event an event store?”
  4. “How do revisions repair duplicate, stale, and missing notifications?”
  5. “How would you prevent a burst from causing excessive LiveView renders?”
  6. “How do you test two clients and a reconnect deterministically?”

Hints in Layers

Hint 1 — Prove lifecycle first: Display connection state and subscription count before implementing domain updates.

Hint 2 — Broadcast less: Use an opaque identifier and committed revision. Reload the authorized projection on receipt.

Hint 3 — Make gaps explicit: Once a gap is detected, reject incremental assumptions until a repository reconciliation succeeds.

Hint 4 — Separate ingest from display: Store the latest valid projection immediately but schedule at most one render tick per cadence window.

Hint 5 — Test revocation as a state transition: Change authorization while the LiveView is connected, then force a reload-producing event.

Books That Will Help

Topic Book Focus
LiveView lifecycle “Programming Phoenix LiveView” by Tate & DeBenedetto Lifecycle and state management chapters
Phoenix real-time architecture “Real-Time Phoenix” by Stephen Bussey PubSub, Channels, and Presence chapters
Derived state “Designing Data-Intensive Applications, 2nd Edition” Derived data and stream processing
Stability “Release It!, 2nd Edition” Backpressure, timeouts, and stability patterns

Implementation Milestones

Integrated basic-to-advanced progression

  1. Use PHX-P7 to establish LiveView lifecycle, validation, events, and diff rendering.
  2. Apply BEAM-P4 operations-domain filtering and telemetry to the same board.
  3. Finish with PUB-P5 transient refresh plus authoritative reload so reconnects converge.

Milestone 1 — Contract and fixture: define one representative input, output, invariant, and failure case.

Milestone 2 — Core artifact: Combine interactive LiveView, diff updates, Pub/Sub refresh, and authoritative reload.

Milestone 3 — Failure behavior: add timeouts, invalid inputs, crashes, retries, or partitions appropriate to the project.

Milestone 4 — Evidence: automate the definition of done and record a reproducible result.

Phase 1 — Durable incident model (4–5 hours)

  • Define incident states and legal transitions.
  • Add board revision and commit it atomically with mutations.
  • Build an authorized board projection query.

Checkpoint: Repository tests prove revision monotonicity and reject unauthorized reads.

Phase 2 — Connected two-browser updates (4–5 hours)

  • Add connected-only subscription.
  • Broadcast compact notices only after successful commit.
  • Reload and render the affected projection.

Checkpoint: One committed action updates two independent sessions exactly once.

Phase 3 — Revision recovery (4–6 hours)

  • Add classification counters.
  • Implement duplicate/stale ignore and gap reload.
  • Reconcile on reconnect.

Checkpoint: Offline wallboard misses three revisions, reconnects, and renders current state without replay.

Phase 4 — Render control and diagnostics (3–5 hours)

  • Add bounded render scheduling.
  • Record event age, revision lag, render/coalescing count, and recovery reason.
  • Show live/stale/recovering badges.

Checkpoint: A 100-notice burst produces no more renders than the configured cap and ends at the latest revision.

Phase 5 — Authorization and fault tests (3–5 hours)

  • Re-check access on reload.
  • Remove protected assigns on revocation.
  • Add two-client, reconnect, burst, and role-change tests.

Checkpoint: The full Definition of Done passes without sleeps that hide races.

Testing Strategy

6.1 Test Categories

Category Purpose Examples
Domain unit Prove legal incident transitions and revisions Resolve increments once; invalid transition rejected
LiveView integration Prove connected subscription and projection reload Two clients observe revision 23
Race tests Exercise queued notice during load Notice equal to loaded revision ignored
Recovery tests Prove offline correctness Reconnect at revision 26
Load tests Prove render cap and freshness 100 notices collapse to bounded renders
Security tests Prove continuous authorization Revoked user cannot reload board

6.2 Critical Test Cases

  1. Initial disconnected render does not subscribe.
  2. Connected mount registers exactly once.
  3. Duplicate event ID and equal revision do not rerender.
  4. Lower revision never moves the UI backward.
  5. Revision jump marks the board stale before reload.
  6. Failed reload keeps RECOVERING or shows an error; it never claims LIVE.
  7. Reconnect after three commits loads the newest revision.
  8. Role revocation clears protected state and denies the next reload.
  9. A notification burst respects the render cap and ends at the latest revision.
  10. Malformed or future-schema envelopes are rejected and counted.

6.3 Deterministic Test Data

Initial board revision: 22
Incident: INC-104, state=MITIGATING, severity=SEV-1
Connected clients: operator-A, wallboard-B

Notices:
  E-230 revision=23 incident=INC-104 occurred_at=T+000ms
  E-230 revision=23 incident=INC-104 occurred_at=T+005ms  # duplicate
  E-219 revision=21 incident=INC-104 occurred_at=T-500ms  # stale
  E-260 revision=26 incident=INC-207 occurred_at=T+900ms  # gap

Expected final state:
  local_revision=26
  duplicate_count=1
  stale_count=1
  gap_count=1
  recovery_reason=repository_reload

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Pitfall Symptom Correction
Subscribe in both mount phases Each change handled twice Guard subscription by connected lifecycle
Treat event payload as truth Stale or unauthorized detail displayed Reload authorized repository projection
Ignore revision gaps Board silently diverges Mark stale and reconcile
Render per notice High CPU, large diffs, browser lag Coalesce render cadence
Trust topic secrecy Revoked user keeps data Re-authorize on load/recovery
Assert only final UI Duplicate handling remains invisible Assert diagnostics and handler counts

7.2 Debugging Strategies

  • Inspect Process.info(liveview_pid, :message_queue_len) during a burst, but do not poll it per event.
  • Log event ID, incoming revision, local revision, classification, and recovery reason as structured fields.
  • Attach Telemetry handlers that record bounded measurements and perform no blocking I/O.
  • Verify the database revision directly whenever the UI reports a gap.
  • Reproduce reconnect with browser offline mode and with server process termination; they exercise different lifecycle paths.

7.3 Performance Traps

Large snapshots amplify serialization and mailbox memory. Per-event database N+1 queries amplify latency. High-cardinality metric labels amplify observability cost. Repeated timers amplify render work. Measure committed-to-handled age and committed-to-rendered age separately so repository or rendering delay is not misdiagnosed as PubSub delay.

Definition of Done

Minimum Viable Completion

  • Two browser sessions update after one committed incident mutation.
  • Connected mount subscribes once.
  • Reconnect reloads the repository and reaches the current revision.
  • Duplicate and gap counters are visible.

Full Completion

  • All functional and non-functional requirements pass.
  • The deterministic race, reconnect, burst, and authorization tests pass.
  • Diagnostics prove the freshness and recovery SLOs.
  • The architecture document names PubSub’s transient boundary.

Excellence

  • Repeat the experiment across two clustered nodes during rolling restart.
  • Produce a before/after report for unbounded versus coalesced rendering.
  • Demonstrate trace correlation from command commit through browser handling.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • Every merged source contribution is implemented as a phase of this one artifact, not as a separate project.
  • disconnected browsers converge without treating Pub/Sub as history.

Project 81: Phoenix Test Pyramid

Source: PHX-P13. Build unit, data-case, controller, channel, and LiveView tests.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: N/A
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: Level 3: Service & Support
  • Curriculum Difficulty: Level 3: Applied
  • Knowledge Area: Testing / Quality
  • Software or Tool: ExUnit, Mox, Wallaby
  • Main Book: “Testing Elixir” by Andrea Leopardi

What you will build: Build unit, data-case, controller, channel, and LiveView tests.

Why it teaches the BEAM ecosystem: It makes you prove that tests assert public behavior and remain stable under randomized order.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Build unit, data-case, controller, channel, and LiveView tests.

$ mix test
...............................................................

Finished in 2.3 seconds
42 tests, 0 failures

Randomized with seed 12345

# Test breakdown:
# - 15 context tests (pure business logic)
# - 10 controller tests (HTTP layer)
# - 8 LiveView tests (interactive UI)
# - 5 channel tests (real-time)
# - 4 integration tests (full stack)

The Core Question You Are Answering

“How can Phoenix Test Pyramid deliver its observable outcome while proving that tests assert public behavior and remain stable under randomized order.”

Concepts You Must Understand First

  • ConnTest → maps to testing controllers
  • DataCase → maps to testing with database
  • ChannelCase → maps to testing channels
  • LiveViewTest → maps to testing LiveView

Questions to Guide Your Design

  1. Which input and output contracts must remain stable across refactoring?
  2. Where should validation happen, and how will expected failures be represented?
  3. Which component owns mutable state or external effects, and what happens when it dies?
  4. What independent evidence proves this mastery condition: tests assert public behavior and remain stable under randomized order.

Thinking Exercise

Draw Phoenix Test Pyramid as an input → decision/state → effect → evidence pipeline.

Mark every failure boundary, retry boundary, and durable state transition. Then inject one failure at each boundary and predict the observable result before implementing it.

The Interview Questions They Will Ask

  1. “What is the hardest invariant in Phoenix Test Pyramid, and where is it enforced?”
  2. “Which parts should be pure transformations and which require BEAM processes?”
  3. “How does the design behave under malformed input, process failure, or retry?”
  4. “What test or runtime evidence proves: tests assert public behavior and remain stable under randomized order.”

Hints in Layers

Testing a controller: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Testing LiveView: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Hint 1: Starting Point Implement the narrowest happy path for: Build unit, data-case, controller, channel, and LiveView tests.

Hint 2: Next Level Separate parsing, validation, and transition decisions from effects so each can be tested directly.

Hint 3: Technical Details Represent expected failures as tagged outcomes and keep state ownership explicit; write only structural pseudocode before implementation.

Hint 4: Tools and Debugging Inject one failure at a time, correlate it with bounded telemetry, and save a deterministic transcript as evidence.

Books That Will Help

  • Main Book: “Testing Elixir” by Andrea Leopardi

Implementation Milestones

  1. Context tests pass → You test business logic
  2. Controller tests pass → You test HTTP layer
  3. LiveView tests pass → You test interactive UIs
  4. Full test suite is fast → You understand async testing

Testing Strategy

  • Unit checks: pure parsing, validation, transition, and formatting decisions.
  • Integration checks: the real process, database, socket, notebook, or framework boundary.
  • Failure checks: malformed input plus at least one crash, timeout, duplicate, overload, or partition scenario.
  • Acceptance check: independently demonstrate that tests assert public behavior and remain stable under randomized order.
  • Avoid arbitrary sleeps; use messages, monitors, deterministic clocks, fixtures, and deadlines where applicable.

Common Pitfalls and Debugging

Problem 1: Happy-path output looks correct but failures disappear

  • Why: validation, effects, and reporting share one opaque step.
  • Fix: preserve tagged errors and source identity through every stage.
  • Quick test: inject one invalid record or failed dependency and verify an explicit result.

Problem 2: Tests merely repeat the implementation

  • Why: assertions reuse the same transformation or state assumptions.
  • Fix: check external invariants, golden fixtures, and observable failure behavior.
  • Quick test: introduce a deliberate ordering or boundary bug and confirm the test fails.

Definition of Done

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • tests assert public behavior and remain stable under randomized order.

Project 82: Durable Oban Document Workflow

Sources: BEAM-P24, PHX-P11. Build queues, schedules, uniqueness, retries, cancellation, idempotent effects, and repair history.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: Level 3: Service & Support
  • Curriculum Difficulty: Level 3: Applied
  • Knowledge Area: Durable Jobs, Workflow Reliability
  • Software or Tool: Oban, Ecto, PostgreSQL
  • Main Book: “Release It!”

What you will build: Build queues, schedules, uniqueness, retries, cancellation, idempotent effects, and repair history.

Why it teaches the BEAM ecosystem: It makes you prove that process or node loss cannot lose work or duplicate the final effect.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Integrated Scope

This is one consolidated project, not separate source builds. Implement the following contributions as phases of the same artifact:

  • Establish PHX-P11 queues, retries, scheduling, and uniqueness.
  • Turn the same worker flow into BEAM-P24’s staged document workflow with idempotent effects and repair history.

Real World Outcome

Build target: Build queues, schedules, uniqueness, retries, cancellation, idempotent effects, and repair history.

Build an API/CLI workflow with validate, preview, metadata, finalize, and notify stages. A local fixture converter simulates an external tool. Operators can inspect stage history, retry permitted failures, cancel active workflows, and verify artifact lineage.

$ docflow submit contract.pdf --key upload-2026-41
document=doc_41 input_version=1 state=queued validation_job=901

$ docflow status doc_41
validate=succeeded preview=retrying(attempt=2) metadata=succeeded
finalize=waiting notify=waiting

$ docflow attempts doc_41 --stage preview
attempt=1 outcome=temporary_failure reason=converter_unavailable
attempt=2 outcome=succeeded artifact=preview/doc_41/v1/transform-v2.png

3.7.1 How to Run (Copy/Paste)

$ mix ecto.create
$ mix ecto.migrate
$ mix test
$ mix run priv/demo_docflow.exs
$ docflow status demo-doc --history

3.7.2 Golden Path Demo (Deterministic)

The demo injects one converter failure, kills the next preview worker after artifact creation, restarts processing, and proves one artifact and one notification exist when the workflow completes.

3.7.3 Exact terminal transcript

$ mix run priv/demo_docflow.exs
submitted document=demo-doc validate_job=1001
validate attempt=1 outcome=succeeded
preview attempt=1 outcome=retry reason=converter_unavailable
preview attempt=2 fault=injected_after_artifact worker_killed=true
processor restarted durable_job_recovered=true
preview attempt=3 outcome=succeeded artifact_reused=true
metadata attempt=1 outcome=succeeded
finalize outcome=succeeded notify attempt=1 outcome=succeeded
artifacts preview=1 metadata=1 notifications=1 duplicate_effects=0
DEMO PASS

The Core Question You Are Answering

“How can a multi-stage Elixir workflow survive arbitrary worker failure without losing intent or duplicating external effects?”

Concepts You Must Understand First

  1. Oban worker lifecycle — Oban documentation, “Workers” and “Error Handling”.
  2. Ecto transactions — Programming Ecto, Chapter 6, “Transactions and Multi”.
  3. Idempotent receivers — Enterprise Integration Patterns, “Idempotent Receiver”.
  4. Stability and timeouts — Release It!, 2nd Edition, Chapters 4 and 5.

Questions to Guide Your Design

  1. What is the durable identity of each stage result and side effect?
  2. Which errors should retry, snooze, reject, or alert after exhaustion?
  3. How are state completion and successor insertion kept atomic?
  4. What happens when cancellation races stage completion?
  5. Which queue protects each constrained resource?

Thinking Exercise

Choose one stage and mark every point at which the process can die. For each point, identify durable records, temporary files, remote effects, and what the next attempt observes. Revise the design until every point converges safely.

The Interview Questions They Will Ask

  1. What durability does Oban provide, and what does it not guarantee?
  2. How do uniqueness, concurrency, and idempotency differ?
  3. When should a worker return an error, discard, or snooze?
  4. How would you prevent a successful stage from losing its next job?
  5. How do you cancel a job that owns an external process?
  6. What evidence lets an operator safely retry a failed workflow?

Hints in Layers

Hint 1: One durable transition — Implement validation with a unique stage row before modeling the whole graph.

Hint 2: Crash after success — Force a kill after artifact creation and design the repeated attempt around that fact.

Hint 3: Separate policies — Put conversion and notification in different queues and error classifiers.

Hint 4: Reconcile missing edges — Add a query that finds successful stages lacking their required successor.

Books That Will Help

Topic Book Chapter
Ecto transactions Programming Ecto Ch. 6
Idempotency Enterprise Integration Patterns Idempotent Receiver
Failure boundaries Release It!, 2nd Edition Ch. 4–5
Data workflows Designing Data-Intensive Applications, 2nd Edition Stream/batch processing chapters

Implementation Milestones

Integrated basic-to-advanced progression

  1. Establish PHX-P11 queues, retries, scheduling, and uniqueness.
  2. Turn the same worker flow into BEAM-P24’s staged document workflow with idempotent effects and repair history.

Milestone 1 — Contract and fixture: define one representative input, output, invariant, and failure case.

Milestone 2 — Core artifact: Build queues, schedules, uniqueness, retries, cancellation, idempotent effects, and repair history.

Milestone 3 — Failure behavior: add timeouts, invalid inputs, crashes, retries, or partitions appropriate to the project.

Milestone 4 — Evidence: automate the definition of done and record a reproducible result.

Phase 1: Durable State and One Worker (5-7 hours)

  • Create document/stage/artifact schemas, validation worker, outcome taxonomy, and operator query.

Phase 2: Workflow Graph and Failure Control (7-10 hours)

  • Add parallel preview/metadata, finalization, external tool bounds, retries, and idempotency.

Phase 3: Operability and Recovery Proof (6-9 hours)

  • Add notification, cancellation, history, reconciliation, telemetry, and kill/restart demo.

Testing Strategy

6.1 Test Categories

Category Purpose Examples
Worker Result classification permanent vs retryable converter failures
Transition Idempotent domain effects duplicate stage job
Transaction State plus successor atomicity injected rollback
Recovery Survive process/node loss kill after artifact write
Cancellation Prevent descendants and clean resources cancel during conversion
Operator Safe history/retry behavior exhausted and rejected jobs

6.2 Critical Test Cases

  1. Duplicate submit key creates one document/input version.
  2. Duplicate stage jobs create one committed stage result and artifact.
  3. Worker killed after artifact write reuses or validates the artifact on retry.
  4. Permanent invalid input is not retried and schedules no descendants.
  5. Temporary failures follow bounded backoff and eventually exhaust visibly.
  6. Parallel preview/metadata completion triggers finalization once.
  7. Cancellation during conversion cleans the external process and prevents notification.
  8. Notification timeout after remote acceptance produces one effect via stable idempotency key.

6.3 Test Data

Include valid, corrupt, encrypted-unsupported, huge-output, slow-converter, metadata-edge, and remote-rate-limit fixtures. Use fixed input digests and deterministic failure injection points.

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Problem: “Retries duplicate previews or notifications.”

  • Why: Output identity includes attempt number or remote calls lack idempotency keys.
  • Fix: Derive effects from document/stage/input version and persist unique transition identity.
  • Quick test: Kill after effect creation and force another attempt.

Problem: “Document says validated but never progresses.”

  • Why: State committed before successor job insertion.
  • Fix: Insert both in one transaction and add a missing-edge reconciler.
  • Quick test: Inject failure between the two intended operations.

Problem: “Poison documents retry forever.”

  • Why: All failures are returned as generic errors.
  • Fix: Classify permanent input failures and discard with a domain-state transition.
  • Quick test: Observe attempt count for a known unsupported fixture.

7.2 Debugging Strategies

  • Query by document ID across stage results and Oban jobs to build one timeline.
  • Record converter exit class, duration, and output size, not document bytes.
  • Inspect whether a job is waiting on schedule, queue capacity, dependency state, or retry delay.
  • Run the missing-successor and orphan-artifact reconciliation queries.

7.3 Performance Traps

  • Storing entire documents in job arguments.
  • Running CPU-heavy conversion in the same high-concurrency queue as notifications.
  • Retrying immediately during dependency outages.
  • Holding database transactions open during external conversion.

Definition of Done

  • Accepted document and first durable job are inserted atomically.
  • Every stage has stable versioned identity and idempotent repetition behavior.
  • Retryable, snoozed, permanent, exhausted, and cancelled outcomes are distinct.
  • Conversion has deadline, output limit, exit handling, and cleanup.
  • Stage completion and successor insertion cannot split.
  • Operators can inspect, cancel, and safely retry authorized failures.
  • Kill/restart demo completes with one artifact per stage and one notification.
  • Metrics expose queue delay, runtime, attempt, and low-cardinality outcome.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • Every merged source contribution is implemented as a phase of this one artifact, not as a separate project.
  • process or node loss cannot lose work or duplicate the final effect.

Project 83: Phoenix Telemetry and Live Metrics

Sources: BEAM-P10, PHX-P12. Instrument request, database, process, and business events.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: Level 3: Service & Support
  • Curriculum Difficulty: Level 3: Applied
  • Knowledge Area: Observability
  • Software or Tool: Telemetry + LiveView
  • Main Book: “Elixir in Action”

What you will build: Instrument request, database, process, and business events.

Why it teaches the BEAM ecosystem: It makes you prove that observability load stays bounded and emitted evidence localizes latency.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Integrated Scope

This is one consolidated project, not separate source builds. Implement the following contributions as phases of the same artifact:

  • Instrument Phoenix request/database events using PHX-P12 conventions.
  • Route those events through BEAM-P10 bounded aggregation and render one live metrics surface.

Real World Outcome

Build target: Instrument request, database, process, and business events.

Build a Phoenix telemetry pipeline that attaches to request, database, process, and business events; aggregates them with bounded memory; and renders a LiveView dashboard without turning telemetry handlers into blocking work.

$ mix telemetry_lab.demo --requests 1000 --inject slow_query
events phoenix_endpoint_stop=1000 ecto_query=412 order_completed=37
http p50_ms=18 p95_ms=74 p99_ms=141 error_rate=0.3%
db slow_queries=1 max_ms=286
aggregator series=12 samples_retained=720 dropped=0 mailbox_peak=14
live_dashboard update_ms=1000 connected=true
result=PASS handlers_non_blocking=true

The Core Question You Are Answering

“How do I make this service recover automatically without global failure?”

Concepts You Must Understand First

  • Review the concepts above and ensure you can explain them clearly.

Questions to Guide Your Design

  1. How will you partition work across processes?
  2. Where is state stored and how is it protected?
  3. What happens when a worker crashes?

Thinking Exercise

Sketch the message flow and failure paths before coding.

The Interview Questions They Will Ask

  1. “Why does this design scale better than shared-memory locks?”
  2. “How do you detect and recover from failures?”
  3. “How do you prevent mailbox buildup?”
  4. “Which measurement would tell you that Phoenix Telemetry and Live Metrics is approaching its operating limit?”

Hints in Layers

Hint 1: Start with one worker process and a single message type.

Hint 2: Add supervision and confirm restart behavior.

Hint 3: Add routing and concurrency only after correctness.

Hint 4: Validate output with scripted test vectors.

Books That Will Help

Topic Book Chapter
Core BEAM “Programming Erlang” Processes chapter
OTP “Designing for Scalability with Erlang/OTP” Supervision chapter

Implementation Milestones

Integrated basic-to-advanced progression

  1. Instrument Phoenix request/database events using PHX-P12 conventions.
  2. Route those events through BEAM-P10 bounded aggregation and render one live metrics surface.

Milestone 1 — Contract and fixture: define one representative input, output, invariant, and failure case.

Milestone 2 — Core artifact: Instrument request, database, process, and business events.

Milestone 3 — Failure behavior: add timeouts, invalid inputs, crashes, retries, or partitions appropriate to the project.

Milestone 4 — Evidence: automate the definition of done and record a reproducible result.

Phase 1: Foundation (2-4 hours)

  • Build a single worker process
  • Define message shapes

Phase 2: Core Functionality (4-8 hours)

  • Add routing and state storage
  • Validate correctness on test cases

Phase 3: Polish & Edge Cases (2-4 hours)

  • Add failure injection tests
  • Document recovery behavior

Testing Strategy

6.1 Test Categories

Category Purpose Examples
Unit Tests Validate core logic message parsing
Integration Tests End-to-end flow demo scenario
Failure Tests Crash recovery kill worker

6.2 Critical Test Cases

  1. Normal path: request -> response
  2. Crash path: worker exit -> restart
  3. Overload: burst input -> bounded queue

6.3 Test Data

inputs: demo messages
expected: stable outputs

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Pitfall Symptom Solution
Missing supervisor app dies on crash add supervisor
Oversized mailbox latency spikes split processes
Unbounded state memory growth add eviction

7.2 Debugging Strategies

  • Use observer to inspect process counts and queues
  • Add structured logs on message receive

7.3 Performance Traps

  • Avoid heavy work in a single process

Definition of Done

  • Metrics update in real time
  • Pipeline handles burst without backlog
  • Dashboard remains responsive
  • Metrics are accurate and documented

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • Every merged source contribution is implemented as a phase of this one artifact, not as a separate project.
  • observability load stays bounded and emitted evidence localizes latency.

Project 84: Production Phoenix Deployment

Source: PHX-P14. Build a release with runtime config, HTTPS, migrations, health checks, graceful shutdown, and rollback.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Docker, Bash
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: Level 3: Service & Support
  • Curriculum Difficulty: Level 3: Applied
  • Knowledge Area: DevOps / Deployment
  • Software or Tool: Mix releases, Docker, Fly.io or self-hosted
  • Main Book: “Real-World Elixir Deployment” (various resources)

What you will build: Build a release with runtime config, HTTPS, migrations, health checks, graceful shutdown, and rollback.

Why it teaches the BEAM ecosystem: It makes you prove that a clean host boots the immutable artifact.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Build a release with runtime config, HTTPS, migrations, health checks, graceful shutdown, and rollback.

Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

# Build and deploy
$ docker build -t my_app .
$ docker push my_registry/my_app

# On Fly.io
$ fly deploy

# Check clustering
$ fly ssh console
> Node.list()
[:my_app@fdaa:0:1234::3]  # Connected to peer!

# Run migrations
$ fly ssh console
> MyApp.Release.migrate()

The Core Question You Are Answering

“How can Production Phoenix Deployment deliver its observable outcome while proving that a clean host boots the immutable artifact.”

Concepts You Must Understand First

  • Releases → maps to packaging for production
  • Runtime configuration → maps to config/runtime.exs
  • Migrations in production → maps to Ecto.Migrator
  • Clustering → maps to connecting nodes

Questions to Guide Your Design

  1. Which input and output contracts must remain stable across refactoring?
  2. Where should validation happen, and how will expected failures be represented?
  3. Which component owns mutable state or external effects, and what happens when it dies?
  4. What independent evidence proves this mastery condition: a clean host boots the immutable artifact.

Thinking Exercise

Draw Production Phoenix Deployment as an input → decision/state → effect → evidence pipeline.

Mark every failure boundary, retry boundary, and durable state transition. Then inject one failure at each boundary and predict the observable result before implementing it.

The Interview Questions They Will Ask

  1. “What is the hardest invariant in Production Phoenix Deployment, and where is it enforced?”
  2. “Which parts should be pure transformations and which require BEAM processes?”
  3. “How does the design behave under malformed input, process failure, or retry?”
  4. “What test or runtime evidence proves: a clean host boots the immutable artifact.”

Hints in Layers

Release configuration: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Release module for migrations: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Hint 1: Starting Point Implement the narrowest happy path for: Build a release with runtime config, HTTPS, migrations, health checks, graceful shutdown, and rollback.

Hint 2: Next Level Separate parsing, validation, and transition decisions from effects so each can be tested directly.

Hint 3: Technical Details Represent expected failures as tagged outcomes and keep state ownership explicit; write only structural pseudocode before implementation.

Hint 4: Tools and Debugging Inject one failure at a time, correlate it with bounded telemetry, and save a deterministic transcript as evidence.

Books That Will Help

  • Main Book: “Real-World Elixir Deployment” (various resources)

Implementation Milestones

  1. Release builds successfully → You understand mix release
  2. Docker container runs → You understand containerization
  3. App starts in production → You understand runtime config
  4. Multiple instances cluster → You understand horizontal scaling

Testing Strategy

  • Unit checks: pure parsing, validation, transition, and formatting decisions.
  • Integration checks: the real process, database, socket, notebook, or framework boundary.
  • Failure checks: malformed input plus at least one crash, timeout, duplicate, overload, or partition scenario.
  • Acceptance check: independently demonstrate that a clean host boots the immutable artifact.
  • Avoid arbitrary sleeps; use messages, monitors, deterministic clocks, fixtures, and deadlines where applicable.

Common Pitfalls and Debugging

Problem 1: Happy-path output looks correct but failures disappear

  • Why: validation, effects, and reporting share one opaque step.
  • Fix: preserve tagged errors and source identity through every stage.
  • Quick test: inject one invalid record or failed dependency and verify an explicit result.

Problem 2: Tests merely repeat the implementation

  • Why: assertions reuse the same transformation or state assumptions.
  • Fix: check external invariants, golden fixtures, and observable failure behavior.
  • Quick test: introduce a deliberate ordering or boundary bug and confirm the test fails.

Definition of Done

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • a clean host boots the immutable artifact.

Project 85: Transactional Notification Outbox

Source: PUB-P9. Commit domain state and an Oban/outbox handoff atomically, using Pub/Sub only for UI refresh.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Java
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: Level 3: Service & Support
  • Curriculum Difficulty: Level 3: Applied
  • Knowledge Area: Database transactions, durable jobs, idempotency
  • Software or Tool: Ecto, PostgreSQL, Oban 2.23, Phoenix.PubSub
  • Main Book: “Designing Data-Intensive Applications, 2nd Edition” by Kleppmann et al.

What you will build: Commit domain state and an Oban/outbox handoff atomically, using Pub/Sub only for UI refresh.

Why it teaches the BEAM ecosystem: It makes you prove that duplicate delivery creates one effective external action.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Commit domain state and an Oban/outbox handoff atomically, using Pub/Sub only for UI refresh.

Build a Phoenix training application with an order aggregate, an immutable durable handoff, a supervised worker, a mock external webhook receiver, and two connected order views.

The reference scenario supports one transition from authorized to approved. The command includes tenant ID, order ID, expected revision, actor ID, and request ID. A successful transaction updates the order revision and inserts either an outbox event plus relay job or an Oban job containing the immutable event envelope. An invalid state transition rolls back both operations.

After commit, the command path broadcasts a compact refresh. Two LiveViews subscribed to a server-derived tenant/order topic reload revision 18. If either misses the message, reconnecting or detecting a revision gap produces the same state.

The worker calls a local mock webhook with evt-77 as its idempotency key. The mock stores one effect result per event ID. A failure switch crashes the worker after the mock accepts the call but before local completion is recorded. Retry receives already_processed, records success, and completes the durable job.

$ mix outbox.scenario
TX begin tenant=42 order=913 expected_revision=17
TX commit order_revision=18 event_id=evt-77 job_id=551
pubsub topic=tenant:42:order:913 refresh_revision=18 online_views=2

worker paused
application restarted
job id=551 state=available persisted=true

attempt=1 event_id=evt-77 webhook=accepted effect_id=fx-208
fault injected point=after_remote_accept_before_local_ack
attempt=2 event_id=evt-77 webhook=already_processed effect_id=fx-208
job id=551 state=completed effective_calls=1

invalid transition expected=18 requested=cancelled reason=policy_denied
transaction=rolled_back order_revision=18 new_jobs=0
scenario result=PASS

Open the application in two browser windows as two authorized operators for tenant 42. Both windows show order 913 at revision 17 and a notification-delivery panel. Approve the order in the first window. The status card changes to revision 18 in both windows without a manual refresh. The event panel shows evt-77, job 551, and available or executing before it becomes completed.

Next, pause the worker before approving a second order. The UI shows the business transition as committed while the notification card remains pending. Restart the application. The order and pending work are still present, demonstrating that correctness did not depend on a process mailbox.

Enable the dangerous fault switch. The webhook receiver records one effect, the worker crashes before acknowledgement, and the job retries. The second request returns the original effect result. The final evidence screen shows two attempts, one effective action, one immutable event ID, and no duplicate customer notification.

Finally, attempt an invalid transition. The UI renders a policy error, the order revision remains unchanged, and the audit query reports zero new handoff records. Export the scenario transcript and invariant table as the completion artifact.

The Core Question You Are Answering

“How do I guarantee that committed state eventually triggers required work without pretending the database and message system share one transaction?”

Before implementation, write the guarantee in one sentence. It must mention one local atomic commit, durable responsibility, at-least-once execution, stable identity, and idempotent effects. If it says “exactly once,” identify the specific storage constraint and boundary that make that statement true; do not use it as an end-to-end slogan.

Concepts You Must Understand First

  1. Database transaction boundaries
    • Which operations can PostgreSQL commit or roll back together?
    • Why can an HTTP call inside the callback not be rolled back?
    • Reference: Ecto Ecto.Multi and repository transaction documentation.
  2. Transactional outbox or transactional job insertion
    • Is the durable record an integration event, an executable job, or both?
    • Which component owns relay and retention?
    • Reference: Oban insert/4 with Ecto.Multi; Debezium outbox event router documentation.
  3. At-least-once delivery
    • Which crash window leaves completion uncertain?
    • Why must every attempt preserve event identity?
    • Book Reference: “Enterprise Integration Patterns” — Guaranteed Delivery and Idempotent Receiver.
  4. Optimistic concurrency
    • How does expected revision prevent lost updates?
    • What should a stale caller receive?
    • Book Reference: “Designing Data-Intensive Applications, 2nd Edition” — Transactions.
  5. PubSub as invalidation
    • Why should a view reload current authorized state?
    • What happens if the notification is missed or reordered?
    • Reference: Phoenix.PubSub API documentation.

Questions to Guide Your Design

  1. Event identity
    • Is the ID generated before transaction retry, and can retries accidentally create a new logical event?
    • How do you detect the same ID reused with a different payload?
  2. Commit and notify
    • Who owns after-commit broadcast?
    • How does the UI recover when that owner crashes before broadcasting?
  3. Failure classification
    • Which HTTP errors are transient, rate-limited, permanent, or ambiguous?
    • When does an exhausted job require operator action?
  4. Retention and privacy
    • How long must event metadata remain auditable?
    • Which fields must never enter job arguments or logs?
  5. Operational budgets
    • What oldest-job age pages an operator?
    • What queue depth triggers degraded noncritical delivery?

Thinking Exercise

Draw this timeline on paper and mark each crash point:

request -> decision -> DB begin -> order update -> handoff insert -> commit
        -> PubSub refresh -> worker claim -> receiver effect -> receiver response
        -> local completion acknowledgement

For every arrow, answer:

  • What durable evidence exists immediately before and after it?
  • Can the step be repeated safely?
  • Can a duplicate delivery occur?
  • Can a duplicate effect occur?
  • What process or scan resumes progress?
  • What would the user observe?

The dangerous case is receiver effect success followed by worker death. Your design is not complete until this case has a deterministic answer.

The Interview Questions They Will Ask

  1. “What problem does the transactional outbox solve, and what does it not solve?”
  2. “Why isn’t a broker publish inside Ecto.Multi.run atomic with PostgreSQL?”
  3. “How do you handle a crash after a side effect but before acknowledgement?”
  4. “What is the difference between Oban job uniqueness and idempotent execution?”
  5. “Why keep a periodic scan if PubSub or PostgreSQL notification wakes the worker?”
  6. “When would you choose an outbox plus broker over a database job?”

Hints in Layers

Hint 1: Start with the invariant

Write a query that finds approved order revisions with no handoff. Make the test fail under a two-write implementation, then remove the window with one transaction.

Hint 2: Broadcast identities, not snapshots

Use a conceptual refresh message:

{:order_changed, tenant_id, order_id, revision, event_id}

The subscriber authorizes and reloads. Treat the tuple as a protocol outline, not the source of truth.

Hint 3: Preserve identity through retries

Put the immutable event ID in job arguments and the receiver idempotency header. Never derive a new ID from attempt number.

Hint 4: Test uncertainty, not only obvious failure

Crash after receiver commit but before worker completion. A pre-call crash proves only ordinary retry; the post-effect crash proves idempotency.

Books That Will Help

Topic Book Chapter / Pattern
Guaranteed delivery “Enterprise Integration Patterns” Guaranteed Delivery, Idempotent Receiver
Local transactions and derived data “Designing Data-Intensive Applications, 2nd Edition” Transactions; Stream Processing
Service messaging “Building Microservices, 2nd Edition” Asynchronous Communication
Failure and recovery “Release It!, 2nd Edition” Stability Patterns

Implementation Milestones

Phase 1: Atomic Domain Handoff (8–10 hours)

Goals

  • Define the order transition and immutable event envelope.
  • Commit domain revision and durable handoff together.

Tasks

  1. Create order, handoff/job, and effect-ledger schemas with database constraints.
  2. Write the valid and invalid transition decision table.
  3. Build the transaction outline and inspect its named operations before execution.
  4. Add the orphan query and rollback tests.
  5. Record event identity and correlation policy.

Checkpoint: 1,000 injected failures around transaction operations produce zero committed revisions without a handoff and zero handoffs for rolled-back revisions.

Phase 2: Durable Execution and Idempotency (8–12 hours)

Goals

  • Execute pending work under retry.
  • Prove the dangerous crash produces one effect.

Tasks

  1. Add the worker and explicit transient/permanent failure table.
  2. Implement the mock receiver’s unique event ledger.
  3. Inject faults before call, after receiver commit, and before local acknowledgement.
  4. Pause workers and restart the application.
  5. Add queue-age, attempt, and outcome telemetry.

Checkpoint: The same event is delivered at least twice after the post-effect crash, but the receiver reports one effective action and the job completes.

Phase 3: Transient UX and Operations (8–14 hours)

Goals

  • Add fast online refresh without coupling correctness to PubSub.
  • Produce an operator-grade audit and recovery story.

Tasks

  1. Add after-commit refresh and authorized reload.
  2. Run two-client, missed-message, reconnect, and stale-revision tests.
  3. Add periodic recovery scan and oldest-work alert.
  4. Document retention, redaction, discard, and manual resolution.
  5. Run the complete scenario and export evidence.

Checkpoint: Both online views refresh quickly; a disconnected view catches up from the database; pending work survives restart; the failure report explains every attempt.

Testing Strategy

6.1 Test Categories

Category Purpose Examples
Unit Verify transition and error classification Valid revision, stale revision, transient vs permanent response
Transaction integration Prove atomic database invariant Fail before update, between operations, before commit
Worker integration Prove retry and idempotency Crash after receiver effect, repeated event ID
PubSub integration Prove refresh is optional Two clients, missed broadcast, reconnect reload
Restart Prove durable responsibility Worker pause, app restart, database restart
Property/state-machine Explore operation sequences Commands, failures, retries, duplicate delivery
Operational Verify metrics and runbook Oldest age alert, discard visibility, redaction

6.2 Critical Test Cases

  1. Successful transition: Revision 17 becomes 18 and exactly one durable handoff contains the matching identity.
  2. Invalid transition: Policy failure rolls back; no revision or handoff changes.
  3. Optimistic conflict: Two commands expect revision 17; one commits and one receives a conflict without a second event.
  4. Crash before commit: Neither domain nor handoff change persists.
  5. Crash after commit before PubSub: Durable work remains and reconnect reloads revision 18.
  6. Worker restart: Available or executing work becomes runnable after restart according to queue semantics.
  7. Crash after external effect: Retry occurs with the same ID and receiver effect count stays one.
  8. Identity collision: Same event ID with a different digest is rejected and alerted.
  9. Missed wake-up: Periodic scan finds the pending item.
  10. Redaction: Secrets and customer payload fields are absent from job args, logs, metrics, and exported evidence.

6.3 Test Data

tenant: 42
order: 913
initial_status: authorized
initial_revision: 17
valid_command: approve expected_revision=17 request=req-501
event: evt-77 type=order.approved revision=18 schema=1
job: 551 queue=notifications max_attempts=8
receiver_result: fx-208

invalid_cases:
  - approve expected_revision=16 -> optimistic_conflict
  - cancel approved_order -> policy_denied
  - evt-77 with altered order_id -> idempotency_identity_conflict
  - receiver 503 -> retry
  - receiver 422 unsupported_schema -> permanent_failure

The test suite should generate additional event IDs deterministically from a fixed seed and should print the seed on failure.

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Pitfall Symptom Solution
Separate transactions Approved order has no job Commit mutation and handoff in one transaction
External call inside transaction Long locks and ghost effects after rollback Keep external effects in durable post-commit work
New ID per retry Duplicate receiver actions Preserve logical event ID across attempts
Treating Oban uniqueness as execution lock Concurrent jobs still run Configure concurrency and make effects idempotent
Broadcast before commit Subscriber reloads old state or sees rolled-back event Broadcast after successful transaction result
PubSub-only recovery Disconnected views remain stale Reload on mount and detect revision gaps
Unbounded job payload Sensitive/stale snapshots persist Store minimal identifiers and versioned fields
Retry every error Permanent poison work loops forever Classify discard, retry, and review outcomes

7.2 Debugging Strategies

  • Query the invariant first: Count committed target revisions without matching handoff rows.
  • Trace one event ID: Search structured logs, job args, receiver ledger, and refresh metrics for evt-77.
  • Inspect transaction operations: Use the Multi’s canonical operation list in tests rather than poking at internal fields.
  • Freeze workers: Pausing execution separates commit behavior from delivery behavior.
  • Move the fault point: A named fault switch before/after each boundary makes uncertainty reproducible.
  • Compare delivery and effect counts: Delivery attempts may exceed one; effective actions must not.
  • Reconnect the UI: If state repairs on reconnect, the transient notification path—not the authority—is suspect.

7.3 Performance Traps

  • Holding a transaction open during HTTP or broker I/O increases lock time and contention.
  • Scanning the entire outbox without a state/time index becomes progressively expensive.
  • Immediate retries amplify downstream outages; use backoff, jitter, and queue concurrency limits.
  • Large job arguments increase database I/O and retention cost.
  • Broadcasting full aggregates increases serialization and mailbox pressure.
  • Retaining every completed job and effect forever requires partitioning/archival policy.

Definition of Done

Minimum Viable Completion

  • One valid order transition atomically commits revision and durable handoff.
  • One invalid transition rolls back both.
  • One connected view refreshes after commit.
  • Paused work survives application restart.
  • Event identity is visible across database, worker, and mock receiver.

Full Completion

  • All minimum criteria plus optimistic conflict, two-client refresh, missed-message reload, recovery scan, and explicit failure classification.
  • The post-effect crash produces at least two deliveries and exactly one effective action.
  • Queue age, attempts, terminal failures, and refresh latency are observable.
  • Retention, privacy, redaction, and operator-resolution policies are documented.
  • The complete deterministic scenario transcript reports all invariants as passing.

Excellence (Going Above & Beyond)

  • A property/state-machine test explores command, crash, and retry sequences with reproducible seeds.
  • An alternative CDC/broker relay is benchmarked against direct database-job execution.
  • Commit-to-effect SLOs and alert thresholds are justified with load evidence.
  • The learner can disable PubSub entirely and prove durable facts and work still recover.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • duplicate delivery creates one effective external action.

Phase 4 - Ash Framework Resource and Policy Mastery

Project 86: First Typed Ash Resource

Sources: ASH-P1, ASH-P2. Define a resource with types, defaults, identities, and validations.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: Level 3: Service & Support
  • Curriculum Difficulty: Level 3: Applied
  • Knowledge Area: Declarative domain modeling
  • Software or Tool: Ash Framework
  • Main Book: Ash Framework documentation and Elixir in Action

What you will build: Define a resource with types, defaults, identities, and validations.

Why it teaches the BEAM ecosystem: It makes you prove that all generated interfaces honor the same contract.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Integrated Scope

This is one consolidated project, not separate source builds. Implement the following contributions as phases of the same artifact:

  • Complete ASH-P1 installation, domain registration, and one ETS-backed Ticket resource.
  • Extend that resource with ASH-P2 types, defaults, identities, constraints, and validations.

Real World Outcome

Build target: Define a resource with types, defaults, identities, and validations.

Your Ticket resource will have rich attributes:

Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Build First Typed Ash Resource as one runnable, observable artifact. Define a resource with types, defaults, identities, and validations.

Produce an evidence bundle containing:

  • one deterministic happy-path run;
  • one rejected or malformed input with an explicit reason;
  • one injected failure or boundary condition;
  • a final verification result proving: all generated interfaces honor the same contract.
artifact=first_typed_ash_resource
happy_path=PASS
invalid_input=REJECTED explicit_reason=true
failure_boundary=EXERCISED recovery_evidence=true
mastery_check=PASS

The Core Question You Are Answering

How does Ash’s attribute system differ from Ecto schemas, and how do constraints provide validation at the data definition level rather than in separate changeset functions?

Concepts You Must Understand First

  1. Elixir type specs: How Elixir types work (atoms, strings, integers)
  2. Ecto types: Ash builds on Ecto’s type system
  3. Changeset validations: Understand how Ecto validates before storage

Questions to Guide Your Design

  1. Should status be a string or an enum? What are the tradeoffs?
  2. When should an attribute have allow_nil?: false?
  3. What’s the difference between default and create_default?
  4. Why might you make an attribute private?: true?

Thinking Exercise

Design the attributes for a User resource that includes:

  • Email (required, unique, must be valid format)
  • Name (required, min 2 characters)
  • Role (enum: admin, member, guest)
  • Bio (optional, max 500 characters)
  • Verified status (boolean, default false)
  • Timestamps

Write out the attribute definitions before implementing.

The Interview Questions They Will Ask

  1. “How do you define an enum type in Ash?”
  2. “What’s the difference between allow_nil? and required??”
  3. “How do you set default values that are computed at runtime?”
  4. “What constraints are available for string attributes?”
  5. “How do you prevent an attribute from being set by external input?”

Hints in Layers

Hint 1 - Starting Point: Define a dedicated ticket-status enum type with the values open, in_progress, and closed; keep the module shape as your own implementation exercise.

Hint 2 - Next Level: Use constraints for validation: attribute :subject, :string, allow_nil?: false, constraints: [min_length: 5, max_length: 200]

Hint 3 - Technical Details: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Hint 4 - Verification: Try creating tickets with invalid data and verify you get proper error messages.

Books That Will Help

  • Main Book: Ash Framework documentation and Elixir in Action

Implementation Milestones

Integrated basic-to-advanced progression

  1. Complete ASH-P1 installation, domain registration, and one ETS-backed Ticket resource.
  2. Extend that resource with ASH-P2 types, defaults, identities, constraints, and validations.

Milestone 1 — Contract and fixture: define one representative input, output, invariant, and failure case.

Milestone 2 — Core artifact: Define a resource with types, defaults, identities, and validations.

Milestone 3 — Failure behavior: add timeouts, invalid inputs, crashes, retries, or partitions appropriate to the project.

Milestone 4 — Evidence: automate the definition of done and record a reproducible result.

Testing Strategy

  • Unit checks: pure parsing, validation, transition, and formatting decisions.
  • Integration checks: the real process, database, socket, notebook, or framework boundary.
  • Failure checks: malformed input plus at least one crash, timeout, duplicate, overload, or partition scenario.
  • Acceptance check: independently demonstrate that all generated interfaces honor the same contract.
  • Avoid arbitrary sleeps; use messages, monitors, deterministic clocks, fixtures, and deadlines where applicable.

Common Pitfalls and Debugging

Problem Cause Fix Verification
Enum not found Module not compiled Ensure enum module is defined before resource Code.ensure_loaded(MyApp.Support.Ticket.Status)
Constraint not validated Wrong constraint name Check docs for exact constraint names Read error messages carefully
Default not applied Using default instead of create_default Use create_default for runtime computation Create record and check value

Definition of Done

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • Every merged source contribution is implemented as a phase of this one artifact, not as a separate project.
  • all generated interfaces honor the same contract.

Sources: ASH-P3, ASH-P4. Model relationships and CRUD actions with relationship management.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: Level 3: Service & Support
  • Curriculum Difficulty: Level 3: Applied
  • Knowledge Area: Declarative domain modeling
  • Software or Tool: Ash Framework
  • Main Book: Ash Framework documentation and Elixir in Action

What you will build: Model relationships and CRUD actions with relationship management.

Why it teaches the BEAM ecosystem: It makes you prove that loading avoids N+1 work and invalid links fail predictably.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Integrated Scope

This is one consolidated project, not separate source builds. Implement the following contributions as phases of the same artifact:

  • Model ASH-P3 relationships and loading behavior first.
  • Expose those relationships through ASH-P4 CRUD actions without duplicating lifecycle rules.

Real World Outcome

Build target: Model relationships and CRUD actions with relationship management.

Implement comprehensive CRUD (Create, Read, Update, Destroy) actions for your support system with validation, error handling, and action arguments.

Build Related Resources and CRUD Actions as one runnable, observable artifact. Model relationships and CRUD actions with relationship management.

Produce an evidence bundle containing:

  • one deterministic happy-path run;
  • one rejected or malformed input with an explicit reason;
  • one injected failure or boundary condition;
  • a final verification result proving: loading avoids N+1 work and invalid links fail predictably.
artifact=related_resources_and_crud_actions
happy_path=PASS
invalid_input=REJECTED explicit_reason=true
failure_boundary=EXERCISED recovery_evidence=true
mastery_check=PASS

The Core Question You Are Answering

How do Ash actions provide a layer of abstraction over raw data operations, and why is it better to define many specific actions rather than few generic ones?

Concepts You Must Understand First

  1. Changesets: How Ash builds changesets for actions
  2. Action semantics: What each action type means
  3. Elixir pattern matching: For action arguments

Questions to Guide Your Design

  1. Should you have one :update action or many specific ones (:assign, :close, :escalate)?
  2. When should you use accept vs reject for attributes?
  3. What’s the difference between an action argument and an accepted attribute?
  4. How do you ensure only certain fields can be changed through a specific action?

Thinking Exercise

Design the actions for a Ticket resource:

  • Create actions: :open (new tickets), :create_from_email (automated)
  • Read actions: :list_open, :list_by_assignee, :search
  • Update actions: :assign, :unassign, :change_priority, :add_note, :close
  • Destroy actions: :delete, :archive

For each, list what attributes/arguments it should accept.

The Interview Questions They Will Ask

  1. “Why does Ash encourage many specific actions instead of generic CRUD?”
  2. “What’s the difference between accept and argument in an action?”
  3. “How do you make an action the primary action for its type?”
  4. “Explain the action lifecycle: what happens before and after the data layer?”
  5. “How do you add side effects to an action?”

Hints in Layers

Hint 1 - Starting Point: Start with defaults [:create, :read, :update, :destroy], then customize one at a time.

Hint 2 - Next Level: Create a specific action: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Hint 3 - Technical Details: Use changes for action logic: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Hint 4 - Verification: Try calling each action and verify only the intended attributes can be changed.

Books That Will Help

  • Main Book: Ash Framework documentation and Elixir in Action

Implementation Milestones

Integrated basic-to-advanced progression

  1. Model ASH-P3 relationships and loading behavior first.
  2. Expose those relationships through ASH-P4 CRUD actions without duplicating lifecycle rules.

Milestone 1 — Contract and fixture: define one representative input, output, invariant, and failure case.

Milestone 2 — Core artifact: Model relationships and CRUD actions with relationship management.

Milestone 3 — Failure behavior: add timeouts, invalid inputs, crashes, retries, or partitions appropriate to the project.

Milestone 4 — Evidence: automate the definition of done and record a reproducible result.

Testing Strategy

  • Unit checks: pure parsing, validation, transition, and formatting decisions.
  • Integration checks: the real process, database, socket, notebook, or framework boundary.
  • Failure checks: malformed input plus at least one crash, timeout, duplicate, overload, or partition scenario.
  • Acceptance check: independently demonstrate that loading avoids N+1 work and invalid links fail predictably.
  • Avoid arbitrary sleeps; use messages, monitors, deterministic clocks, fixtures, and deadlines where applicable.

Common Pitfalls and Debugging

Problem Cause Fix Verification
Attribute not accepted Not in accept list Add to accept [:field] or use argument Check error message
Action not found Typo or not defined Check action name exactly Resource.__ash_actions__()
Changes not applied Missing change call Add change set_attribute(...) Read after write

Definition of Done

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • Every merged source contribution is implemented as a phase of this one artifact, not as a separate project.
  • loading avoids N+1 work and invalid links fail predictably.

Project 88: Custom Ash Actions on PostgreSQL

Sources: ASH-P5, ASH-P6. Persist custom actions, changes, preparations, migrations, and constraints through AshPostgres.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: Level 3: Service & Support
  • Curriculum Difficulty: Level 3: Applied
  • Knowledge Area: Declarative domain modeling
  • Software or Tool: Ash Framework
  • Main Book: Ash Framework documentation and Elixir in Action

What you will build: Persist custom actions, changes, preparations, migrations, and constraints through AshPostgres.

Why it teaches the BEAM ecosystem: It makes you prove that named transitions survive concurrent enforcement.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Integrated Scope

This is one consolidated project, not separate source builds. Implement the following contributions as phases of the same artifact:

  • Define ASH-P5 named business actions, changes, and preparations.
  • Persist those same actions through ASH-P6 AshPostgres migrations and constraints.

Real World Outcome

Build target: Persist custom actions, changes, preparations, migrations, and constraints through AshPostgres.

Build a PostgreSQL-backed support domain whose named assign, escalate, and resolve actions enforce the same transition rules in every interface. Generated migrations create the resource tables, constraints, and query indexes. A version or equivalent concurrency guard ensures two actors cannot both complete the same transition from stale state.

SCENARIO named_action_persistence
ticket=T-42 initial_state=open version=1
action=assign actor=lead assignee=agent_7 result=accepted state=assigned version=2
action=resolve actor=agent_7 notes="fixed upstream" result=accepted state=resolved version=3
restart_application=true reload ticket=T-42 state=resolved version=3 persistence=PASS

SCENARIO rejected_contracts
action=resolve ticket=T-99 state=closed result=rejected reason=invalid_transition
create ticket=T-100 subject_length=2 result=rejected reason=subject_too_short
concurrent_action ticket=T-101 expected_version=4 accepted=1 conflict=1 final_version=5
database_constraints=PASS named_transitions=PASS result=PASS

The Core Question You Are Answering

How does Ash’s declarative resource definition translate to PostgreSQL schemas and queries, and how do you optimize database performance within the Ash model?

Concepts You Must Understand First

  1. PostgreSQL basics: Tables, columns, constraints, indexes
  2. Ecto migrations: How schema changes are managed
  3. SQL queries: Understanding SELECT, JOIN, WHERE

Questions to Guide Your Design

  1. What indexes should you add for your most common queries?
  2. How do you handle schema changes after initial deployment?
  3. When should you use database constraints vs application validations?
  4. How do you debug slow queries?

Thinking Exercise

Review your Ticket and User resources. List:

  1. All the tables that will be created
  2. All foreign key relationships
  3. Indexes you need for these queries:
    • Find all open tickets
    • Find tickets by reporter email
    • Find recent tickets (last 7 days)
    • Full-text search on ticket subject

The Interview Questions They Will Ask

  1. “How does AshPostgres generate migrations?”
  2. “What’s the difference between mix ash.codegen and mix ecto.gen.migration?”
  3. “How do you add custom indexes in Ash?”
  4. “How do you handle database-specific column types?”
  5. “How does Ash handle relationship queries at the database level?”

Hints in Layers

Hint 1 - Starting Point: Write a table for every named action: accepted arguments, allowed source states, resulting state, database constraint, and externally visible error.

Hint 2 - Next Level: Use this structural pseudocode before writing the Ash resource:

Ticket resource -> PostgreSQL tickets table
resolve action -> validate actor and source state -> compare expected version -> persist new state
failed validation or stale version -> tagged rejection with no partial update

Hint 3 - Technical Details: Derive indexes from named read paths rather than adding them generically: one composite index for status plus recency, one for assignee work queues, and an identity/unique constraint for the external ticket key. Record the intended query beside each index and confirm it with an explain plan.

Hint 4 - Verification: Generate and inspect the migration, run the action transcript, restart the application, and race two stale transitions. Verify persistence, one accepted winner, one explicit conflict, and no bypass of the named action contract.

Books That Will Help

  • Main Book: Ash Framework documentation and Elixir in Action

Implementation Milestones

Integrated basic-to-advanced progression

  1. Define ASH-P5 named business actions, changes, and preparations.
  2. Persist those same actions through ASH-P6 AshPostgres migrations and constraints.

Milestone 1 — Contract and fixture: define one representative input, output, invariant, and failure case.

Milestone 2 — Core artifact: Persist custom actions, changes, preparations, migrations, and constraints through AshPostgres.

Milestone 3 — Failure behavior: add timeouts, invalid inputs, crashes, retries, or partitions appropriate to the project.

Milestone 4 — Evidence: automate the definition of done and record a reproducible result.

Testing Strategy

  • Unit checks: pure parsing, validation, transition, and formatting decisions.
  • Integration checks: the real process, database, socket, notebook, or framework boundary.
  • Failure checks: malformed input plus at least one crash, timeout, duplicate, overload, or partition scenario.
  • Acceptance check: independently demonstrate that named transitions survive concurrent enforcement.
  • Avoid arbitrary sleeps; use messages, monitors, deterministic clocks, fixtures, and deadlines where applicable.

Common Pitfalls and Debugging

Problem Cause Fix Verification
Migration fails Missing references Ensure related resources are migrated first Check migration order
Slow queries Missing indexes Add indexes for filter/sort columns EXPLAIN ANALYZE in psql
Type mismatch Ash type vs Postgres type Use migration_types for custom mappings Check migration file

Definition of Done

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • Every merged source contribution is implemented as a phase of this one artifact, not as a separate project.
  • named transitions survive concurrent enforcement.

Project 89: Ash Calculations, Aggregates, and Queries

Sources: ASH-P7, ASH-P8, ASH-P9. Build derived fields, aggregates, filters, sorts, and read models.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: Level 3: Service & Support
  • Curriculum Difficulty: Level 3: Applied
  • Knowledge Area: Declarative domain modeling
  • Software or Tool: Ash Framework
  • Main Book: Ash Framework documentation and Elixir in Action

What you will build: Build derived fields, aggregates, filters, sorts, and read models.

Why it teaches the BEAM ecosystem: It makes you prove that generated queries are explainable and authorization-aware.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Integrated Scope

This is one consolidated project, not separate source builds. Implement the following contributions as phases of the same artifact:

  • Add ASH-P7 calculations for row-level derived values.
  • Add ASH-P8 aggregates for relationship-level summaries.
  • Expose both through ASH-P9 filters, sorts, pagination, and explainable query behavior.

Real World Outcome

Build target: Build derived fields, aggregates, filters, sorts, and read models.

Implement comprehensive query capabilities with complex filters, sorting, pagination, and search functionality.

Build Ash Calculations, Aggregates, and Queries as one runnable, observable artifact. Build derived fields, aggregates, filters, sorts, and read models.

Produce an evidence bundle containing:

  • one deterministic happy-path run;
  • one rejected or malformed input with an explicit reason;
  • one injected failure or boundary condition;
  • a final verification result proving: generated queries are explainable and authorization-aware.
artifact=ash_calculations,_aggregates,_and_queries
happy_path=PASS
invalid_input=REJECTED explicit_reason=true
failure_boundary=EXERCISED recovery_evidence=true
mastery_check=PASS

The Core Question You Are Answering

How does Ash’s query DSL provide type-safe, efficient filtering that translates to optimized SQL while remaining composable and easy to use?

Concepts You Must Understand First

  1. Boolean algebra: AND, OR, NOT combinations
  2. SQL WHERE clauses: How filters translate
  3. Pagination strategies: Offset vs cursor/keyset tradeoffs

Questions to Guide Your Design

  1. How do you safely accept filter parameters from users?
  2. When should you use keyset vs offset pagination?
  3. How do you filter on related resources?
  4. What indexes do you need for your common filters?

Thinking Exercise

Design filters for a ticket search API:

  • Filter by status (multiple values)
  • Filter by priority
  • Filter by date range
  • Filter by reporter email (across relationship)
  • Full-text search on subject and description
  • Sort by any combination of fields

Write the Ash.Query code for each.

The Interview Questions They Will Ask

  1. “What filter predicates does Ash support?”
  2. “How do you prevent SQL injection in dynamic filters?”
  3. “Explain keyset vs offset pagination tradeoffs.”
  4. “How do you filter across relationships?”
  5. “How do you implement full-text search in Ash?”

Hints in Layers

Hint 1 - Starting Point: Basic filtering: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Hint 2 - Next Level: Dynamic filters from user input: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Hint 3 - Technical Details: Keyset pagination: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Hint 4 - Verification: Test with various filter combinations and verify SQL efficiency.

Books That Will Help

  • Main Book: Ash Framework documentation and Elixir in Action

Implementation Milestones

Integrated basic-to-advanced progression

  1. Add ASH-P7 calculations for row-level derived values.
  2. Add ASH-P8 aggregates for relationship-level summaries.
  3. Expose both through ASH-P9 filters, sorts, pagination, and explainable query behavior.

Milestone 1 — Contract and fixture: define one representative input, output, invariant, and failure case.

Milestone 2 — Core artifact: Build derived fields, aggregates, filters, sorts, and read models.

Milestone 3 — Failure behavior: add timeouts, invalid inputs, crashes, retries, or partitions appropriate to the project.

Milestone 4 — Evidence: automate the definition of done and record a reproducible result.

Testing Strategy

  • Unit checks: pure parsing, validation, transition, and formatting decisions.
  • Integration checks: the real process, database, socket, notebook, or framework boundary.
  • Failure checks: malformed input plus at least one crash, timeout, duplicate, overload, or partition scenario.
  • Acceptance check: independently demonstrate that generated queries are explainable and authorization-aware.
  • Avoid arbitrary sleeps; use messages, monitors, deterministic clocks, fixtures, and deadlines where applicable.

Common Pitfalls and Debugging

Problem 1: Happy-path output looks correct but failures disappear

  • Why: validation, effects, and reporting share one opaque step.
  • Fix: preserve tagged errors and source identity through every stage.
  • Quick test: inject one invalid record or failed dependency and verify an explicit result.

Problem 2: Tests merely repeat the implementation

  • Why: assertions reuse the same transformation or state assumptions.
  • Fix: check external invariants, golden fixtures, and observable failure behavior.
  • Quick test: introduce a deliberate ordering or boundary bug and confirm the test fails.

Definition of Done

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • Every merged source contribution is implemented as a phase of this one artifact, not as a separate project.
  • generated queries are explainable and authorization-aware.

Project 90: AshPhoenix Forms

Source: ASH-P10. Drive LiveView forms from Ash actions and nested relationships.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: Level 3: Service & Support
  • Curriculum Difficulty: Level 3: Applied
  • Knowledge Area: Declarative domain modeling
  • Software or Tool: Ash Framework
  • Main Book: Ash Framework documentation and Elixir in Action

What you will build: Drive LiveView forms from Ash actions and nested relationships.

Why it teaches the BEAM ecosystem: It makes you prove that UI validation reflects the resource contract rather than duplicating rules.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Drive LiveView forms from Ash actions and nested relationships.

Integrate Ash with Phoenix LiveView forms using AshPhoenix. Build interactive forms with validation, error handling, and nested data.

Build AshPhoenix Forms as one runnable, observable artifact. Drive LiveView forms from Ash actions and nested relationships.

Produce an evidence bundle containing:

  • one deterministic happy-path run;
  • one rejected or malformed input with an explicit reason;
  • one injected failure or boundary condition;
  • a final verification result proving: UI validation reflects the resource contract rather than duplicating rules.
artifact=ashphoenix_forms
happy_path=PASS
invalid_input=REJECTED explicit_reason=true
failure_boundary=EXERCISED recovery_evidence=true
mastery_check=PASS

The Core Question You Are Answering

How does AshPhoenix.Form bridge the gap between Ash’s action system and Phoenix’s form handling, enabling real-time validation and seamless data submission?

Concepts You Must Understand First

  1. Phoenix LiveView forms: to_form/1, form events
  2. Changesets: Ash uses changesets internally
  3. LiveView assigns: State management in LiveView

Questions to Guide Your Design

  1. When should validation run (on change vs on submit)?
  2. How do you display errors for nested forms?
  3. How do you handle forms for existing records (updates)?
  4. What happens when the actor context is needed?

Thinking Exercise

Design forms for:

  1. Create ticket (new form)
  2. Edit ticket (update form)
  3. Create ticket with comments (nested form)
  4. Assign ticket to user (select from relationship)

Sketch the LiveView structure for each.

The Interview Questions They Will Ask

  1. “How does AshPhoenix.Form differ from Ecto changesets in forms?”
  2. “How do you handle nested forms with AshPhoenix?”
  3. “How do you pass actor context to forms?”
  4. “What’s the validation flow for AshPhoenix forms?”
  5. “How do you handle form errors in LiveView?”

Hints in Layers

Hint 1 - Starting Point: Install AshPhoenix: mix igniter.install ash_phoenix. Create a basic form in LiveView.

Hint 2 - Next Level: Pass actor to forms: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Hint 3 - Technical Details: Nested forms for relationships: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Hint 4 - Verification: Test full flow: render form, enter invalid data, see errors, fix errors, submit successfully.

Books That Will Help

  • Main Book: Ash Framework documentation and Elixir in Action

Implementation Milestones

Milestone 1 — Contract and fixture: define one representative input, output, invariant, and failure case.

Milestone 2 — Core artifact: Drive LiveView forms from Ash actions and nested relationships.

Milestone 3 — Failure behavior: add timeouts, invalid inputs, crashes, retries, or partitions appropriate to the project.

Milestone 4 — Evidence: automate the definition of done and record a reproducible result.

Testing Strategy

  • Unit checks: pure parsing, validation, transition, and formatting decisions.
  • Integration checks: the real process, database, socket, notebook, or framework boundary.
  • Failure checks: malformed input plus at least one crash, timeout, duplicate, overload, or partition scenario.
  • Acceptance check: independently demonstrate that UI validation reflects the resource contract rather than duplicating rules.
  • Avoid arbitrary sleeps; use messages, monitors, deterministic clocks, fixtures, and deadlines where applicable.

Common Pitfalls and Debugging

Problem 1: Happy-path output looks correct but failures disappear

  • Why: validation, effects, and reporting share one opaque step.
  • Fix: preserve tagged errors and source identity through every stage.
  • Quick test: inject one invalid record or failed dependency and verify an explicit result.

Problem 2: Tests merely repeat the implementation

  • Why: assertions reuse the same transformation or state assumptions.
  • Fix: check external invariants, golden fixtures, and observable failure behavior.
  • Quick test: introduce a deliberate ordering or boundary bug and confirm the test fails.

Definition of Done

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • UI validation reflects the resource contract rather than duplicating rules.

Project 91: AshAuthentication Application

Source: ASH-P11. Add password and token strategies, confirmation, reset, sessions, and actor propagation.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: Level 3: Service & Support
  • Curriculum Difficulty: Level 3: Applied
  • Knowledge Area: Declarative domain modeling
  • Software or Tool: Ash Framework
  • Main Book: Ash Framework documentation and Elixir in Action

What you will build: Add password and token strategies, confirmation, reset, sessions, and actor propagation.

Why it teaches the BEAM ecosystem: It makes you prove that identity reaches every action and resists replay.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Add password and token strategies, confirmation, reset, sessions, and actor propagation.

Add user authentication to your application using AshAuthentication with password-based login, registration, and session management.

Build AshAuthentication Application as one runnable, observable artifact. Add password and token strategies, confirmation, reset, sessions, and actor propagation.

Produce an evidence bundle containing:

  • one deterministic happy-path run;
  • one rejected or malformed input with an explicit reason;
  • one injected failure or boundary condition;
  • a final verification result proving: identity reaches every action and resists replay.
artifact=ashauthentication_application
happy_path=PASS
invalid_input=REJECTED explicit_reason=true
failure_boundary=EXERCISED recovery_evidence=true
mastery_check=PASS

The Core Question You Are Answering

How does AshAuthentication extend the resource model to provide declarative authentication, and how does this integrate with Phoenix’s request lifecycle?

Concepts You Must Understand First

  1. Password hashing: Why we hash, common algorithms
  2. Session management: Cookies, tokens, expiration
  3. Phoenix plugs: How authentication middleware works

Questions to Guide Your Design

  1. Should you use session-based or token-based authentication?
  2. How do you handle “remember me” functionality?
  3. What password requirements should you enforce?
  4. How do you protect routes that require authentication?

Thinking Exercise

Design your authentication flow:

  1. Registration with email confirmation (optional)
  2. Login with password
  3. Password reset flow
  4. Session timeout behavior
  5. Multi-device session handling

Sketch the database fields and routes needed.

The Interview Questions They Will Ask

  1. “How does AshAuthentication integrate with Ash resources?”
  2. “What authentication strategies does AshAuthentication support?”
  3. “How do you protect routes in Phoenix with AshAuthentication?”
  4. “How are passwords stored securely?”
  5. “How do you implement ‘remember me’ functionality?”

Hints in Layers

Hint 1 - Starting Point: Install: mix igniter.install ash_authentication ash_authentication_phoenix

Hint 2 - Next Level: Add to User resource: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Hint 3 - Technical Details: Add Phoenix routes: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Hint 4 - Verification: Register a user, sign in, access protected route, sign out, verify cannot access protected route.

Books That Will Help

  • Main Book: Ash Framework documentation and Elixir in Action

Implementation Milestones

Milestone 1 — Contract and fixture: define one representative input, output, invariant, and failure case.

Milestone 2 — Core artifact: Add password and token strategies, confirmation, reset, sessions, and actor propagation.

Milestone 3 — Failure behavior: add timeouts, invalid inputs, crashes, retries, or partitions appropriate to the project.

Milestone 4 — Evidence: automate the definition of done and record a reproducible result.

Testing Strategy

  • Unit checks: pure parsing, validation, transition, and formatting decisions.
  • Integration checks: the real process, database, socket, notebook, or framework boundary.
  • Failure checks: malformed input plus at least one crash, timeout, duplicate, overload, or partition scenario.
  • Acceptance check: independently demonstrate that identity reaches every action and resists replay.
  • Avoid arbitrary sleeps; use messages, monitors, deterministic clocks, fixtures, and deadlines where applicable.

Common Pitfalls and Debugging

Problem 1: Happy-path output looks correct but failures disappear

  • Why: validation, effects, and reporting share one opaque step.
  • Fix: preserve tagged errors and source identity through every stage.
  • Quick test: inject one invalid record or failed dependency and verify an explicit result.

Problem 2: Tests merely repeat the implementation

  • Why: assertions reuse the same transformation or state assumptions.
  • Fix: check external invariants, golden fixtures, and observable failure behavior.
  • Quick test: introduce a deliberate ordering or boundary bug and confirm the test fails.

Definition of Done

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • identity reaches every action and resists replay.

Project 92: Ash Authorization Policies

Source: ASH-P12. Define actor-, action-, field-, and record-level policies.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: Level 3: Service & Support
  • Curriculum Difficulty: Level 3: Applied
  • Knowledge Area: Declarative domain modeling
  • Software or Tool: Ash Framework
  • Main Book: Ash Framework documentation and Elixir in Action

What you will build: Define actor-, action-, field-, and record-level policies.

Why it teaches the BEAM ecosystem: It makes you prove that policies constrain both actions and returned records across every interface.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Define actor-, action-, field-, and record-level policies.

Implement comprehensive authorization using Ash policies. Define who can do what with fine-grained access control based on roles, ownership, and resource state.

Build Ash Authorization Policies as one runnable, observable artifact. Define actor-, action-, field-, and record-level policies.

Produce an evidence bundle containing:

  • one deterministic happy-path run;
  • one rejected or malformed input with an explicit reason;
  • one injected failure or boundary condition;
  • a final verification result proving: policies constrain both actions and returned records across every interface.
artifact=ash_authorization_policies
happy_path=PASS
invalid_input=REJECTED explicit_reason=true
failure_boundary=EXERCISED recovery_evidence=true
mastery_check=PASS

The Core Question You Are Answering

How do Ash policies provide declarative, composable authorization that’s co-located with resources and automatically applied across all access paths?

Concepts You Must Understand First

  1. Authorization vs authentication: Auth = who you are, Authz = what you can do
  2. RBAC: Role-based access control patterns
  3. ABAC: Attribute-based access control

Questions to Guide Your Design

  1. What roles exist in your system?
  2. Which resources have ownership concepts?
  3. Should read actions filter or reject?
  4. What’s the default policy (allow or deny)?

Thinking Exercise

Design policies for a ticket system:

  • Users can read tickets they reported
  • Users can read tickets assigned to them
  • Managers can read all tickets in their department
  • Admins can read all tickets
  • Only managers can assign tickets
  • Users can only update their own ticket descriptions
  • Anyone can add comments, but only to tickets they can read

Write the policy definitions before implementing.

The Interview Questions They Will Ask

  1. “How do Ash policies differ from controller-based authorization?”
  2. “What’s the difference between authorize_if and forbid_if?”
  3. “How do you implement row-level security?”
  4. “How do you debug authorization failures?”
  5. “How do policies interact with read actions?”

Hints in Layers

Hint 1 - Starting Point: Add authorizer to resource: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Hint 2 - Next Level: Ownership-based policy: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Hint 3 - Technical Details: Custom check: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Hint 4 - Verification: Test each policy by calling actions with different actors and verifying expected behavior.

Books That Will Help

  • Main Book: Ash Framework documentation and Elixir in Action

Implementation Milestones

Milestone 1 — Contract and fixture: define one representative input, output, invariant, and failure case.

Milestone 2 — Core artifact: Define actor-, action-, field-, and record-level policies.

Milestone 3 — Failure behavior: add timeouts, invalid inputs, crashes, retries, or partitions appropriate to the project.

Milestone 4 — Evidence: automate the definition of done and record a reproducible result.

Testing Strategy

  • Unit checks: pure parsing, validation, transition, and formatting decisions.
  • Integration checks: the real process, database, socket, notebook, or framework boundary.
  • Failure checks: malformed input plus at least one crash, timeout, duplicate, overload, or partition scenario.
  • Acceptance check: independently demonstrate that policies constrain both actions and returned records across every interface.
  • Avoid arbitrary sleeps; use messages, monitors, deterministic clocks, fixtures, and deadlines where applicable.

Common Pitfalls and Debugging

Problem 1: Happy-path output looks correct but failures disappear

  • Why: validation, effects, and reporting share one opaque step.
  • Fix: preserve tagged errors and source identity through every stage.
  • Quick test: inject one invalid record or failed dependency and verify an explicit result.

Problem 2: Tests merely repeat the implementation

  • Why: assertions reuse the same transformation or state assumptions.
  • Fix: check external invariants, golden fixtures, and observable failure behavior.
  • Quick test: introduce a deliberate ordering or boundary bug and confirm the test fails.

Definition of Done

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • policies constrain both actions and returned records across every interface.

Project 93: Ash JSON:API and GraphQL Adapters

Sources: ASH-P13, ASH-P14. Expose one policy-protected domain through both adapters.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: Level 3: Service & Support
  • Curriculum Difficulty: Level 3: Applied
  • Knowledge Area: Declarative domain modeling
  • Software or Tool: Ash Framework
  • Main Book: Ash Framework documentation and Elixir in Action

What you will build: Expose one policy-protected domain through both adapters.

Why it teaches the BEAM ecosystem: It makes you prove that both enforce identical actions and authorization without bespoke controllers.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Integrated Scope

This is one consolidated project, not separate source builds. Implement the following contributions as phases of the same artifact:

  • Expose the policy-protected domain through ASH-P13 JSON:API first.
  • Add ASH-P14 GraphQL as a second adapter over the same actions, policies, and relationship rules.

Real World Outcome

Build target: Expose one policy-protected domain through both adapters.

# List tickets
GET /api/tickets
{
  "data": [
    {
      "type": "ticket",
      "id": "uuid",
      "attributes": {
        "subject": "Help needed",
        "status": "open"
      },
      "relationships": {
        "reporter": {
          "data": {"type": "user", "id": "uuid"}
        }
      }
    }
  ]
}

# Create ticket
POST /api/tickets
Content-Type: application/vnd.api+json
{
  "data": {
    "type": "ticket",
    "attributes": {
      "subject": "New issue",
      "description": "Details here"
    },
    "relationships": {
      "reporter": {
        "data": {"type": "user", "id": "uuid"}
      }
    }
  }
}

# Filter tickets
GET /api/tickets?filter[status]=open&filter[priority]=high

# Include relationships
GET /api/tickets?include=reporter,comments

# Get OpenAPI spec
GET /api/openapi.json

The Core Question You Are Answering

How does AshJsonApi translate Ash’s declarative resource model into a fully compliant JSON:API, and how do you customize the API behavior while maintaining spec compliance?

Concepts You Must Understand First

  1. JSON:API spec: Resource objects, relationships, compound documents
  2. REST conventions: HTTP methods, status codes
  3. OpenAPI/Swagger: API documentation formats

Questions to Guide Your Design

  1. Which actions should be exposed via API?
  2. How should relationships be serialized?
  3. What filters should be available?
  4. How do you version your API?

Thinking Exercise

Design your API endpoints:

  • GET /api/tickets (list, filtered)
  • POST /api/tickets (create)
  • GET /api/tickets/:id (show)
  • PATCH /api/tickets/:id (update)
  • DELETE /api/tickets/:id (delete)
  • GET /api/tickets/:id/comments (related)
  • POST /api/tickets/:id/comments (create related)

What JSON:API features will each use?

The Interview Questions They Will Ask

  1. “What is the JSON:API specification?”
  2. “How does AshJsonApi generate endpoints from resources?”
  3. “How do you handle authentication in AshJsonApi?”
  4. “How do you customize serialization?”
  5. “How do you generate OpenAPI documentation?”

Hints in Layers

Hint 1 - Starting Point: Install: mix igniter.install ash_json_api

Hint 2 - Next Level: Add to resource: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Hint 3 - Technical Details: Configure router: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Hint 4 - Verification: Test endpoints with curl or Postman. Verify JSON:API compliance with a validator.

Books That Will Help

  • Main Book: Ash Framework documentation and Elixir in Action

Implementation Milestones

Integrated basic-to-advanced progression

  1. Expose the policy-protected domain through ASH-P13 JSON:API first.
  2. Add ASH-P14 GraphQL as a second adapter over the same actions, policies, and relationship rules.

Milestone 1 — Contract and fixture: define one representative input, output, invariant, and failure case.

Milestone 2 — Core artifact: Expose one policy-protected domain through both adapters.

Milestone 3 — Failure behavior: add timeouts, invalid inputs, crashes, retries, or partitions appropriate to the project.

Milestone 4 — Evidence: automate the definition of done and record a reproducible result.

Testing Strategy

  • Unit checks: pure parsing, validation, transition, and formatting decisions.
  • Integration checks: the real process, database, socket, notebook, or framework boundary.
  • Failure checks: malformed input plus at least one crash, timeout, duplicate, overload, or partition scenario.
  • Acceptance check: independently demonstrate that both enforce identical actions and authorization without bespoke controllers.
  • Avoid arbitrary sleeps; use messages, monitors, deterministic clocks, fixtures, and deadlines where applicable.

Common Pitfalls and Debugging

Problem 1: Happy-path output looks correct but failures disappear

  • Why: validation, effects, and reporting share one opaque step.
  • Fix: preserve tagged errors and source identity through every stage.
  • Quick test: inject one invalid record or failed dependency and verify an explicit result.

Problem 2: Tests merely repeat the implementation

  • Why: assertions reuse the same transformation or state assumptions.
  • Fix: check external invariants, golden fixtures, and observable failure behavior.
  • Quick test: introduce a deliberate ordering or boundary bug and confirm the test fails.

Definition of Done

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • Every merged source contribution is implemented as a phase of this one artifact, not as a separate project.
  • both enforce identical actions and authorization without bespoke controllers.

Project 94: Ash PubSub and Notifiers

Source: ASH-P15. Emit resource-change notifications to tenant-safe topics and refresh from authoritative reads.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: Level 3: Service & Support
  • Curriculum Difficulty: Level 3: Applied
  • Knowledge Area: Declarative domain modeling
  • Software or Tool: Ash Framework
  • Main Book: Ash Framework documentation and Elixir in Action

What you will build: Emit resource-change notifications to tenant-safe topics and refresh from authoritative reads.

Why it teaches the BEAM ecosystem: It makes you prove that transaction timing and missed notifications are tested.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Emit resource-change notifications to tenant-safe topics and refresh from authoritative reads.

Implement real-time features using Ash notifiers and Phoenix.PubSub. Build live updates for ticket changes and new comments.

Build Ash PubSub and Notifiers as one runnable, observable artifact. Emit resource-change notifications to tenant-safe topics and refresh from authoritative reads.

Produce an evidence bundle containing:

  • one deterministic happy-path run;
  • one rejected or malformed input with an explicit reason;
  • one injected failure or boundary condition;
  • a final verification result proving: transaction timing and missed notifications are tested.
artifact=ash_pubsub_and_notifiers
happy_path=PASS
invalid_input=REJECTED explicit_reason=true
failure_boundary=EXERCISED recovery_evidence=true
mastery_check=PASS

The Core Question You Are Answering

How do Ash notifiers provide a declarative way to publish events on resource changes, and how do you build reactive UIs that respond to these events?

Concepts You Must Understand First

  1. Phoenix.PubSub: Pub/sub messaging in Elixir
  2. LiveView subscriptions: How LiveView handles external messages
  3. Topic patterns: Designing topic hierarchies

Questions to Guide Your Design

  1. What events should be published?
  2. What topic pattern makes sense?
  3. Who should receive which notifications?
  4. How do you handle notification payloads?

Thinking Exercise

Design your notification system:

  • Ticket created → notify all agents
  • Ticket updated → notify reporter and assignee
  • Comment added → notify ticket participants
  • Ticket assigned → notify new assignee

What topics and patterns do you need?

The Interview Questions They Will Ask

  1. “How does Ash’s PubSub notifier work?”
  2. “What’s the difference between publish and publish_all?”
  3. “How do you handle notifications within transactions?”
  4. “How do you design topic patterns for multi-tenant apps?”
  5. “How do you test real-time notifications?”

Hints in Layers

Hint 1 - Starting Point: Add notifier to resource: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Hint 2 - Next Level: Configure publications: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Hint 3 - Technical Details: Subscribe in LiveView: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Hint 4 - Verification: Open two browser tabs, create/update in one, verify changes appear in other.

Books That Will Help

  • Main Book: Ash Framework documentation and Elixir in Action

Implementation Milestones

Milestone 1 — Contract and fixture: define one representative input, output, invariant, and failure case.

Milestone 2 — Core artifact: Emit resource-change notifications to tenant-safe topics and refresh from authoritative reads.

Milestone 3 — Failure behavior: add timeouts, invalid inputs, crashes, retries, or partitions appropriate to the project.

Milestone 4 — Evidence: automate the definition of done and record a reproducible result.

Testing Strategy

  • Unit checks: pure parsing, validation, transition, and formatting decisions.
  • Integration checks: the real process, database, socket, notebook, or framework boundary.
  • Failure checks: malformed input plus at least one crash, timeout, duplicate, overload, or partition scenario.
  • Acceptance check: independently demonstrate that transaction timing and missed notifications are tested.
  • Avoid arbitrary sleeps; use messages, monitors, deterministic clocks, fixtures, and deadlines where applicable.

Common Pitfalls and Debugging

Problem 1: Happy-path output looks correct but failures disappear

  • Why: validation, effects, and reporting share one opaque step.
  • Fix: preserve tagged errors and source identity through every stage.
  • Quick test: inject one invalid record or failed dependency and verify an explicit result.

Problem 2: Tests merely repeat the implementation

  • Why: assertions reuse the same transformation or state assumptions.
  • Fix: check external invariants, golden fixtures, and observable failure behavior.
  • Quick test: introduce a deliberate ordering or boundary bug and confirm the test fails.

Definition of Done

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • transaction timing and missed notifications are tested.

Project 95: Ash Resource Test Harness

Source: ASH-P16. Test actions, calculations, aggregates, policies, notifiers, and constraints.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: Level 3: Service & Support
  • Curriculum Difficulty: Level 3: Applied
  • Knowledge Area: Declarative domain modeling
  • Software or Tool: Ash Framework
  • Main Book: Ash Framework documentation and Elixir in Action

What you will build: Test actions, calculations, aggregates, policies, notifiers, and constraints.

Why it teaches the BEAM ecosystem: It makes you prove that regressions are caught without asserting private framework internals.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Test actions, calculations, aggregates, policies, notifiers, and constraints.

Comprehensive test suites for your Ash resources covering actions, policies, calculations, and integration scenarios.

Build Ash Resource Test Harness as one runnable, observable artifact. Test actions, calculations, aggregates, policies, notifiers, and constraints.

Produce an evidence bundle containing:

  • one deterministic happy-path run;
  • one rejected or malformed input with an explicit reason;
  • one injected failure or boundary condition;
  • a final verification result proving: regressions are caught without asserting private framework internals.
artifact=ash_resource_test_harness
happy_path=PASS
invalid_input=REJECTED explicit_reason=true
failure_boundary=EXERCISED recovery_evidence=true
mastery_check=PASS

The Core Question You Are Answering

What testing patterns are effective for Ash applications, and how do you test declarative resource definitions while avoiding testing the framework itself?

Concepts You Must Understand First

  1. ExUnit basics: Test structure, assertions, setup
  2. DataCase: Database test isolation
  3. Test factories: Generating test data

Questions to Guide Your Design

  1. What needs testing vs what’s framework behavior?
  2. How do you generate consistent test data?
  3. How do you test policies in isolation?
  4. How do you test async behavior?

Thinking Exercise

Design test cases for:

  1. Ticket creation (success, validation errors)
  2. Ticket state transitions (valid, invalid)
  3. Policy enforcement (owner, admin, stranger)
  4. Calculations (with various inputs)
  5. Aggregates (correct counts)

What fixtures/factories do you need?

The Interview Questions They Will Ask

  1. “What should you test in an Ash resource?”
  2. “How do you test policies effectively?”
  3. “How do you set up test data for Ash tests?”
  4. “Should you test calculations that use expressions?”
  5. “How do you test real-time notifications?”

Hints in Layers

Hint 1 - Starting Point: Set up DataCase with Ash-aware database wrapping per AshPostgres testing guide.

Hint 2 - Next Level: Create test factories: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Hint 3 - Technical Details: Test assertions: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Hint 4 - Verification: Run mix test and ensure all tests pass. Check coverage.

Books That Will Help

  • Main Book: Ash Framework documentation and Elixir in Action

Implementation Milestones

Milestone 1 — Contract and fixture: define one representative input, output, invariant, and failure case.

Milestone 2 — Core artifact: Test actions, calculations, aggregates, policies, notifiers, and constraints.

Milestone 3 — Failure behavior: add timeouts, invalid inputs, crashes, retries, or partitions appropriate to the project.

Milestone 4 — Evidence: automate the definition of done and record a reproducible result.

Testing Strategy

  • Unit checks: pure parsing, validation, transition, and formatting decisions.
  • Integration checks: the real process, database, socket, notebook, or framework boundary.
  • Failure checks: malformed input plus at least one crash, timeout, duplicate, overload, or partition scenario.
  • Acceptance check: independently demonstrate that regressions are caught without asserting private framework internals.
  • Avoid arbitrary sleeps; use messages, monitors, deterministic clocks, fixtures, and deadlines where applicable.

Common Pitfalls and Debugging

Problem 1: Happy-path output looks correct but failures disappear

  • Why: validation, effects, and reporting share one opaque step.
  • Fix: preserve tagged errors and source identity through every stage.
  • Quick test: inject one invalid record or failed dependency and verify an explicit result.

Problem 2: Tests merely repeat the implementation

  • Why: assertions reuse the same transformation or state assumptions.
  • Fix: check external invariants, golden fixtures, and observable failure behavior.
  • Quick test: introduce a deliberate ordering or boundary bug and confirm the test fails.

Definition of Done

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • regressions are caught without asserting private framework internals.

Project 96: Ash Help Desk Application

Source: ASH-P17. Integrate tickets, users, policies, authentication, APIs, forms, and notifications.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: Level 3: Service & Support
  • Curriculum Difficulty: Level 3: Applied
  • Knowledge Area: Declarative domain modeling
  • Software or Tool: Ash Framework
  • Main Book: Ash Framework documentation and Elixir in Action

What you will build: Integrate tickets, users, policies, authentication, APIs, forms, and notifications.

Why it teaches the BEAM ecosystem: It makes you prove that UI and API share one resource contract end to end.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Integrate tickets, users, policies, authentication, APIs, forms, and notifications.

A fully functional help desk with:

Web Interface (Phoenix LiveView):

  • User registration and authentication
  • Dashboard showing ticket counts and status
  • Ticket list with filtering, sorting, pagination
  • Ticket detail with comments and history
  • Real-time updates when tickets change
  • Agent assignment interface
  • Manager reporting dashboard

JSON:API:

  • Full CRUD for tickets via REST
  • Relationship handling
  • Filtering and pagination
  • OpenAPI documentation

GraphQL API:

  • Queries for tickets, users
  • Mutations for all actions
  • Subscriptions for real-time

Authorization:

  • Customers see only their tickets
  • Agents see assigned tickets
  • Managers see all tickets in department
  • Admins see everything

The Core Question You Are Answering

How do you architect a production Ash application that combines multiple domains, interfaces, and real-time features while maintaining code quality and testability?

Application Requirements

Users:

  • Registration, login, password reset
  • Roles: customer, agent, manager, admin
  • Profile management

Tickets:

  • Create, update, close, reopen
  • Priority levels
  • Status workflow (open → in_progress → resolved → closed)
  • Assignment to agents
  • SLA tracking

Comments:

  • Add comments to tickets
  • Internal notes (visible only to agents)
  • File attachments (optional)

Departments:

  • Organize agents and tickets
  • Department managers
  • Cross-department escalation

Reports:

  • Ticket volume by time period
  • Resolution time metrics
  • Agent performance

Concepts You Must Understand First

  1. Domain modeling for a real application
  2. Complex policy requirements
  3. Multiple user interfaces (web, API)
  4. Real-time features
  5. Production considerations

Questions to Guide Your Design

  1. How do you structure domains for this application?
  2. What resources belong in each domain?
  3. How do tickets flow through the workflow?
  4. What policies enforce role-based access?
  5. What real-time updates are needed?

Thinking Exercise

Before coding, design:

  1. Domain structure (which resources in which domain)
  2. Resource relationships (ER diagram)
  3. Action list for each resource
  4. Policy matrix (who can do what)
  5. API design (endpoints/queries)
  6. Real-time event design

The Interview Questions They Will Ask

  1. “What is the hardest invariant in Ash Help Desk Application, and where is it enforced?”
  2. “Which parts should be pure transformations and which require BEAM processes?”
  3. “How does the design behave under malformed input, process failure, or retry?”
  4. “What test or runtime evidence proves: UI and API share one resource contract end to end.”

Hints in Layers

Hint 1 - Starting Point: Create separate domains: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Hint 2 - Next Level: Use generators to scaffold:

mix ash.gen.resource MyApp.Accounts.User
mix ash.gen.resource MyApp.Support.Ticket --extend postgres
mix ash.gen.resource MyApp.Support.Comment --extend postgres

Hint 3 - Technical Details: Structure your LiveView:

lib/my_app_web/live/
├── ticket_live/
│   ├── index.ex
│   ├── show.ex
│   ├── form_component.ex
│   └── comment_component.ex
├── dashboard_live.ex
└── auth/
    ├── login_live.ex
    └── register_live.ex

Hint 4 - Verification: Create comprehensive integration tests covering main user flows.

Books That Will Help

  • Main Book: Ash Framework documentation and Elixir in Action

Implementation Milestones

  1. Week 1: Core resources (User, Ticket, Comment)
  2. Week 2: Authentication, authorization policies
  3. Week 3: Phoenix LiveView interface
  4. Week 4: APIs (JSON:API, GraphQL)
  5. Week 5: Real-time updates, refinement, testing

Testing Strategy

  • Unit checks: pure parsing, validation, transition, and formatting decisions.
  • Integration checks: the real process, database, socket, notebook, or framework boundary.
  • Failure checks: malformed input plus at least one crash, timeout, duplicate, overload, or partition scenario.
  • Acceptance check: independently demonstrate that UI and API share one resource contract end to end.
  • Avoid arbitrary sleeps; use messages, monitors, deterministic clocks, fixtures, and deadlines where applicable.

Common Pitfalls and Debugging

Problem Cause Fix
Circular domain dependencies Resources referencing across domains Use string references, reorganize domains
N+1 queries Missing relationship preloading Use Ash.Query.load/2
Policy confusion Complex rules interacting Test policies in isolation first
Real-time not working Transaction timing Notifications are sent after transaction
Slow tests Not using async Use async: true with proper isolation

Definition of Done

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • UI and API share one resource contract end to end.

Phase 5 - Livebook Applications and Data Portability

Project 97: Interactive SLA Command Center

Source: LIVE-P7. Build VegaLite views, event-driven filters, responsive state, and freshness-aware analysis.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: SQL; JavaScript only for optional custom visualization
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: Level 3: Service & Support
  • Curriculum Difficulty: Level 3: Applied
  • Knowledge Area: Operational analytics, event-driven UI, visualization
  • Software or Tool: Livebook, Kino, Explorer, VegaLite, KinoVegaLite
  • Main Book: Data Science for Business

What you will build: Build VegaLite views, event-driven filters, responsive state, and freshness-aware analysis.

Why it teaches the BEAM ecosystem: It makes you prove that visual interactions never obscure stale or partial data.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Build VegaLite views, event-driven filters, responsive state, and freshness-aware analysis.

Create an interactive SLA command center for a synthetic multi-service request dataset. The dashboard must include:

  1. A source strip showing dataset snapshot, event-time coverage, last refresh, current data age, and request generation.
  2. Filters for period, service, severity, and region.
  3. KPI cards for request count, availability, SLA-breach rate, and p50/p95/p99 latency.
  4. A bounded latency histogram or distribution view.
  5. A breach trend chart with explicit time-bucket and denominator semantics.
  6. A bounded drilldown table containing only safe, useful operational fields.
  7. An update loop that discards obsolete generations.
  8. Explicit UI variants for initial, loading, ready, empty, partial, stale, and failed states.
  9. A deterministic slow-query simulation that proves generation 17 cannot overwrite generation 18.
  10. Evidence that two clients have independent filters and generations where intended.

Use Explorer for transformation and aggregation, Kino controls for interaction, Kino frames for updates, and VegaLite/KinoVegaLite for declarative charts. A static fixture is sufficient; the difficulty lies in state truthfulness, not data acquisition.

The ready state should include a compact evidence panel like:

SERVICE: checkout-api       WINDOW: last 24 hours
Requests: 8,241,993         Availability: 99.94%
SLA breaches: 0.37%         p50 / p95 / p99: 42 / 211 / 804 ms
Data age: 47 seconds        Status: CURRENT
Filter generation: 18
Late result generation 17: discarded

The empty state must not render perfect service:

SERVICE: training-unused-service   WINDOW: last 15 minutes
Eligible requests: 0
Availability: N/A
Latency percentiles: N/A
Status: EMPTY_POPULATION
Data age: 31 seconds

A partial state may resemble:

Generation: 22
KPI cards: READY
Breach trend: READY
Latency histogram: FAILED (invalid bucket contract)
Drilldown: TRUNCATED at 100 rows
Overall status: PARTIAL

An operator can filter service behavior, understand what each KPI measures, and trust that the view corresponds to the latest accepted request. Rapid filter changes never show an older result as current. Empty traffic, stale sources, partial component failures, and hard failures are visibly distinct.

A reviewer can inspect the generation transcript and see:

  • when each request was accepted;
  • when loading began;
  • which computation finished first;
  • why an old completion was discarded;
  • how much data was aggregated and rendered;
  • which freshness and metric contracts governed the result.

The outcome is a defensible lightweight operational interface and a reusable concurrency pattern for Livebook applications.

The Core Question You Are Answering

How do you keep an analytical view truthful while users and data change faster than computation?

Your answer must cover semantic truth (metric contract, population, freshness) and temporal truth (the rendered generation is the newest accepted request). Both are necessary.

Concepts You Must Understand First

Before implementation, explain:

  1. The numerator, denominator, window, and empty behavior for availability and breach rate.
  2. The difference between p99 and maximum latency.
  3. Why global percentiles cannot usually be reconstructed by averaging subgroup percentiles.
  4. How a control event becomes an owned request generation.
  5. Why late-result checks are required even when cancellation exists.
  6. How many points and rows each dashboard component may render.
  7. How stale and partial differ from failed.

Questions to Guide Your Design

  • Is the time window based on event time, ingestion time, or processing time?
  • Which HTTP or domain-specific outcomes count as available?
  • Are maintenance windows excluded, and how is that visible?
  • What happens to requests with missing latency or unknown service identity?
  • Are filters applied atomically as one coherent request?
  • Which process owns the current generation for each client?
  • Can two clients affect one another’s selected filters or frame?
  • What is cancelled, and what is merely ignored when obsolete?
  • How do you cap series when a region or service dimension has high cardinality?
  • How do you indicate chart truncation or grouped “other” values?
  • When source age crosses its threshold during a displayed result, does the state transition to stale without a new filter event?

Thinking Exercise

Draw a timeline for this sequence:

t0: generation 17 accepted; forced computation delay = 900 ms
t1: generation 18 accepted; computation delay = 100 ms
t2: generation 18 finishes
t3: generation 17 finishes

For every time, record the owner state, active tasks, frame status, and transcript entry. Then add a client B whose generation numbering is independent. Finally, make generation 18 return zero eligible rows and decide which KPIs are N/A, zero, or still meaningful.

The Interview Questions They Will Ask

  1. How do you prevent stale asynchronous work from overwriting current UI state?
  2. What is the difference between cancellation and late-result suppression?
  3. How would you define and validate an availability metric?
  4. Why are percentiles difficult to aggregate across partitions?
  5. How do you distinguish an empty result from a failed data source?
  6. What limits would you place on an interactive operational dashboard?

Hints in Layers

Hint 1 — Compute statically first. Prove KPIs and fixture expectations with no controls.

Hint 2 — Use one coherent request. Combine the current control values, validate them, then allocate a generation.

Hint 3 — Tag everything. Worker result, frame state, transcript event, and error must carry client and generation.

Hint 4 — Accept updates at one gate. Only the state owner compares a result with the current generation and authorizes rendering.

Hint 5 — Bound before encoding. The Vega-Lite dataset should already contain only intended bins or buckets.

Hint 6 — Empty is a state. Keep population count and KPI nullability in the result contract.

Pseudocode sketch:

request = normalize_controls(current_values)
generation = owner.accept(request)
frame.render(loading(generation))
worker.start(request, generation)

when result arrives:
  if owner.is_current?(result.client_id, result.generation):
    frame.render(classify_and_present(result))
  else:
    transcript.record(discarded(result.generation))

Books That Will Help

Topic Book Suggested focus
Visual encodings Fundamentals of Data Visualization — Claus O. Wilke Scales, distributions, uncertainty
Dashboard design The Big Book of Dashboards — Wexler, Shaffer, Cotgreave Choosing views for operational questions
Concurrency and state Elixir in Action — Saša Jurić Processes, message passing, state ownership
Reliability metrics Site Reliability Engineering — Beyer et al. SLOs, monitoring, alerting
Streaming systems Designing Data-Intensive Applications — Martin Kleppmann Event time, stream processing, derived views

Implementation Milestones

Phase 1 — Metric and fixture contract (3–4 hours)

  • Define source coverage, freshness, eligible population, KPI formulas, and empty behavior.
  • Create fixture truth for ready, empty, stale, and tail-latency cases.
  • Validate static results.

Phase 2 — Static dashboard and bounded encodings (3–5 hours)

  • Design KPI cards, histogram, trend, and drilldown.
  • Choose explicit Vega-Lite field types, units, bins, and scales.
  • Prove chart and table payload bounds.

Phase 3 — Event ownership and generations (4–6 hours)

  • Combine controls into coherent requests.
  • Add per-client generation ownership and loading state.
  • Tag asynchronous results and suppress obsolete completions.

Phase 4 — Complete state model (3–5 hours)

  • Implement initial, loading, ready, empty, partial, stale, and failed rendering.
  • Surface component failures, truncation, and freshness consistently.
  • Bound transition history.

Phase 5 — Concurrency and soak verification (3–5 hours)

  • Run deterministic generation 17/18 inversion.
  • Verify two-client isolation.
  • Run a 30-minute rapid-interaction soak and inspect process, memory, frame, and payload behavior.

Testing Strategy

6.1 Test Categories

Test the metric contract, asynchronous generation ordering, complete UI state model, bounded rendering, and multi-client isolation separately. Their combination proves that the dashboard is numerically meaningful and remains correct under interaction and concurrency.

6.2 Critical Test Cases

Metric tests

  • Hand-calculate a tiny fixture and compare request count, availability, breach rate, p50, p95, and p99.
  • Verify window boundaries use one explicit inclusive/exclusive convention.
  • Verify missing latency and excluded traffic follow the declared population rules.
  • Verify an empty eligible population produces N/A where the denominator is zero.
  • Verify the same selected population feeds KPI, histogram, trend, and drilldown.

Race and generation tests

  1. Force generation 17 to take 900 ms.
  2. Accept generation 18 after 50 ms and let it finish in 100 ms.
  3. Assert generation 18 renders ready.
  4. Let generation 17 finish.
  5. Assert the frame remains generation 18 and transcript records 17 as discarded.
  6. Repeat around cancellation timing boundaries.

State matrix

Condition Expected state Required evidence
No request yet INITIAL Instructions and source identity
Current request running LOADING Generation and filters
Complete current data READY KPIs, age, population
Zero eligible observations EMPTY Successful query plus zero population
Some components usable PARTIAL Component success/failure list
Source age over threshold STALE Age, threshold, last refresh
Source/computation unusable FAILED Safe error classification and request ID

Boundedness tests

  • Generate many services and verify series cap/grouping.
  • Generate dense events and verify fixed histogram bins and trend buckets.
  • Generate more drilldown matches than allowed and verify truncation indicator.
  • Verify transition log retention remains fixed under thousands of events.
  • Inspect browser payload and runtime memory over the soak test.

Multi-client tests

  • Client A and B choose different services.
  • Each receives independent current generation and result.
  • A’s late result cannot overwrite B’s frame or vice versa.
  • Disconnect one client and verify its tasks/state are cleaned up according to policy.

6.3 Test Data

Keep a hand-calculated fixture for exact KPI assertions, deterministic slow and fast generations for race tests, an empty population, stale timestamps, component failures, high-cardinality services, dense events, and two named client sessions. Seed every fixture so failures can be replayed byte-for-byte.

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Problem: Old data flashes after rapid filter changes

  • Why: workers update a shared frame directly or results lack generations.
  • Evidence: rendered generation decreases or filter label and data disagree.
  • Fix: route all completions through one owner and accept only the current client generation.
  • Quick test: deterministic slow generation 17 followed by fast generation 18.

Problem: Empty traffic displays 100% availability

  • Why: a zero denominator was coerced to a success ratio.
  • Evidence: eligible request count is zero while availability is numeric.
  • Fix: encode empty behavior in the metric contract and render N/A with EMPTY state.

Problem: Browser slows during a long session

  • Why: raw points, unbounded table rows, retained frames, event logs, or orphan tasks accumulate.
  • Evidence: payload size, process count, or memory grows with every interaction.
  • Fix: aggregate before rendering, update one frame, cap logs, and clean obsolete/client-disconnected work.

Problem: p95 changes unexpectedly when grouped

  • Why: subgroup percentiles were averaged or populations differ between views.
  • Evidence: exact reference calculation disagrees with grouped calculation.
  • Fix: compute from the selected population or use a documented mergeable quantile sketch.

Problem: Dashboard shows ready with one broken chart

  • Why: component failures are swallowed or overall status is hard-coded.
  • Evidence: missing visualization with no component error list.
  • Fix: classify per-component outcomes and derive PARTIAL when usable evidence remains.

Problem: Two users change each other’s filters

  • Why: controls, generation, or frame are globally shared despite per-client intent.
  • Evidence: one client’s event changes another client’s rendered service.
  • Fix: key state by client/session and define cleanup; or explicitly label a deliberately shared dashboard.

7.2 Debugging Strategies

Trace one client request through normalized filters, allocated generation, worker start, completion, acceptance or discard, and frame update. Always display the rendered generation and population contract in diagnostic mode. Reproduce races with deterministic delays before reaching for timing-dependent logging.

7.3 Performance Traps

Raw event rendering, unbounded series, growing transition histories, orphan workers, repeated full-data scans, and large frame payloads can exhaust either runtime or browser. Measure both server memory and encoded browser payload, cap retained state, and verify obsolete generations cannot continue expensive work indefinitely.

Definition of Done

Submit the Livebook notebook, deterministic fixture, metric-contract table, state-transition diagram, race-test transcript, boundedness measurements, and 30-minute soak report.

The submission is complete when:

  • KPI cards identify units, population, window, and freshness.
  • Availability and breach denominators are documented and tested.
  • p50/p95/p99 match a hand-calculated reference fixture.
  • Charts use bounded aggregates rather than raw unbounded events.
  • Drilldown is capped and visibly marked when truncated.
  • Every accepted filter request receives a client-scoped generation.
  • Late generation 17 is demonstrably discarded after generation 18 renders.
  • Initial, loading, ready, empty, partial, stale, and failed states are all demonstrated.
  • Empty data never appears as perfect availability.
  • Multi-client state behaves according to the stated design.
  • The 30-minute soak shows no unbounded task, frame, log, payload, or memory growth.
  • A fresh runtime reproduces the fixture metrics and race behavior.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • visual interactions never obscure stale or partial data.

Project 98: Portable Cloud Data Lake Lab

Source: LIVE-P8. Move the tabular pipeline across local files and S3-compatible storage using explicit file references and secrets.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: SQL; Python integration for interoperability checks
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: Level 3: Service & Support
  • Curriculum Difficulty: Level 3: Applied
  • Knowledge Area: File systems, object storage, data portability, security
  • Software or Tool: Livebook file references, Kino.FS, Explorer, S3-compatible storage
  • Main Book: Designing Data-Intensive Applications, Second Edition

What you will build: Move the tabular pipeline across local files and S3-compatible storage using explicit file references and secrets.

Why it teaches the BEAM ecosystem: It makes you prove that relocation preserves data identity, replay, and provenance.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Move the tabular pipeline across local files and S3-compatible storage using explicit file references and secrets.

Create a Livebook notebook that reads the same seven-day mobility dataset through two modes:

  1. Local snapshot mode: a notebook-managed file/directory reference representing an immutable training snapshot.
  2. S3-compatible mode: a training bucket or shared file storage containing equivalent date-partitioned Parquet objects.

Both modes must return one SourceResult contract and feed the same downstream transformation. The notebook will select the date range 2026-07-01 through 2026-07-07, project a fixed subset of columns, compute a bounded daily/zone summary, and compare the modes.

Provide a source panel containing logical reference, resolved source kind, version/checksum, cache status and age, selected partitions, object/file count, bytes read or best available estimate, and read-only status. Include an explicitly declared local-snapshot fallback for object-store unavailability; when used, label it CACHED_FALLBACK and never CURRENT.

The equivalence report should resemble:

PORTABILITY CHECK
Local source summary checksum:  8f0d...c21
S3 source summary checksum:     8f0d...c21
Schema equivalence: PASS
Row-count equivalence: PASS
Selected partitions: date=2026-07-01..2026-07-07
Rows collected: 4,218
Secret names used: [LB_TRAINING_S3_ACCESS] (values never displayed)

The source evidence panel might show:

logical_reference: mobility_training
source_mode: s3_training
source_state: CURRENT
object_version_manifest: sha256:example-redacted
selected_partitions: 7 / 365
projected_columns: 6 / 24
objects_read: 7
bytes_read_or_estimated: 41.8 MiB
cache_status: MISS
resolved_input_policy: READ_ONLY

When the object store is disabled:

requested_source: s3_training
remote_status: UNAVAILABLE
fallback: local_snapshot
fallback_status: CACHED_FALLBACK
snapshot_age: 26 hours
coverage: 2026-07-01..2026-07-07
current_claim: false

Another operator can open the notebook on a different machine, choose a configured source, and obtain the same bounded summary without editing analytical cells. They can tell whether the result came from current object storage, an immutable local snapshot, or a stale fallback.

A reviewer can independently verify:

  • logical and physical source identities;
  • selected partitions and projected columns;
  • schema, row-count, range, and checksum equivalence;
  • cache/fallback state and freshness;
  • absence of hard-coded paths and credential values;
  • reproducibility from a clean runtime and second environment.

The notebook becomes a portable analytical method with a visible data-access contract, not a machine-specific script.

The Core Question You Are Answering

What must remain stable for an analytical method to move between a local file, object storage, and another operator’s machine?

Your answer should separate stable logical contracts—schema, selected snapshot, partitions, transformations, canonical result—from expected environmental differences—resolved path, cache location, network latency, and provider metadata.

Concepts You Must Understand First

Before implementation, explain:

  1. The difference between a logical file reference and a resolved local path.
  2. Why Kino.FS.file_path/1 can involve a download and why the result is read-only.
  3. How column projection and partition pruning reduce remote work.
  4. Why an ETag is not always a portable content checksum.
  5. How a cache can be valid but stale.
  6. What secret references and Livebook stamps do and do not guarantee.
  7. Why identical row counts do not prove source equivalence.

Questions to Guide Your Design

  • What immutable identity binds the local snapshot to the object dataset?
  • Which timezone determines a date=... partition?
  • Is the end of the selected date range inclusive or exclusive?
  • How does the adapter report a missing partition versus an empty partition?
  • Which columns are required for the shared summary, and can the reader prove projection?
  • What evidence is available for actual bytes read versus only estimated bytes?
  • When is fallback permitted, and how old may it be?
  • What happens if a cache entry has the right logical name but the wrong manifest checksum?
  • How are provider differences isolated without erasing useful source evidence?
  • Which notebook modification invalidates a stamp, and how should the operator recover safely?
  • Can another environment use a different storage provider while preserving the same SourceResult contract?

Thinking Exercise

Trace the lifecycle of mobility_training through five situations:

  1. A cold local-file resolution.
  2. A warm local cache hit.
  3. A successful seven-partition S3 read.
  4. An unauthorized S3 request with a valid local snapshot available.
  5. A modified notebook whose prior secret/file permissions are no longer approved.

For each, record logical reference, physical resolution, credential involvement, cache state, source identity, freshness, terminal state, and whether analysis may proceed. Then decide whether an unauthorized remote request should automatically fall back. Defend your answer in terms of fail-closed behavior and operator visibility.

The Interview Questions They Will Ask

  1. How would you make a notebook portable across local and object-backed data?
  2. What is the difference between partition pruning and filtering after a full read?
  3. Why should a resolved notebook file path be treated as read-only?
  4. How do you prove two physical sources represent the same logical snapshot?
  5. What metadata is required for a trustworthy cached fallback?
  6. What security guarantees do secret stores and notebook permission stamps provide—and not provide?

Hints in Layers

Hint 1 — Define the adapter contract first. Make downstream code depend on SourceResult, not paths or buckets.

Hint 2 — Use a manifest. Bind partitions, sizes, schemas, and content checksums to one immutable snapshot identity.

Hint 3 — Derive partitions from the validated window. Do not list the whole bucket and filter filenames after download.

Hint 4 — Project early. Request only the six columns required by the summary.

Hint 5 — Compare canonical outputs. Sort the bounded summary by stable keys and normalize representation before hashing.

Hint 6 — Fail visibly. Never turn an authorization error into a quiet cache hit.

Pseudocode sketch:

request = validate_source_request(control_state)
partitions = partition_plan(request.window)
result = adapter_for(request.mode).resolve(request, partitions)
assert_identity_and_completeness(result)
summary = result.data |> shared_lazy_pipeline |> collect_bounded
evidence = summarize_source_and_checksum(result, summary)

if remote failure and explicit fallback policy permits:
  fallback = validate_local_snapshot_against_expected_manifest()
  mark_state(fallback, CACHED_FALLBACK, not_current=true)

Books That Will Help

Topic Book Suggested focus
Storage and data systems Designing Data-Intensive Applications — Martin Kleppmann Encoding, batch data, replication, derived data
Data engineering Fundamentals of Data Engineering — Reis and Housley Storage abstraction, data lifecycle, orchestration
Cloud architecture Building Evolutionary Architectures — Ford, Parsons, Kua Fitness functions and portability tradeoffs
Reproducible analysis The Practice of Reproducible Research — Kitzes, Turek, Deniz Provenance, environment, artifacts

Implementation Milestones

Phase 1 — Dataset and immutable manifest (3–4 hours)

  • Build partitioned synthetic Parquet fixtures.
  • Define logical schema, coverage, partition keys, sizes, and checksums.
  • Create the local immutable snapshot and remote training copy.

Phase 2 — Common source contract (3–5 hours)

  • Define SourceRequest, SourceIdentity, and SourceResult.
  • Implement local file-reference resolution and evidence.
  • Implement S3-compatible resolution using approved secret/storage configuration.

Phase 3 — Pruned shared analysis (3–5 hours)

  • Derive exact partitions from the selected date window.
  • Project required columns and build one shared lazy pipeline.
  • Bound collection and emit read-size evidence.

Phase 4 — Equivalence and fallback (3–5 hours)

  • Compare schema, counts, range, profiles, partition set, and canonical checksum.
  • Add explicit cache/fallback states and freshness labels.
  • Disable remote access and verify fallback semantics.

Phase 5 — Portability and failure verification (2–4 hours)

  • Test unauthorized, unavailable, corrupt, missing-partition, and partial-read cases.
  • Clear caches and run from a fresh runtime.
  • Run in a second environment with only documented logical configuration.

Testing Strategy

6.1 Test Categories

The suite separates adapter contract, cross-source equivalence, pruning, failure classification, secret leakage, and fresh-environment portability. No single successful checksum can substitute for all six forms of evidence.

6.2 Critical Test Cases

Contract tests

  • Local and remote adapters return the same normalized schema and required metadata fields.
  • Neither adapter exposes provider-specific path details to downstream analytical cells.
  • Returned local paths are never opened for mutation by notebook logic.
  • Required source identity and freshness fields are never optional in a successful result.

Equivalence tests

Check Expected result
Normalized schema Equal
Selected partition set Equal
Row count Equal
Event-time minimum/maximum Equal
Key null/distinct profile Equal within exact fixture contract
Canonical bounded summary checksum Equal
Physical resolved path Expected to differ; excluded from logical equality

Pruning tests

  • Select seven of 365 date partitions and verify only seven objects/files are requested.
  • Request six of 24 columns and verify the projection plan contains only those columns where supported.
  • Compare full-year and seven-day read-size evidence.
  • Fail the test if a source adapter lists/downloads the entire dataset before filtering.

Failure matrix

Injected condition Expected state
Endpoint unreachable UNAVAILABLE; optional explicit fallback
Invalid/expired credential UNAUTHORIZED; never mislabeled unavailable
Missing selected partition INCOMPLETE or declared PARTIAL
Manifest checksum mismatch CORRUPT_OR_WRONG_SNAPSHOT
Cache older than threshold STALE_CACHE
Truncated object/read PARTIAL_READ or CORRUPT
Modified notebook loses resource approval PERMISSION_REQUIRED

Secret leakage tests

  • Use a unique canary training secret.
  • Scan notebook source, rendered output, controlled errors, logs, manifests, and exported artifacts.
  • Verify the value never appears.
  • Verify only the approved secret name is shown in the evidence panel.

Fresh-environment tests

  1. Clear runtime and any notebook-specific cache.
  2. Resolve and analyze the local source.
  3. Resolve and analyze the remote source.
  4. Compare equivalence evidence.
  5. Repeat in a second environment using different resolved paths.
  6. Confirm analytical cells and canonical checksum remain unchanged.

6.3 Test Data

Use one immutable, versioned Parquet fixture split across 365 date partitions with a signed manifest and six required columns among a wider schema. Maintain corrupted, truncated, missing-partition, stale-cache, unauthorized, and alternate-path variants, plus a unique canary secret that must never appear in any artifact.

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Problem: A seven-day request downloads the entire dataset

  • Why: partition pruning occurs after listing/downloading everything, the filter does not match partition keys, or the reader cannot push it down.
  • Evidence: selected objects/bytes resemble the full-year dataset.
  • Fix: derive exact partition references first, project columns, and verify the backend plan/read metrics.
  • Quick test: compare one-day, seven-day, and full-year object counts.

Problem: The notebook works only on the author’s Mac

  • Why: absolute paths, ambient credentials, or undocumented cache files leak into source resolution.
  • Evidence: fresh runtime or second environment cannot resolve the logical input.
  • Fix: use notebook file references/shared storage, documented secret names, and the common adapter.

Problem: Remote outage silently shows an old snapshot as current

  • Why: cache fallback reuses the ready-state label without source/freshness evidence.
  • Evidence: object access fails but CURRENT remains visible.
  • Fix: classify fallback explicitly, display snapshot age/coverage, and set current_claim=false.

Problem: Local and remote counts match but checksum differs

  • Why: schema coercion, timezone interpretation, null semantics, partition duplication, unstable ordering, or different source version.
  • Evidence: stepwise equivalence report identifies the first mismatch.
  • Fix: compare identity, schema, partitions, ranges, and canonicalized rows before the final checksum.

Problem: Writing to a resolved path corrupts a source or cache

  • Why: the path was treated as a workspace file rather than a read-only input reference.
  • Evidence: later reads vary or original input changes.
  • Fix: never mutate the resolved path; write outputs to a separate explicit destination.

Problem: Modified notebook unexpectedly loses access

  • Why: the prior stamp no longer authorizes changed content/resources.
  • Evidence: Livebook requests permission again or reports an unstamped/foreign state.
  • Fix: review changes and reapprove through the intended Livebook workflow; do not bypass permission checks or paste secrets into source.

Problem: ETag equality is treated as universal content equality

  • Why: multipart/provider behavior was ignored.
  • Evidence: documented checksum and ETag semantics disagree.
  • Fix: use a controlled manifest with explicit content hashes or immutable version IDs.

7.2 Debugging Strategies

Compare the source-result contract one field at a time: logical identity, manifest/version, selected partitions, projection, resolved read statistics, normalized schema, row range, and canonical summary. Preserve the original provider error class, and clear caches when testing portability so local residue cannot hide a missing configuration.

7.3 Performance Traps

Bucket-wide listings, download-before-filter behavior, absent projection, repeated remote resolution, copying large data into notebook state, and silent cache growth defeat portability and cost controls. Measure object count and bytes for one-day, seven-day, and full-year requests, and assert that read work scales with the selection.

Definition of Done

Submit the Livebook notebook, source-contract documentation, immutable partition manifest, local and S3-compatible training setup instructions, equivalence report, failure-matrix transcript, and second-environment replay evidence.

The submission is complete when:

  • Local and object-backed sources feed identical downstream analytical cells.
  • No executable configuration contains an author-specific absolute path.
  • The source panel reports logical reference, identity/version, cache, freshness, selected partitions, read evidence, and read-only policy.
  • A seven-day request selects only the intended partitions and columns where supported.
  • The collected output is bounded at the expected summary grain.
  • Schema, row count, time range, profiles, selected partitions, and canonical checksum are equivalent.
  • Secret values are absent from source, outputs, errors, logs, and artifacts.
  • Resolved input paths are never modified.
  • Unavailable, unauthorized, stale-cache, corrupt/mismatched, missing-partition, and partial-read cases are demonstrated.
  • Any fallback is explicitly labeled cached/non-current with age and coverage.
  • Stamp/resource-permission behavior and limitations are explained.
  • A cold fresh runtime and a second environment reproduce the analytical result.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • relocation preserves data identity, replay, and provenance.

Project 99: Tested Domain Smart Cell Toolkit

Source: LIVE-P9. Build a Kino smart cell and renderer that generate inspectable source.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: JavaScript; TypeScript for bundled UI assets; Erlang for generated-source comparison
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: Level 3: Service & Support
  • Curriculum Difficulty: Level 3: Applied
  • Knowledge Area: Source generation, collaborative UI, packaging, testing
  • Software or Tool: Kino.JS, Kino.JS.Live, Kino.SmartCell, Kino.Test
  • Main Book: Domain Specific Languages

What you will build: Build a Kino smart cell and renderer that generate inspectable source.

Why it teaches the BEAM ecosystem: It makes you prove that generated code is stable, editable, tested, and versioned independently.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Build a Kino smart cell and renderer that generate inspectable source.

Create a small package exposing a “Data quality rule” Smart Cell. Its editor lets an author choose:

  • the DataFrame variable to inspect;
  • the target column;
  • one allowlisted rule: non-null, numeric range, accepted category set, or uniqueness;
  • severity: information, warning, or error;
  • null behavior where the rule supports it;
  • a human-readable message stored strictly as data.

The cell shows a generated-source preview and a compact description of the rule. Evaluation produces a structured validation result that another notebook section may render. The package includes tests, package documentation, one minimal .livemd example, and a compatibility policy for saved attributes.

SMART CELL: Data quality rule

DataFrame variable: trips
Column: duration_minutes
Rule: numeric range
Minimum: 1
Maximum: 360
Null behavior: reject
Severity: error
Message: Duration must be within the service contract

Source preview: VALID
Rule identifier: quality.duration_minutes.range.v1

After evaluation, a consumer sees a structured result transcript:

Rule quality.duration_minutes.range.v1
Rows evaluated: 24,000
Violations: 37
Severity: error
Sample row identifiers: [redacted bounded sample]
Status: FAIL

In a clean notebook, install the local package through the normal dependency setup, open the Smart menu, and insert the cell. Configure a rule, save the notebook, close the session, reopen it, and observe every field restored. Convert a copy to a normal code cell; the source is formatted, short enough to review, and produces an equivalent structured result. Run the package test suite and obtain:

SMART CELL VERIFICATION
attribute round-trip ............... PASS
legacy attrs v0 -> current ......... PASS
legacy attrs v1 -> current ......... PASS
invalid identifier rejection ....... PASS
malformed attrs recovery ........... PASS
source byte stability .............. PASS
convert-to-code parity ............. PASS
pending editor synchronization ..... PASS
duplicate event tolerance .......... PASS

The outcome is visible in three places: the editor works, the saved .livemd diff contains stable attributes, and the generated source remains useful without the custom UI.

The Core Question You Are Answering

“How do you give a domain workflow a friendly interface without replacing readable source with opaque magic?”

Before implementation, decide what must remain understandable after the package disappears. The answer should be: domain meaning and generated source remain; only the editing convenience is lost.

Concepts You Must Understand First

  1. Smart Cell lifecycle
    • When are attributes initialized, restored, edited, synchronized, and exported?
    • Primary reference: Kino.SmartCell
  2. Live process state
    • Which assigns are authoritative and which browser values are only drafts?
    • Primary reference: Kino.JS.Live
  3. Safe syntax construction
    • Which fields are code identifiers and which are quoted runtime data?
    • Book reference: Metaprogramming Elixir — quoting and AST chapters
  4. Schema evolution
    • How will a one-year-old notebook restore after attributes change?
    • Book reference: Designing Data-Intensive Applications — evolvability and encoding chapters
  5. Integration testing
    • Which public events and outputs prove the cell works?
    • Primary reference: Kino.Test

Questions to Guide Your Design

  1. What is the smallest useful rule vocabulary?
  2. Can every persisted value be represented as ordinary JSON without losing meaning?
  3. What is the canonical order of keys, category values, and generated options?
  4. How does an invalid draft differ from the last valid exported source?
  5. Which old attribute forms are migrated, rejected, or preserved?
  6. Can free-form user text ever change syntax?
  7. What does a collaborator see while another author edits?

Thinking Exercise

Create a state table for four layers: browser draft, server assigns, persisted attributes, generated source. Trace these events by hand:

  1. restore a valid old notebook;
  2. enter an invalid variable name;
  3. change rule type while a now-irrelevant option exists;
  4. save before a collaborative editor blur event;
  5. reconnect after a server process restart.

For each event, state which layer changes, what the user sees, and whether evaluation is allowed.

The Interview Questions They Will Ask

  1. “What is a Livebook Smart Cell under the hood?”
  2. “Why must persisted attributes be JSON-compatible?”
  3. “How do you prevent source injection from labels and identifiers?”
  4. “What does deterministic source generation buy you?”
  5. “How do you evolve saved attributes without breaking old notebooks?”
  6. “What does convert-to-code parity prove?”

Hints in Layers

Hint 1: Build the compiler first

Start with pure attribute normalization and source generation. A static map should produce a stable result before a browser exists.

Hint 2: Separate syntax from data

Use an allowlist for syntax-bearing choices. Treat column names and messages as safely quoted data wherever possible.

Hint 3: Version at the boundary

Migrate persisted attributes into one current normalized shape. Do not spread historical cases throughout the UI and generator.

Hint 4: Test the bridge

Use Kino.Test to connect, send events, request source, restore saved data, and observe replies. Pure tests cannot reveal synchronization bugs.

Books That Will Help

Topic Book Chapter
Domain-specific language design Domain Specific Languages by Martin Fowler Semantic model and representation chapters
Elixir syntax representation Metaprogramming Elixir by Chris McCord Chapters 1–4
Evolvable persisted formats Designing Data-Intensive Applications, 2nd ed. Encoding and evolvability chapters
Stable library design The Pragmatic Programmer Orthogonality, tracer bullets, and contracts topics

Implementation Milestones

Phase 1: Domain Compiler (5–7 hours)

Goals: define the current attribute schema, two historical fixtures, normalization, validation, and source-generation contract.

Tasks:

  1. Write valid, invalid, legacy, and malicious attribute fixtures.
  2. Define allowlists and identifier policy.
  3. Specify canonical ordering and formatting.
  4. Test repeated generation and migration idempotency.

Checkpoint: pure tests prove stable source and safe rejection without Kino.

Phase 2: Smart Cell Bridge (7–10 hours)

Goals: register the cell, restore attributes, handle typed events, and export source.

Tasks:

  1. Map normalized attributes into server assigns.
  2. Design the browser/server event protocol.
  3. Implement validation feedback and source preview.
  4. Exercise connection and event handling with Kino.Test.

Checkpoint: a minimal editor round-trips one rule and converts to equivalent code.

Phase 3: Compatibility, Collaboration, and Packaging (8–13 hours)

Goals: harden restoration, pending-edit synchronization, documentation, and package behavior.

Tasks:

  1. Restore historical fixtures and malformed notebooks.
  2. Test two-client editing and evaluation boundaries.
  3. Bundle assets and remove external runtime dependencies.
  4. Create the example .livemd and compatibility matrix.

Checkpoint: save/reopen, convert-to-code, clean-runtime install, and full test transcript all pass.

Testing Strategy

6.1 Test Categories

Category Purpose Examples
Pure unit Prove normalization, migration, validation, and source stability equivalent attrs, invalid ranges, malicious identifiers
Smart Cell integration Prove bridge behavior connect, event, export, restore, editor sync
Compatibility Protect saved notebooks v0, v1, current, unknown/malformed fields
Conversion Preserve transparency Smart Cell result versus converted source result
Collaboration Detect pending and conflicting edit problems two clients, save during edit, reconnect
Packaging Prove fresh installation clean Mix cache and fresh Livebook runtime

6.2 Critical Test Cases

  1. Round-trip: save valid attributes, restore them, and export byte-identical source.
  2. Migration idempotency: migrating historical attributes twice produces the same current form.
  3. Identifier attack: quotes, newlines, interpolation markers, aliases, and invalid Unicode identifiers cannot change source structure.
  4. Free-text safety: messages containing source-like characters remain literal data.
  5. Malformed recovery: invalid persisted state yields a repairable editor and no server crash.
  6. Pending edit: evaluation sees the latest synchronized value or is visibly blocked until synchronization.
  7. Duplicate event: repeated delivery does not append duplicate options or change meaning.
  8. Conversion parity: the generated code reports the same rule identity, severity, and result.

6.3 Test Data

Fixture current_valid:
  variable=trips, column=duration_minutes, range=1..360, severity=error

Fixture legacy_v0:
  no schema version, old “level” field, missing null policy

Fixture hostile_identifier:
  includes quote, newline, interpolation marker, and expression-like text

Fixture malformed:
  unsupported rule, reversed range, severity as nested object

Expected:
  valid -> stable source
  legacy -> documented normalized source
  hostile -> actionable rejection
  malformed -> safe repair state

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Pitfall Symptom Solution
Assigns never exported Cell reopens with defaults Define complete attribute serialization and round-trip test
Map iteration leaks into source Git diff changes without semantic edit Canonicalize every unordered collection
Browser treated as authority Crafted event bypasses UI restriction Revalidate all events server-side
Label inserted into syntax Source breaks or changes behavior Quote labels strictly as data
Migration mixed into callbacks Old notebooks fail in surprising paths Normalize once before current-state logic
Listener duplication Each UI event is handled more than once Ensure one Smart Cell process and idempotent event transitions

7.2 Debugging Strategies

  • Inspect four states separately: browser draft, server assigns, exported attrs, and source.
  • Reduce to one event: reproduce with a single typed event through Kino.Test.
  • Compare normalized forms: diff canonical attributes before diffing generated text.
  • Reopen the saved notebook: a live session can hide serialization omissions.
  • Convert to code: if the generated result is mysterious, the DSL model is too opaque.
  • Disable network: verify bundled assets and local package behavior.

7.3 Performance Traps

Avoid regenerating large source on every keystroke, shipping oversized option lists to the browser, recompiling browser assets at runtime, or retaining full collaboration event histories. Debounce cosmetic preview updates, but synchronize authoritative state before export or evaluation.

Definition of Done

Minimum Viable Completion:

  • One allowlisted rule type edits, persists, restores, and generates readable source.
  • Invalid identifiers are rejected server-side.
  • Pure source-generation and one Kino bridge test pass.

Full Completion:

  • All four rule types, versioned attributes, two historical migrations, malformed recovery, deterministic source, convert-to-code parity, bundled assets, and clean-runtime installation work.
  • Test evidence includes events, restoration, source export, duplicate delivery, and pending-editor synchronization.

Excellence (Going Above & Beyond):

  • Publish a versioned package with compatibility policy, property-based safety tests, accessible editor behavior, and a second independent notebook consuming the generated result protocol.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • generated code is stable, editable, tested, and versioned independently.

Project 100: Governed Multi-Session Livebook Operations Studio

Sources: LIVE-P12, LIVE-CAP. Deploy an authenticated decision app inside a governed notebook portfolio with manifests and rollback gates.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: SQL; JavaScript for packaged custom UI only
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: Level 3: Service & Support
  • Curriculum Difficulty: Level 3: Applied
  • Knowledge Area: Internal tools, deployment, identity, operations, data and ML governance
  • Software or Tool: Livebook Apps, Kino, Explorer, VegaLite, optional Nx.Serving, Docker, Livebook Teams
  • Main Book: Release It!, Second Edition

What you will build: Deploy an authenticated decision app inside a governed notebook portfolio with manifests and rollback gates.

Why it teaches the BEAM ecosystem: It makes you prove that a new operator can replay, isolate users, observe a fault, and roll back.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Integrated Scope

This is one consolidated project, not separate source builds. Implement the following contributions as phases of the same artifact:

  • Deliver LIVE-P12 authentication, multi-session isolation, deployment configuration, and rollback evidence.
  • Treat LIVE-CAP governance, portfolio manifests, and operational handoff as hardening of that same deployed app.

Real World Outcome

Build target: Deploy an authenticated decision app inside a governed notebook portfolio with manifests and rollback gates.

Build a multi-session operations decision app with these panels:

  1. Environment and provenance header: environment, app revision, runtime mode, data age, source mode, optional model revision, and health dimensions.
  2. Incident queue: at most 100 read-only, authorization-filtered incidents with severity, owner, status, and freshness.
  3. SLA evidence: bounded summary cards and charts for availability, error rate, p50/p95/p99 latency, saturation, and comparison window.
  4. Decision assistant: a reviewed runbook catalog and optional model suggestion with evidence, abstention, and human accept/correct/skip.
  5. Private notes: session-local notes clearly labeled ephemeral until the user exports.
  6. Handoff export: a sanitized, durable report containing user-approved evidence, provenance, decisions, and checksums but no secret or forbidden data.
  7. Deployment evidence: clean replay, stamp authority, named secret/storage resources, image digest, warmup, capacity, smoke tests, and rollback revision.

The production deployment uses a standalone runtime and only read-only bounded operational integrations. A separate scoped write credential may write sanitized handoff reports to a dedicated evidence store; it must have no authority over production application data.

OPERATIONS DECISION APP
Environment: PRODUCTION (read-only)
App revision: 9b73c2a
Runtime: standalone
Authenticated scope: payments / viewer
Data observed at: 2026-07-15T19:03:12Z
Data age: 41 seconds [CURRENT]
Model: optional-triage-r17 [READY]
Mutation capability: NONE
INCIDENT INC-TRAINING-SHAPE
Evidence window: 30 minutes
Requests: 8,241,993
Availability: 99.94%
Error rate: 0.37%
p50 / p95 / p99: 42 / 211 / 804 ms
Source status: PARTIAL — saturation feed delayed 73 seconds

Model suggestion: dependency_degradation (score 0.74)
Policy: ABSTAIN — below decision threshold 0.80
Human action: investigate dependency runbook

After authentication, two test users open separate multi-session app sessions. Their queue scope follows authorization policy. Distinct note, filter, upload, and export canaries never cross sessions. Shared reference data and an optional shared serving process contain no user content.

The UI looks and behaves as follows:

┌─────────────────────────────────────────────────────────────────────┐
│ PROD READ-ONLY | Data age 41s | App 9b73c2a | Model r17 | READY    │
├────────────────┬────────────────────────────┬───────────────────────┤
│ Incident queue │ SLA and service evidence   │ Decision assistant    │
│ severity/owner │ latency/errors/saturation  │ suggest/correct/skip  │
│ max 100 rows   │ bounded comparison window  │ human owns decision   │
├────────────────┴────────────────────────────┴───────────────────────┤
│ Private notes | read-only runbook | provenance | export handoff    │
└─────────────────────────────────────────────────────────────────────┘

The staging deployment gate produces:

DEPLOYMENT GATE
clean-runtime replay ................ PASS
source and dependency review ........ PASS
expected team stamp authority ....... PASS
secret names / no values ............ PASS
read-only integration capability .... PASS
two-user isolation canaries ......... PASS
cold start / warmup budget .......... PASS
session memory and load budget ....... PASS
stale/partial/empty failure states ... PASS
handoff idempotency ................. PASS
previous-revision rollback .......... PASS
production mutation paths ........... NONE

Only after the same immutable revision passes staging may it be promoted. Production verification remains read-only.

The Core Question You Are Answering

“What must change when an executable notebook becomes a multi-user service that influences operational decisions?”

The answer includes identity, authorization, runtime authority, session isolation, durable state, freshness, model governance, capacity, observability, immutable deployment, and rollback. App preview alone is not completion.

Concepts You Must Understand First

  1. App and session semantics
  2. Runtime authority
    • Why must this app use a standalone runtime and narrow interfaces?
    • Primary reference: Livebook runtimes
  3. Authentication and authorization
  4. Secrets, storage, and stamps
  5. App-server capacity
  6. Repeatable deployment
    • How does CI promote one immutable revision and preserve rollback?
    • Primary reference: CLI deployment
  7. Decision support
    • How do freshness, uncertainty, abstention, and human override affect action?
    • Book reference: AI Engineering — evaluation and inference chapters

Questions to Guide Your Design

  1. Which state is session-private, immutable shared cache, durable handoff, deployment config, and audit metadata?
  2. How are authenticated groups mapped to allowed environments and services?
  3. What independent enforcement makes operational data read-only?
  4. Which source failure produces stale, partial, empty, or failed UI state?
  5. Can a late query result overwrite a newer filter generation?
  6. Does any shared process retain user content after a request?
  7. What cold-start and per-session memory budget follows from the expected concurrency?
  8. What exact smoke failure triggers automatic or manual rollback?
  9. Can the previous revision still use current secrets, storage, schemas, and model artifacts?
  10. What evidence proves production contains no mutation path?

Thinking Exercise

Create a state and authority matrix before building the UI:

Actor/component Identity Reads Writes Credential Lifetime Durable evidence
App user authenticated subject authorized app views private session controls app identity session metadata only
Session runtime app revision read-only ops sources sanitized handoff only scoped resources session revision/outcome
Query catalog app code approved schemas/APIs none read-only source credential revision query ID/status
Shared cache app server immutable reference data cache refresh source reader server freshness only
Handoff exporter app code selected sanitized evidence dedicated evidence store write-only/scoped store credential request checksum/location
CI protected automation notebook artifact deployment group deploy token pipeline deployment record

Add database, model store, audit sink, author, and app server. If any row has ambiguous write authority, stop and redesign.

The Interview Questions They Will Ask

  1. “How do single-session and multi-session Livebook Apps differ?”
  2. “Why does code-hidden app mode not sandbox notebook execution?”
  3. “How do you prevent shared caches or model serving from leaking user data?”
  4. “How do authentication and authorization differ in this app?”
  5. “What does a notebook stamp guarantee and not guarantee?”
  6. “How do you size, deploy, observe, and roll back a Livebook App?”

Hints in Layers

Hint 1: Begin with authority, not layout

Select standalone runtime, read-only source credentials, authorization scope, and durable evidence store before drawing cards.

Hint 2: Treat each session as disposable

Private notes and filters live in the session until explicitly exported. Never rely on session memory for durable operational decisions.

Hint 3: Make stale and partial visible

Attach freshness to each source. Do not let a healthy app process hide an old or failed feed.

Hint 4: Promote evidence, not hope

Clean replay, two-user canaries, cold start, memory, load, redaction, smoke, and rollback must pass on the exact revision.

Books That Will Help

Topic Book Chapter
Production stability and capacity Release It!, 2nd ed. Stability, capacity, and operations chapters
Architecture trade-offs Fundamentals of Software Architecture Architecture characteristics and risk chapters
Data reliability Designing Data-Intensive Applications, 2nd ed. Chapters 1, 3, and 11
Model-backed decisions AI Engineering Evaluation and inference chapters
Continuous delivery Continuous Delivery by Jez Humble and David Farley Deployment pipeline and release strategy chapters

Implementation Milestones

Integrated basic-to-advanced progression

  1. Deliver LIVE-P12 authentication, multi-session isolation, deployment configuration, and rollback evidence.
  2. Treat LIVE-CAP governance, portfolio manifests, and operational handoff as hardening of that same deployed app.

Milestone 1 — Contract and fixture: define one representative input, output, invariant, and failure case.

Milestone 2 — Core artifact: Deploy an authenticated decision app inside a governed notebook portfolio with manifests and rollback gates.

Milestone 3 — Failure behavior: add timeouts, invalid inputs, crashes, retries, or partitions appropriate to the project.

Milestone 4 — Evidence: automate the definition of done and record a reproducible result.

Phase 1: Authority, Contracts, and Fixtures (8–11 hours)

Goals: prove read-only architecture and build testable domain components before app mode.

Tasks:

  1. Complete trust, state, credential, and data-flow maps.
  2. Define authorization policy and fixed query catalog.
  3. Build stale, partial, empty, timeout, unauthorized, and overload fixtures.
  4. Define evidence, redaction, audit, and idempotent handoff schemas.
  5. Define optional model provenance and abstention policy.

Checkpoint: normal Mix tests prove authorization, bounds, redaction, and no mutation capability.

Phase 2: Multi-Session App Experience (9–13 hours)

Goals: build private session workflow and honest operational presentation.

Tasks:

  1. Implement identity/scope gate and session coordinator.
  2. Add bounded queue, SLA evidence, failure states, and generation control.
  3. Add private notes and optional model suggestion/human correction.
  4. Add sanitized idempotent export.
  5. Run two-client canary and inactivity cleanup tests.

Checkpoint: app preview meets all privacy, freshness, and read-only interaction requirements.

Phase 3: App Server, Capacity, and Staging (9–13 hours)

Goals: operate the app as a service before production promotion.

Tasks:

  1. Configure Teams workspace, expected stamp authority, deployment group, authentication, secrets, and storage.
  2. Build immutable app-server image/dependency/model artifacts.
  3. Measure cold start, warmup, base memory, per-session memory, shared resources, and load.
  4. Configure inactivity shutdown and health/freshness metrics.
  5. Deploy the reviewed revision to staging and run smoke tests.

Checkpoint: staging gate passes with recorded image digest and capacity margin.

Phase 4: Promotion, Observation, and Rollback (9–13 hours)

Goals: prove deployment and recovery rather than simply publishing.

Tasks:

  1. Promote the same immutable revision through repeatable CI/manual deployment.
  2. Run production read-only smoke checks and audit verification.
  3. Freeze one source and verify freshness alarms while process health stays green.
  4. Redeploy the previous revision and repeat the gate.
  5. Restore the candidate revision only after rollback evidence is captured.

Checkpoint: production read-only verification and previous-revision rollback both pass.

Testing Strategy

6.1 Test Categories

Category Purpose Examples
Authorization Prevent cross-scope access role/service/environment matrix, denied identity
Query/data contract Bound operational work parameters, row/byte/time limits, stale/partial sources
Session isolation Protect private state two-user filters, notes, uploads, outputs, exports
Shared-resource privacy Keep caches/serving safe user-content canary scans after batching/cache refresh
Decision Preserve human authority abstain, model unavailable, accept/correct/skip
Export/audit Prove durable safe evidence redaction, idempotency, audit metadata, failure retry
Capacity Size app server cold start, memory/session, concurrency, inactivity shutdown
Deployment Prove promotion and reversal staging smoke, immutable revision, rollback compatibility
Security Prove read-only path credential permissions, no dynamic SQL/code, no attached runtime

6.2 Critical Test Cases

  1. Unauthenticated user: receives no operational content.
  2. Unauthorized scope: a valid user cannot request another service/environment by changing input.
  3. Two-user canaries: notes, filters, model inputs, outputs, and exports remain isolated.
  4. Shared cache scan: no user canary appears in shared state after requests finish.
  5. Late result: an older slow query cannot overwrite a newer filter generation.
  6. Stale source: process health stays ready while UI changes to stale and alarms.
  7. Partial source: valid panels remain visible with explicit missing-source context.
  8. Read-only enforcement: source credential and API reject mutation independently of notebook behavior.
  9. Model unavailable: app remains usable, reports model failure, and allows human-only decision.
  10. Handoff idempotency: retry produces one durable report identity, not duplicates.
  11. Cold offline start: approved dependencies/model are available without runtime internet fetch.
  12. Capacity threshold: excess sessions receive bounded refusal/degradation rather than memory exhaustion.
  13. Rollback: previous revision deploys and passes authentication, secrets, storage, schema, and smoke checks.
  14. Mutation-path scan: source, dependencies, configuration, UI, and network observations show no production write/attached/remote-code path.

6.3 Test Data

Identity fixtures:
  payments_viewer, catalog_viewer, unauthorized_user, missing_identity

Source fixtures:
  current, stale, partial, empty, timeout, oversized, schema_mismatch

Session canaries:
  user-A-note, user-B-note, user-A-upload, user-B-upload

Decision fixtures:
  high suggestion, low/abstain, tie, model unavailable, human correction

Deployment fixtures:
  candidate revision, previous revision, secret-name manifest,
  app-server image digest, expected stamp authority

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Pitfall Symptom Solution
Shared input/frame used Users see another session’s data Multi-session controls plus two-user canary tests
UI says read-only but credential writes Hidden mutation capability remains Use independently read-only credential/API
App healthy, data old Operators trust stale evidence Separate runtime health and source freshness
Model copied per session Memory rises sharply with users Measure architecture; share only immutable serving resources safely
Startup downloads dependencies/model Slow or failed restart without network Prewarm and verify immutable artifacts
Notes stored in shared cache Cross-user privacy leak Keep private state in session; export explicitly
Rollback cannot access storage Old revision incompatible with current environment Version deployment contract and rehearse rollback in staging
Audit contains payloads/secrets Privacy/security incident Emit minimal metadata and scan with seeded canaries

7.2 Debugging Strategies

  • Start at the header: verify environment, revision, runtime, identity scope, source time, and model version.
  • Trace one request generation: authentication -> authorization -> query -> normalize -> render -> export.
  • Compare session and app-server memory: identify accidental per-session model/cache copies.
  • Freeze dependencies one at a time: distinguish stale data, model failure, and app-process failure.
  • Use two real authenticated test identities: one browser is insufficient evidence.
  • Inspect source credentials externally: do not rely only on notebook claims of read-only access.
  • Replay the previous revision: rollback failures are usually environment-contract drift.

7.3 Performance Traps

Avoid querying raw production-scale rows for every filter, rendering millions of points, refreshing faster than source change, compiling dependencies or model shapes per session, retaining unbounded notes/logs, and allowing multi-session count to exceed measured memory. Use bounded pre-aggregation, explicit cache keys containing no user data, fixed serving shapes, and inactivity shutdown where workflow permits.

Definition of Done

Minimum Viable Completion:

  • A local multi-session app preview authenticates test identity context, isolates two sessions, reads a bounded synthetic/read-only source, shows freshness, and exports a sanitized handoff.
  • Runtime is standalone and no mutation path exists.

Full Completion:

  • Authorization scope, fixed query catalog, stale/partial/empty/failure states, optional human-owned model suggestion, shared-resource privacy, idempotent export, durable audit metadata, Teams authentication/configuration, shared secrets/storage, expected stamp authority, offline cold start, capacity/load, immutable staging/production deployment, and previous-revision rollback all pass.
  • Production verification uses only bounded read-only operations.

Excellence (Going Above & Beyond):

  • Operate multiple app servers with measured capacity and recovery, externalize model inference behind a narrow service, add signed/lifecycle-managed handoff artifacts, automate dependency/model policy checks, and demonstrate a disaster-recovery rehearsal—while preserving the no-production-mutation rule.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • Every merged source contribution is implemented as a phase of this one artifact, not as a separate project.
  • a new operator can replay, isolate users, observe a fault, and roll back.

Phase 6 - Real-Time Flow, Native Boundaries, and Numerical Computing

Project 101: Distributed Presence Workspace

Sources: BEAM-P7, PUB-P6. Build multi-node, multi-device Presence with uncertainty and convergence.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: JavaScript/TypeScript client, Erlang backend
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: Level 4: Open Core Infrastructure
  • Curriculum Difficulty: Level 4: Advanced
  • Knowledge Area: Presence CRDTs, multi-device lifecycle, eventual consistency
  • Software or Tool: Phoenix.Presence, Phoenix.Tracker, LiveView or Channels
  • Main Book: “Real-Time Phoenix” by Stephen Bussey

What you will build: Build multi-node, multi-device Presence with uncertainty and convergence.

Why it teaches the BEAM ecosystem: It makes you prove that Presence never substitutes for durable identity or audit truth.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Integrated Scope

This is one consolidated project, not separate source builds. Implement the following contributions as phases of the same artifact:

  • Use BEAM-P7 for multi-node notification and process-lifecycle foundations.
  • Complete the workspace with PUB-P6 Presence metas, multi-device identity, uncertainty, and convergence.

Real World Outcome

Build target: Build multi-node, multi-device Presence with uncertainty and convergence.

Create a collaborative incident workspace with:

  • A responder roster grouped by logical user.
  • Expandable device details for every active meta.
  • Coarse activity states such as active, away, and reconnecting.
  • A visible UNCERTAIN state when a node or connection is suspected but convergence is pending.
  • A cluster diagnostics panel showing local node, tracker replica, last diff, known metas, and convergence drill timing.
  • Development controls for graceful tab close, abrupt process loss, node isolation, reconnect, and delayed profile fetching.

The durable incident membership table determines who may enter the room and preserves incident participation history. Presence only answers who appears connected now.

Run three application nodes, join incident room INC-104 from two laptop tabs and one phone as Douglas, then join from one laptop as Margarita. The roster groups the three Douglas metas and shows one logical user. Close the second laptop tab: Douglas remains online with two devices.

Next, isolate the node hosting the phone. The UI must not instantly assert that the phone definitely left. It marks that connection uncertain according to your failure policy. Reconnect the phone on a new node, producing a new ref while the old ref is still known. After Tracker converges, all three nodes show the same final refs.

The reference transcript is:

Room INC-104 — Responders
Douglas   ONLINE devices=3 [laptop:A, tab:C, phone:B]
Margarita ONLINE devices=1 [laptop:D]

leave ref=C -> Douglas remains ONLINE devices=2
partition node_b -> phone ref=B status=UNCERTAIN
reconnect phone ref=E -> temporary metas=[B,E]
convergence complete -> metas=[A,E] consistent_on=3/3 nodes
audit truth changed by presence diff=false

The Core Question You Are Answering

“How do I represent ‘online’ honestly when users have many connections and the cluster cannot know failure instantly?”

Your written answer should define online, offline, uncertain, reconnecting, and converged in terms of observable refs and tracker state—not human intent.

Concepts You Must Understand First

  1. State and diff synchronization
    • Why must initial state precede ordinary diffs?
    • How does a phx_ref identify one meta?
    • Reference: Phoenix Presence server and JavaScript client docs.
  2. CRDT convergence
    • What does conflict-free merge guarantee after communication resumes?
    • What does it not guarantee during a partition?
    • Book: “Designing Data-Intensive Applications, 2nd Edition,” replication and distributed systems chapters.
  3. Failure detection
    • Why is silence ambiguous?
    • How do down and permanent-down windows affect UX?
  4. Process ownership
    • What happens to tracked metas when their owning process exits?
    • How does abrupt node loss differ from orderly untracking?
  5. Callback isolation
    • Why should Presence handle_metas/4 remain bounded, and why is blocking raw Tracker handle_diff/2 even more dangerous?
    • Which work belongs in a supervised task or durable pipeline?

Questions to Guide Your Design

  1. Which stable identifier groups a user across devices without exposing private data?
  2. Which metadata is truly ephemeral and necessary on every node?
  3. How does the UI distinguish one meta leave from the final meta leave?
  4. When does the UI show UNCERTAIN, and what clears it?
  5. How will a failed batch profile query affect the roster?
  6. Is the Tracker at the supervision-tree root under :one_for_one, and what does a rolling deploy look like under the safe permdown_on_shutdown policy available to that topology?

Thinking Exercise

Draw two nodes and one user with refs A and C on node A and ref B on node B. Trace:

  1. Graceful close of C.
  2. Network isolation of B.
  3. Reconnect on node C as ref E.
  4. Delayed observation of B’s down status.
  5. Connectivity restoration and convergence.

For each step, list each node’s possible local view and the safest UI label. Then explain why none of those steps should charge a bill or create a compliance attendance record.

The Interview Questions They Will Ask

  1. “How is Phoenix Presence different from PubSub subscriptions?”
  2. “Why can one presence key contain multiple metas?”
  3. “What consistency model does Phoenix.Tracker provide?”
  4. “Why can a disconnected user remain visible temporarily?”
  5. “How do Presence handle_metas/4 and raw Tracker handle_diff/2 differ, and what work is dangerous inside either callback?”
  6. “Why isn’t presence a valid authorization or audit source?”

Hints in Layers

Hint 1 — Render the raw shape first: Inspect grouped keys and metas before inventing an online boolean.

Hint 2 — Let refs drive mutation: Remove exact refs using supported sync behavior; never infer removal by device name.

Hint 3 — Degrade enrichment, not tracking: If profile data fails, show an opaque responder label and preserve liveness convergence.

Hint 4 — Separate graceful from abrupt drills: A tab close, process kill, node halt, and network partition have different timing.

Hint 5 — Measure convergence from a shared scenario ID: Compare final ref sets across nodes without using raw user IDs as metrics.

Books That Will Help

Topic Book Focus
Phoenix Presence “Real-Time Phoenix” by Stephen Bussey Presence and Channels chapters
Replication and convergence “Designing Data-Intensive Applications, 2nd Edition” Replication, distributed systems, and CRDT discussion
Operational failure “Release It!, 2nd Edition” Stability patterns and failure isolation
Integration boundaries “Enterprise Integration Patterns” Message channels and event messages

Implementation Milestones

Integrated basic-to-advanced progression

  1. Use BEAM-P7 for multi-node notification and process-lifecycle foundations.
  2. Complete the workspace with PUB-P6 Presence metas, multi-device identity, uncertainty, and convergence.

Milestone 1 — Contract and fixture: define one representative input, output, invariant, and failure case.

Milestone 2 — Core artifact: Build multi-node, multi-device Presence with uncertainty and convergence.

Milestone 3 — Failure behavior: add timeouts, invalid inputs, crashes, retries, or partitions appropriate to the project.

Milestone 4 — Evidence: automate the definition of done and record a reproducible result.

Phase 1 — Durable membership and single-node presence (4–6 hours)

  • Define authorized incident membership.
  • Track one connection with minimal metadata.
  • Render grouped state.

Checkpoint: An unauthorized user cannot track or list; one authorized user appears once.

Phase 2 — Multi-device state and diff (4–5 hours)

  • Open three connections under one key.
  • Apply state and diffs by ref.
  • Keep the user online as individual refs leave.

Checkpoint: Closing one of three tabs yields devices=2, not offline.

Phase 3 — Batch enrichment and callback safety (3–5 hours)

  • Add compact meta validation.
  • Batch-fetch display details.
  • Isolate optional failure-prone work.

Checkpoint: A delayed profile source degrades names/avatars without blocking Tracker callbacks.

Phase 4 — Cluster and hard-failure drill (5–8 hours)

  • Run three connected nodes.
  • Isolate one node and record local views.
  • Reconnect with a new ref and observe convergence.

Checkpoint: All connected nodes reach the same final refs within the measured target.

Phase 5 — Deploy policy and tests (4–6 hours)

  • Compare graceful permanent-down enabled/disabled behavior.
  • Test rolling restart, abrupt halt, and partition.
  • Document the chosen product language for uncertainty.

Checkpoint: Test reports distinguish all failure modes and prove no business truth depends on diffs.

Testing Strategy

6.1 Test Categories

Category Purpose Examples
Projection unit Verify grouping and exact-ref mutation One key with A/B/C; remove C
Authorization Separate presence from access Revoked responder cannot track
Callback performance Keep Tracker work bounded Slow profile source isolated
Cluster integration Verify eventual convergence Partition B, reconnect as E
Lifecycle Compare graceful and abrupt loss Tab close vs node halt
Privacy Enforce metadata schema and size Reject secret or oversized meta

6.2 Critical Test Cases

  1. One user with three metas renders one roster row and devices=3.
  2. Removing one ref preserves the other refs and online status.
  3. Removing the final ref changes the user to offline according to UI policy.
  4. A duplicate join ref does not duplicate a device.
  5. A leave for an unknown ref does not remove the logical key.
  6. Initial state plus queued diff produces the correct final refs.
  7. Profile fetch uses one batch for all affected keys.
  8. Profile fetch failure does not crash the tracker path.
  9. Abrupt node loss shows uncertainty before convergence.
  10. Reconnect overlap temporarily permits old and new refs.
  11. Restored connectivity converges all nodes to the same set.
  12. Presence diffs never write durable attendance/audit rows.

6.3 Deterministic Test Data

Room: INC-104
Authorized keys: user-42, user-77

Initial metas:
  user-42 -> A(node_a,laptop), B(node_b,phone), C(node_a,tab)
  user-77 -> D(node_c,laptop)

Sequence:
  leave C
  isolate node_b
  join E(node_c,phone)
  mark B down after configured window
  restore node_b connectivity

Expected converged refs:
  user-42 -> [A,E]
  user-77 -> [D]

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Pitfall Symptom Correction
Flatten key to boolean One tab close makes user offline Preserve the meta collection
Store profile in meta Large replicated payload and leaks Batch-fetch durable detail
Block callback work Presence handling stalls; raw Tracker work can stall heartbeats/diffs Bound handle_metas/4; offload optional work from either layer
Treat leave as intent False audit or workflow events Use explicit durable commands
Expect instant hard-loss detection “Ghost” users reported as bug Model and explain uncertainty window
Assume transitive cluster membership Nodes see different rosters Verify direct connectivity and topology

7.2 Debugging Strategies

  • Log scenario ID, tracker node, ref, operation, and monotonic timestamp.
  • Compare Presence.list results on every node at controlled checkpoints.
  • Inspect node connectivity before blaming CRDT merge.
  • Measure Presence handle_metas/4 duration; if you run the optional raw Tracker experiment, also measure handle_diff/2 duration and tracker mailbox length during injected latency.
  • Capture both the raw ref set and the grouped roster; grouping bugs often masquerade as replication bugs.

7.3 Performance Traps

Frequent activity updates create high diff volume. Large metadata multiplies cluster traffic. fetch/2 on every change can overload the database if it performs one query per meta. Avoid broadcasting cursor pixels or keystrokes as Presence metadata; use a separate ephemeral channel with sampling/coalescing.

Definition of Done

Minimum Viable Completion

  • One logical user supports at least three visible metas.
  • Closing one meta does not create a false offline state.
  • State and diff synchronization produces the expected final set.
  • Presence is gated by durable authorization.

Full Completion

  • All functional requirements and critical tests pass.
  • A three-node partition/reconnect drill is documented with timestamps.
  • Metadata and callback budgets are verified.
  • Durable business behavior is proven independent of Presence diffs.

Excellence

  • Compare both shutdown policies during a rolling deployment.
  • Produce a convergence timeline visualization for every node.
  • Demonstrate degraded profile enrichment without tracker delay or crash.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • Every merged source contribution is implemented as a phase of this one artifact, not as a separate project.
  • Presence never substitutes for durable identity or audit truth.

Project 102: Demand-Aware Fanout Pipeline

Sources: BEAM-P5, PUB-P8. Compare raw push, GenStage demand, Broadway batching, and bounded Pub/Sub edges.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: Level 4: Open Core Infrastructure
  • Curriculum Difficulty: Level 4: Advanced
  • Knowledge Area: Reactive streams, demand, batching, acknowledgements
  • Software or Tool: GenStage 1.3, Broadway 1.3, Telemetry
  • Main Book: “Designing Data-Intensive Applications, 2nd Edition” by Kleppmann et al.

What you will build: Compare raw push, GenStage demand, Broadway batching, and bounded Pub/Sub edges.

Why it teaches the BEAM ecosystem: It makes you prove that tests show where backpressure stops and explicit shedding begins.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Integrated Scope

This is one consolidated project, not separate source builds. Implement the following contributions as phases of the same artifact:

  • Build BEAM-P5 demand-aware GenStage/Broadway stages and measure bounded queues.
  • Expose the result through PUB-P8 fanout boundaries with explicit drop, coalesce, or spill policy.

Real World Outcome

Build target: Compare raw push, GenStage demand, Broadway batching, and bounded Pub/Sub edges.

Run the same 50,000 telemetry events through three modes: raw PubSub to slow workers, GenStage demand distribution, and BroadcastDispatcher. The report shows raw mailbox growth, bounded work distribution, and slowest-consumer coupling in broadcast mode. Add Broadway processors/batches and a caller acknowledger test so completion is observable. Then push into a deliberately full edge and see the declared coalescing/rejection counter rather than hidden buffering.

$ mix flow.compare --events 50000
MODE pubsub_push      queue_max=38112 age_p99_ms=9440 backpressure=false
MODE genstage_demand  in_flight_max=160 age_p99_ms=218 distributed_once=true
MODE broadcast_demand consumers=4 throughput_limited_by=slow_consumer
MODE broadway_batch   processed=50000 ack_success=49992 ack_failed=8 batch_p99=100
EDGE full policy=coalesce_by_device coalesced=6840 durable_events_dropped=0

The Core Question You Are Answering

How can a system cross from push-based fanout into demand-driven processing without hiding an unbounded queue or claiming guarantees that stop at the bridge?

Concepts You Must Understand First

  1. GenStage demand — What does a consumer request? Reference: GenStage behavior docs.
  2. Dispatcher choice — Why does BroadcastDispatcher wait for every consumer’s demand? Reference: GenStage dispatchers.
  3. Broadway acknowledgement — Who decides retry after failure? Reference: Broadway.Acknowledger.
  4. Ordering/concurrency — What does partition_by preserve and not preserve? Book Reference: “Designing Data-Intensive Applications, 2nd Edition” — stream processing.

Questions to Guide Your Design

  1. Where can events accumulate before demand is observed?
  2. Can the original publisher know that the bridge is full?
  3. Which event class is safe to compact, and what business rule proves that safety?
  4. Does every broadcast subscriber have the same service-level objective?
  5. Is the desired property distribution to one worker or replication to all consumers?
  6. Who owns an event after the bridge says it was accepted?
  7. What happens if processing succeeds but acknowledgement fails?
  8. Does the ordering requirement apply across keys or only within one key?
  9. Can one hot key starve unrelated keys?
  10. Which metric detects overload sooner: throughput, queue length, or event age?

Thinking Exercise

Take EVT-0000417 for device-042. Draw its path through all four modes and answer:

  • How many process mailboxes can contain a copy?
  • Which component decides when it may advance?
  • What happens if its handler takes 500 milliseconds?
  • Who records success or failure?
  • What survives a node crash?
  • Can the same event be processed again?
  • What ordering relationship exists with EVT-0000418 for the same device?

The Interview Questions They Will Ask

  1. “Why does putting Broadway after Phoenix.PubSub not automatically backpressure publishers?”
  2. “When would you use DemandDispatcher instead of BroadcastDispatcher?”
  3. “How can one slow consumer affect a demand-driven broadcast topology?”
  4. “What does a Broadway acknowledger guarantee?”
  5. “How would you preserve ordering per customer while retaining concurrency across customers?”
  6. “What policy would you use when a bounded bridge is full?”

Hints in Layers

Hint 1: Start with accounting

Before optimizing throughput, make every event land in exactly one observable accounting category.

Hint 2: Draw the feedback path

Use arrows to show where demand travels. Stop the arrow at the first push-only API.

Hint 3: Measure age, not only queue length

A queue of 1,000 two-millisecond events differs from a queue of 1,000 five-second events. Event age exposes user-visible staleness.

Hint 4: Separate event classes

Do not use one overflow rule for replaceable state, commands, and durable facts.

Books That Will Help

Topic Book Suggested focus
Messaging patterns Enterprise Integration Patterns by Gregor Hohpe and Bobby Woolf Message channels, competing consumers, publish-subscribe channels, idempotent receivers
Reliability boundaries Release It!, Second Edition by Michael T. Nygard Stability patterns, capacity, timeouts, bulkheads, operational visibility
Streams and delivery semantics Designing Data-Intensive Applications, Second Edition by Martin Kleppmann and Chris Riccomini Replication, stream processing, delivery semantics, partitioning
Phoenix messaging Real-Time Phoenix by Stephen Bussey PubSub, distributed real-time systems, operational behavior
Live systems on the BEAM Programming Phoenix LiveView by Bruce A. Tate and Sophie DeBenedetto Event-driven UI boundaries and process-oriented design

Implementation Milestones

Integrated basic-to-advanced progression

  1. Build BEAM-P5 demand-aware GenStage/Broadway stages and measure bounded queues.
  2. Expose the result through PUB-P8 fanout boundaries with explicit drop, coalesce, or spill policy.

Milestone 1 — Contract and fixture: define one representative input, output, invariant, and failure case.

Milestone 2 — Core artifact: Compare raw push, GenStage demand, Broadway batching, and bounded Pub/Sub edges.

Milestone 3 — Failure behavior: add timeouts, invalid inputs, crashes, retries, or partitions appropriate to the project.

Milestone 4 — Evidence: automate the definition of done and record a reproducible result.

Testing Strategy

Test layers

Layer What to prove Example failure caught
Unit Event classification, coalescing choice, accounting equations A durable fact enters the drop path
Component Demand never dispatches above the requested count Producer oversends during replenishment
Integration Dispatcher and worker topology has intended delivery shape Broadcast used where competing delivery was intended
Load Queue, age, and in-flight bounds under a 50,000-event burst Hidden mailbox grows without limit
Failure Crashes and acknowledgements produce documented outcomes Event disappears between effect and ack
Recovery Restart behavior matches durability claim In-memory accepted work is incorrectly described as durable
Property Generated IDs reconcile into terminal categories Duplicate or missing terminal accounting

Required deterministic test data

Use at least these fixtures:

Fixture Count Purpose
Normal device-state events 40,000 Sustained keyed coalescing and partition load
Commands 5,000 Synchronous acceptance/rejection semantics
Durable facts 5,000 Spill and zero-loss invariant
Injected transient failures 5 Failed acknowledgement and retry-owner analysis
Injected permanent failures 3 Dead-letter or terminal failure analysis
Entity keys 1,000 Parallelism and per-key ordering
Deliberately hot key 1 Partition skew experiment
Slow broadcast subscriber 1 of 4 Slowest-consumer coupling

The eight failures are included within the 50,000 total events, not added afterward.

Critical tests

  1. Demand bound — dispatch never exceeds cumulative demand for a subscription.
  2. Competing delivery — each event reaches one worker in a failure-free run.
  3. Broadcast delivery — each event reaches every active broadcast subscriber.
  4. Slow-consumer coupling — group throughput falls when the slow subscriber remains active.
  5. Push-boundary overload — Pub/Sub publication outpaces the bridge without corrupting accounting.
  6. Coalescing safety — only replaceable state with the same key is superseded.
  7. Command rejection — rejected commands are never counted as accepted.
  8. Durable spill — a durable fact is accepted only after the adapter confirms durable admission.
  9. Acknowledgement partition — success and failed ID sets are disjoint and complete.
  10. Per-key normal order — same-key processing follows declared order in the no-failure case.
  11. Failure-order caveat — the report demonstrates how retry or crash can change completion order.
  12. Restart semantics — in-memory queued work may be lost and the report labels that result correctly.

Load profiles

Run all four profiles:

STEADY     input rate < processing capacity for 120 seconds
BURST      50,000 events as fast as the source can publish
SUSTAINED  input rate 20% above processing capacity for 180 seconds
RECOVERY   source stops; measure time until queue age and depth return to baseline

Measurements and assertions

Collect:

  • publication rate and completion rate;
  • mailbox length where available;
  • outstanding demand and in-flight count;
  • accepted-edge and coalescing-slot occupancy;
  • event age at handler start and completion;
  • per-worker and per-subscriber counts;
  • batch size and wait-time distributions;
  • acknowledgement success and failure totals;
  • scheduler and memory context sufficient to interpret the run.

Avoid asserting exact millisecond values across machines. Assert bounds, accounting identities, and qualitative relationships such as “broadcast throughput decreases when the slow subscriber participates.”

Example final verification transcript

$ mix test test/flow_compare
78 tests, 0 failures

$ mix flow.compare --events 50000 --seed 417
fixture checksum=8f3c2d71 generated=50000
accounting missing=0 duplicate_terminal=0 durable_events_dropped=0
comparison written=tmp/flow_compare/seed-417.json
RESULT pass

Common Pitfalls and Debugging

Problem 1: “Broadway is downstream, so Pub/Sub is backpressured”

  • Symptom: The Broadway processor queue looks bounded, but the subscriber mailbox grows rapidly.
  • Why: Demand stops at the push boundary; publication continues independently.
  • Fix: Add a bounded edge with a class-specific coalesce, reject, or durable-spill policy.
  • Quick test: Pause downstream demand and confirm that every accepted event is still bounded and accounted for.

Problem 2: Using push_messages/2 as a flow-control mechanism

  • Symptom: The bridge injects messages faster than the topology can process them.
  • Why: The API pushes messages and does not wait for downstream demand.
  • Fix: Treat it as an injection mechanism only, or place a real demand-aware producer behind a bounded admission edge.
  • Quick test: Set processor work cost to 500 milliseconds and publish a burst while sampling the bridge mailbox.

Problem 3: Broadcasting work that should be distributed

  • Symptom: The same side effect runs once per consumer.
  • Why: Broadcast semantics replicate every event.
  • Fix: Use competing-consumer semantics for interchangeable workers and retain idempotency at the effect boundary.
  • Quick test: Compare unique event IDs with total handler invocations.

Problem 4: An optional subscriber throttles critical consumers

  • Symptom: All broadcast consumers slow when an analytics subscriber falls behind.
  • Why: Broadcast dispatch waits for participating subscribers’ demand.
  • Fix: Move consumers with different service-level objectives to separate flows or a durable stream.
  • Quick test: Remove the slow consumer and compare group throughput.

Problem 5: Treating acknowledgement as exactly-once execution

  • Symptom: An external side effect occurs twice after a crash.
  • Why: The process failed between the side effect and acknowledgement.
  • Fix: Use stable identifiers and an idempotent effect boundary; document the producer’s redelivery contract.
  • Quick test: Crash immediately after the external-effect stub records success but before acknowledgement.

Problem 6: Assuming Broadway retries failed messages

  • Symptom: Failed messages never return, or they return differently across producers.
  • Why: Retry and redelivery behavior belong to the source integration or custom producer design.
  • Fix: State the retry owner explicitly and test that integration’s acknowledgement mapping.
  • Quick test: Fail one deterministic message and inspect the source-side disposition.

Problem 7: Claiming global ordering after partitioning

  • Symptom: Events from different keys complete in a different order from input.
  • Why: Partitioning permits concurrency across keys; failures may also disturb local completion order.
  • Fix: Promise only the required per-key, per-boundary ordering scope.
  • Quick test: Give one key slow events and observe completion order across another key.

Problem 8: Coalescing business facts

  • Symptom: Intermediate payment, inventory, or audit events vanish.
  • Why: A replaceable-state optimization was applied to immutable facts.
  • Fix: Restrict coalescing by event class and prove the rule with domain invariants.
  • Quick test: Attempt to classify a durable fact as coalescible and require the test to reject it.

Problem 9: The metrics collector becomes the bottleneck

  • Symptom: Enabling metrics changes throughput dramatically.
  • Why: Per-event synchronous logging or high-cardinality labels add excessive work.
  • Fix: Aggregate counters and histograms, sample queue state, and keep event IDs out of metric labels.
  • Quick test: Compare a measurement-only run with a no-output run and report overhead.

Problem 10: Queue length appears healthy while users see stale results

  • Symptom: Queue depth is stable but event latency grows.
  • Why: Event cost or an upstream hidden queue changed.
  • Fix: Measure event age at multiple boundaries using monotonic time.
  • Quick test: Add a fixed upstream delay without changing queue capacity and observe age percentiles.

Debugging sequence

When behavior is unclear, inspect in this order:

  1. Reconcile event IDs and terminal categories.
  2. Draw the actual demand feedback path.
  3. Locate every mailbox and internal buffer.
  4. Measure input rate, service rate, and event age.
  5. Confirm dispatcher semantics.
  6. Confirm acknowledgement and retry ownership.
  7. Inspect per-key skew and slow consumers.
  8. Only then tune concurrency, batch size, or demand thresholds.

Definition of Done

Submit the following artifacts:

  1. A runnable project harness organized around the responsibilities in the architecture section.
  2. A deterministic 50,000-event fixture with seed, checksum, class counts, and eight injected failures.
  3. Raw Pub/Sub, GenStage competing-demand, GenStage broadcast-demand, and Broadway batch modes.
  4. A bounded push-to-demand edge with coalesce, reject, and durable-spill decisions.
  5. Automated tests covering demand bounds, delivery shape, accounting, ordering scope, acknowledgement, overload, and restart behavior.
  6. A comparison report containing the required command transcript fields and all accounting invariants.
  7. A failure-window table for side effect, acknowledgement, crash, and retry sequences.
  8. Architecture decision records for delivery semantics, capacity, overload policy, durability, retry ownership, and ordering.
  9. An operator runbook with thresholds and first-response actions for rising event age, full capacity, failed durable spill, and slow broadcast consumers.
  10. A short reflection answering the project’s core question in your own words.

The project is complete when:

  • all tests pass from a clean checkout;
  • the same seed produces the same fixture checksum and accounting totals;
  • all four modes complete or fail explicitly without hidden event categories;
  • durable_events_dropped=0 in every test and load run;
  • the edge never exceeds configured capacity;
  • the report demonstrates, with measurements, that demand controls the GenStage/Broadway topology but not the upstream Pub/Sub publishers;
  • the report identifies the slow broadcast consumer as the throughput constraint;
  • successful and failed acknowledgement sets are complete and disjoint;
  • ordering claims are scoped by key, boundary, and failure model;
  • no section claims exactly-once execution, automatic retry, or durability without supporting evidence.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • Every merged source contribution is implemented as a phase of this one artifact, not as a separate project.
  • tests show where backpressure stops and explicit shedding begins.

Project 103: Runtime-Configured Cluster-Wide Singleton Job Coordinator

Official topic: Configuration and distribution — Elixir v1.20.2

Source file: lib/elixir/pages/mix-and-otp/config-and-distribution.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: Level 2: Micro-SaaS / Pro Tool
  • Curriculum Difficulty: Level 4: Advanced
  • Knowledge Area: Distribution / Runtime Configuration
  • Software or Tool: runtime.exs, Node, :global, :erpc
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build a two-node recurring-job coordinator whose peers and ports come from runtime configuration, whose owner registers through global, whose state is inspected through erpc, and whose partition limits are documented honestly.

Why it teaches this official topic: The artifact makes application environment, compile versus runtime configuration, distributed nodes and remote calls, global registration trade-offs observable through one bounded build instead of isolated syntax examples.

Scope boundary: Use a singleton ownership problem; exclude distributed KV, secure discovery, PubSub, and full netsplit recovery.

Core challenges you will face:

  • application environment -> identify the accepted case, the counterexample, and the observable result at the runtime.exs, Node, :global, :erpc boundary
  • compile versus runtime configuration -> identify the accepted case, the counterexample, and the observable result at the runtime.exs, Node, :global, :erpc boundary
  • distributed nodes and remote calls -> identify the accepted case, the counterexample, and the observable result at the runtime.exs, Node, :global, :erpc boundary
  • global registration trade-offs -> identify the accepted case, the counterexample, and the observable result at the runtime.exs, Node, :global, :erpc boundary

Real World Outcome

Build a two-node recurring-job coordinator whose peers and ports come from runtime configuration, whose owner registers through global, whose state is inspected through erpc, and whose partition limits are documented honestly. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • One runtime artifact boots with two different configurations.
  • At most one connected-node owner executes a named job.
  • Disconnect behavior exposes global consistency limitations.

Acceptance transcript:

$ mix test --only cluster
SOURCE_TOPIC=mix-and-otp/config-and-distribution.md
ARTIFACT=runtime-configured-cluster-wide-singleton-job-coordinator
CHECK 01 PASS :: One runtime artifact boots with two different configurations
CHECK 02 PASS :: At most one connected-node owner executes a named job
CHECK 03 PASS :: Disconnect behavior exposes global consistency limitations
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“How do runtime configuration and distributed naming make one artifact location-transparent without erasing partition trade-offs?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. application environment
    • Working rule: Make “application environment” an explicit rule at the runtime.exs, Node, :global, :erpc boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "application-environment-positive", focus: "application environment", mode: :positive, expect: :observable} and %{id: "application-environment-negative", focus: "application environment", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Configuration and distribution
  2. compile versus runtime configuration
    • Working rule: Make “compile versus runtime configuration” an explicit rule at the runtime.exs, Node, :global, :erpc boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "compile-versus-runtime-configuration-positive", focus: "compile versus runtime configuration", mode: :positive, expect: :observable} and %{id: "compile-versus-runtime-configuration-negative", focus: "compile versus runtime configuration", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Configuration and distribution
  3. distributed nodes and remote calls
    • Working rule: Make “distributed nodes and remote calls” an explicit rule at the runtime.exs, Node, :global, :erpc boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "distributed-nodes-and-remote-calls-positive", focus: "distributed nodes and remote calls", mode: :positive, expect: :observable} and %{id: "distributed-nodes-and-remote-calls-negative", focus: "distributed nodes and remote calls", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Configuration and distribution
  4. global registration trade-offs
    • Working rule: Make “global registration trade-offs” an explicit rule at the runtime.exs, Node, :global, :erpc boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "global-registration-trade-offs-positive", focus: "global registration trade-offs", mode: :positive, expect: :observable} and %{id: "global-registration-trade-offs-negative", focus: "global registration trade-offs", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Configuration and distribution

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “application environment” be enforced?
    • Which check catches the risk “Compile-time configuration freezes a runtime value”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “One runtime artifact boots with two different configurations”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Configuration and distribution”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: application environment, compile versus runtime configuration, distributed nodes and remote calls, global registration trade-offs. Then trace the named counterexample “Compile-time configuration freezes a runtime value” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose application environment, and what does this project prove about it?”
  2. “What interaction between the concept ‘compile versus runtime configuration’ and the concept ‘application environment’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘Compile-time configuration freezes a runtime value’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with application-environment-positive and compile-time-configuration-freezes-a-runtime-value-counterexample. The first must make the concept “application environment” observable and establish “One runtime artifact boots with two different configurations”; the second must reproduce “Compile-time configuration freezes a runtime value”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for mix-and-otp/config-and-distribution.md
evaluate "application environment" through runtime.exs, Node, :global, :erpc
compare actual evidence with "One runtime artifact boots with two different configurations"
run negative fixture for "Compile-time configuration freezes a runtime value"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix test --only cluster from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Configuration and distribution Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
application environment Elixir in Action, 3rd Edition Ch. 10-11: releases and distributed systems
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement application-environment-positive and prove “One runtime artifact boots with two different configurations”.
  3. Topic coverage: add fixtures for compile versus runtime configuration, distributed nodes and remote calls, global registration trade-offs.
  4. Failure campaign: reproduce each named risk: “Compile-time configuration freezes a runtime value”; “Node cookies or naming modes disagree”; “Global is described as partition-tolerant consensus”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute application-environment-positive, compile-versus-runtime-configuration-positive, distributed-nodes-and-remote-calls-positive, global-registration-trade-offs-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute application-environment-negative, compile-versus-runtime-configuration-negative, distributed-nodes-and-remote-calls-negative, global-registration-trade-offs-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute compile-time-configuration-freezes-a-runtime-value-counterexample, node-cookies-or-naming-modes-disagree-counterexample, global-is-described-as-partition-tolerant-consensus-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix test --only cluster through the real runtime.exs, Node, :global, :erpc boundary from a clean shell.
  • Mutation check: violate “One runtime artifact boots with two different configurations” and prove the suite reports fixture application-environment-positive as failed.
  • Regression corpus: retain the risks “Compile-time configuration freezes a runtime value”; “Node cookies or naming modes disagree”; “Global is described as partition-tolerant consensus” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “Compile-time configuration freezes a runtime value”

  • Why: This breaks one or more observable capabilities at the runtime.exs, Node, :global, :erpc boundary while allowing the happy path to look correct.
  • Fix: Run compile-time-configuration-freezes-a-runtime-value-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix test --only cluster

Problem 2: “Node cookies or naming modes disagree”

  • Why: This breaks one or more observable capabilities at the runtime.exs, Node, :global, :erpc boundary while allowing the happy path to look correct.
  • Fix: Run node-cookies-or-naming-modes-disagree-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix test --only cluster

Problem 3: “Global is described as partition-tolerant consensus”

  • Why: This breaks one or more observable capabilities at the runtime.exs, Node, :global, :erpc boundary while allowing the happy path to look correct.
  • Fix: Run global-is-described-as-partition-tolerant-consensus-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix test --only cluster

Definition of Done

  • One runtime artifact boots with two different configurations.
  • At most one connected-node owner executes a named job.
  • Disconnect behavior exposes global consistency limitations.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 104: Secure Multi-Network Cluster Formation Lab

Source: BEAM-P11. Join nodes across network zones with explicit naming, discovery, and secure distribution.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir or Erlang
  • Alternative Programming Languages: Gleam
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: Level 4: Open Core Infrastructure
  • Curriculum Difficulty: Level 4: Advanced
  • Knowledge Area: Distribution, Cluster Operations
  • Software or Tool: Distributed Erlang + TLS Distribution
  • Main Book: “Programming Erlang”

What you will build: Join nodes across network zones with explicit naming, discovery, and secure distribution.

Why it teaches the BEAM ecosystem: It makes you prove that membership and security failures are diagnosed from live evidence.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Join nodes across network zones with explicit naming, discovery, and secure distribution.

A cluster bootstrap toolkit with commands to show topology, validate links, and confirm cross-network process reachability.

$ clusterctl topology
site=us-east ...

3.7.1 How to Run (Copy/Paste)

  • Start nodes per site with your environment bootstrap script.
  • Run clusterctl topology and clusterctl ping probes.

3.7.2 Golden Path Demo (Deterministic) Two sites join, probes succeed, topology reports all expected links.

3.7.3 If CLI: exact terminal transcript

$ clusterctl topology
site=us-east nodes=[edge-us-1,edge-us-2]
site=eu-west nodes=[edge-eu-1,edge-eu-2]
links=8 secure=true

The Core Question You Are Answering

“How do I keep distributed-node operations deterministic when infrastructure is non-deterministic?”

Concepts You Must Understand First

  1. Node naming and distribution identity
  2. Secure distribution channels
  3. Supervisor boundaries for infrastructure processes

Questions to Guide Your Design

  1. Which links are mandatory and which are optional?
  2. What exact signals define healthy vs degraded state?
  3. How do you expose failures so operators can act fast?

Thinking Exercise

Topology Contract

Draw two sites and one DR site. Mark exactly which node pairs are allowed to connect and which are explicitly blocked.

Questions to answer:

  • Which links are mandatory for quorum-critical services?
  • Which links can be lazy or on-demand?

The Interview Questions They Will Ask

  1. “How do you connect Erlang nodes across different private networks?”
  2. “Why is TLS distribution important in BEAM clusters?”
  3. “How do you debug node reachability without guessing?”
  4. “What are common causes of cross-site node flapping?”

Hints in Layers

Hint 1: Starting Point Start with two nodes in different subnets and verify bidirectional ping.

Hint 2: Next Level Add gateway nodes and route inter-site traffic through them.

Hint 3: Technical Details Pseudocode:

for each site:
  connect local mesh
connect site gateways
monitor remote gateway status

Hint 4: Tools/Debugging Track nodeup/nodedown events and correlate with network ACL changes.

Books That Will Help

Topic Book Chapter
Distributed Erlang “Programming Erlang” Distributed Erlang chapter
Cluster reliability “Designing for Scalability with Erlang/OTP” Reliability and operations chapters

Implementation Milestones

Milestone 1 — Contract and fixture: define one representative input, output, invariant, and failure case.

Milestone 2 — Core artifact: Join nodes across network zones with explicit naming, discovery, and secure distribution.

Milestone 3 — Failure behavior: add timeouts, invalid inputs, crashes, retries, or partitions appropriate to the project.

Milestone 4 — Evidence: automate the definition of done and record a reproducible result.

Testing Strategy

  • Unit checks: pure parsing, validation, transition, and formatting decisions.
  • Integration checks: the real process, database, socket, notebook, or framework boundary.
  • Failure checks: malformed input plus at least one crash, timeout, duplicate, overload, or partition scenario.
  • Acceptance check: independently demonstrate that membership and security failures are diagnosed from live evidence.
  • Avoid arbitrary sleeps; use messages, monitors, deterministic clocks, fixtures, and deadlines where applicable.

Common Pitfalls and Debugging

Problem 1: “Nodes connect locally but never connect across networks”

  • Why: Name resolution, cookie mismatch, or blocked distribution ports.
  • Fix: Verify names, cookies, and firewall rules on both ends.
  • Quick test: Run a node-to-node ping plus a remote rpc call.

Definition of Done

  • Two or more network segments form one logical BEAM cluster
  • Cross-site ping and remote calls work consistently
  • TLS distribution path is documented and validated
  • Cluster topology command exposes node/link health

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • membership and security failures are diagnosed from live evidence.

Project 105: Three-Node Distributed Phoenix.PubSub Lab

Sources: PHX-P10, PUB-P10. Test adapter topology, pool migration, partition, and healing.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: Level 4: Open Core Infrastructure
  • Curriculum Difficulty: Level 4: Advanced
  • Knowledge Area: Distributed systems, topology, partitions, rolling deploys
  • Software or Tool: Distributed Erlang, Phoenix.PubSub.PG2, :pg, libcluster (optional)
  • Main Book: “Designing for Scalability with Erlang/OTP” by Cesarini & Vinoski

What you will build: Test adapter topology, pool migration, partition, and healing.

Why it teaches the BEAM ecosystem: It makes you prove that transient gaps and reload recovery match the delivery contract.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Integrated Scope

This is one consolidated project, not separate source builds. Implement the following contributions as phases of the same artifact:

  • Establish PHX-P10 node discovery and distributed PubSub behavior.
  • Run the PUB-P10 three-node topology, pool migration, partition, heal, and reload-recovery drills.

Real World Outcome

Build target: Test adapter topology, pool migration, partition, and healing.

Build a local laboratory with nodes alpha@lab, beta@lab, and gamma@lab. Each node runs the same supervised application, one Phoenix.PubSub instance, a probe subscriber, a topology observer, a revision tracker, and a small status endpoint or terminal panel.

The lab controller starts and stops nodes, requests connectivity snapshots from each one, waits for adapter group convergence, publishes numbered probes, injects a deterministic partition, heals it, and validates application catch-up.

The authoritative revision store may be a small disposable PostgreSQL table or one deliberately centralized training service. It must be clearly separate from PubSub. When alpha commits revision 42 during gamma’s isolation, gamma misses the transient probe. After reconnection, gamma queries the authority and updates from 41 to 42.

The final drill changes PubSub from pool size 1 to 2. A continuous publisher emits sequence probes throughout both deployment stages. The first stage runs the new pool while broadcasting compatibly with the old size; the second removes compatibility after all nodes are upgraded.

$ ./lab cluster status
node matrix:
  alpha -> [beta,gamma]
  beta  -> [alpha,gamma]
  gamma -> [alpha,beta]
topology=full_mesh PASS
pubsub shard=0 members alpha=3 beta=3 gamma=3 converged=true

publish sequence=41 revision=41 from=alpha
observed alpha=12ms beta=18ms gamma=21ms PASS

partition applied component_A=[alpha,beta] component_B=[gamma]
publish sequence=42 revision=42 from=alpha
observed=[alpha,beta] gamma=MISS_EXPECTED

partition healed
node_views_converged=true pg_views_converged=true
gamma last_observed=41 authoritative=42 gap=1
gamma reload revision=42 source=authoritative_store PASS

pool_migration stage=compat pool_size=2 broadcast_pool_size=1 probes=500 gaps=0
pool_migration stage=final  pool_size=2 broadcast_pool_size=2 probes=500 gaps=0
cleanup residual_nodes=0 residual_partition_rules=0
lab result=PASS

Run three terminals or open the lab’s topology page. The normal-state view shows a 3×3 adjacency matrix with symmetric direct connections, one PubSub shard containing one forwarding member per node, and three subscribers on the selected topic. Publish revision 41 and watch all three node timelines add the same event with different arrival latencies.

Activate “Partition Gamma.” The topology view splits into two colored components. Alpha and beta show node-down for gamma; gamma shows isolation from both. Publishing revision 42 produces green delivery markers only on alpha and beta and an explicit gray MISS_EXPECTED marker on gamma. The system must never paint gamma green merely because membership later heals.

Heal the partition. Node and process-group views converge. Gamma’s revision card remains 41 until its recovery path compares against the authoritative revision. It then reloads 42 and labels the transition recovered_from_authority, not replayed_by_pubsub.

Finally, start a continuous probe and perform the pool-size migration. The dashboard overlays rollout stage, node version, configured pool size, broadcast pool size, and any gap. Completion evidence shows no gaps during healthy-network migration, while the earlier partition gap remains documented as expected transient loss.

The Core Question You Are Answering

“What does cluster Pub/Sub guarantee when node views diverge, and how does the application recover facts after connectivity returns?”

Your answer must distinguish current connected component, current membership view, transient message delivery, and authoritative application state. “The cluster heals” is incomplete unless it states what converges and what does not replay.

Concepts You Must Understand First

  1. Distributed Erlang nodes
    • What makes a node name resolvable and a connection authenticated?
    • Which failures appear as nodedown and when?
    • Book Reference: “Designing for Scalability with Erlang/OTP” — distributed architecture chapters.
  2. Topology and discovery
    • Does discovery return candidates or guarantee live full-mesh connectivity?
    • How will every node prove its direct peers?
    • Reference: Erlang distributed-system documentation and chosen discovery adapter docs.
  3. :pg membership
    • What does strong eventual consistency permit during convergence?
    • Why is membership non-transitive?
    • Reference: OTP 29 pg documentation.
  4. Phoenix.PubSub adapter behavior
    • What is local subscription versus cluster forwarding?
    • How do pool shards and remote members relate?
    • Reference: Phoenix.PubSub and Phoenix.PubSub.PG2 documentation.
  5. Revision-based recovery
    • Which system stores authoritative facts?
    • How does a subscriber detect and repair a gap?
    • Book Reference: “Designing Data-Intensive Applications, 2nd Edition” — distributed-system trouble.

Questions to Guide Your Design

  1. Proof quality
    • Are topology and membership sampled from all three nodes?
    • Are intermediate divergent views preserved instead of waiting silently?
  2. Partition mechanism
    • Can isolation be applied and removed deterministically?
    • What cleanup runs after an assertion failure or interrupted shell?
  3. Clock and ordering
    • Which results use monotonic time, and which display wall-clock time?
    • Does sequence, not timestamp, determine missing messages?
  4. Recovery
    • Is the source a current-state reload or durable event replay?
    • How are stale and missing revisions labeled differently?
  5. Migration
    • Which config is deployed in stage A and stage B?
    • How does a probe distinguish network loss from migration loss?

Thinking Exercise

Draw both topologies:

FULL MESH                         HUB AND SPOKE
 alpha ───── beta                 alpha ───── beta ───── gamma
   │  ╲       │                  alpha X gamma direct connection
   │    ╲     │
   └──── gamma

For each node, list Node.list and possible :pg members. Then partition {alpha,beta} from {gamma} and predict:

  • node monitor signals;
  • adapter membership visible from each component;
  • delivery of sequences 41, 42, and 43;
  • what happens to a subscriber that joins during isolation;
  • what membership converges after heal;
  • why sequence 42 remains absent on gamma;
  • which authoritative operation repairs gamma.

Record predictions before running the lab and compare every mismatch.

The Interview Questions They Will Ask

  1. “Does Phoenix.PubSub discover or connect Erlang nodes?”
  2. “What consistency model does :pg provide?”
  3. “Are :pg membership views transitive through a hub?”
  4. “What happens to PubSub broadcasts during a partition?”
  5. “How does an application repair state after the partition heals?”
  6. “How do you safely increase Phoenix.PubSub pool size during a rolling deploy?”

Hints in Layers

Hint 1: Prove the transport before the abstraction

Render the direct-peer matrix before inspecting PubSub. A wrong matrix invalidates later assumptions.

Hint 2: Number every probe

Use one bounded stream of monotonically increasing sequence numbers. Do not infer loss from wall-clock gaps.

Hint 3: Keep convergence and recovery separate

Produce two verdicts after heal:

membership_converged=true
application_revision_recovered=true source=authoritative_reload

Hint 4: Migrate while noisy

A quiet rolling deployment proves only startup. Continuous probes reveal compatibility gaps.

Books That Will Help

Topic Book Chapter / Section
Distributed OTP “Designing for Scalability with Erlang/OTP” Distribution and distributed architectures
Network partitions “Designing Data-Intensive Applications, 2nd Edition” Distributed-System Trouble
Rollouts and stability “Release It!, 2nd Edition” Stability Patterns
Architecture evidence “Software Architecture in Practice, 4th Edition” Quality Attribute Scenarios

Implementation Milestones

Integrated basic-to-advanced progression

  1. Establish PHX-P10 node discovery and distributed PubSub behavior.
  2. Run the PUB-P10 three-node topology, pool migration, partition, heal, and reload-recovery drills.

Milestone 1 — Contract and fixture: define one representative input, output, invariant, and failure case.

Milestone 2 — Core artifact: Test adapter topology, pool migration, partition, and healing.

Milestone 3 — Failure behavior: add timeouts, invalid inputs, crashes, retries, or partitions appropriate to the project.

Milestone 4 — Evidence: automate the definition of done and record a reproducible result.

Phase 1: Topology and Membership Observatory (8–12 hours)

Goals

  • Start three isolated nodes.
  • Prove full mesh and adapter membership from every node.

Tasks

  1. Create lifecycle and teardown interfaces.
  2. Add node monitoring and symmetric peer snapshots.
  3. Add per-shard group snapshots with deadlines.
  4. Add bounded sequence publisher/subscribers.
  5. Export a normal-state topology report.

Checkpoint: Revision 41 reaches all nodes, every node reports two peers, every shard view converges, and teardown leaves no residual runtime.

Phase 2: Partition and Authoritative Recovery (8–14 hours)

Goals

  • Observe component-local fanout.
  • Repair missed facts after heal.

Tasks

  1. Implement deterministic gamma isolation and cleanup.
  2. Capture intermediate node/group views.
  3. Commit and publish revision 42 during isolation.
  4. Heal connectivity and wait for convergence.
  5. Detect gamma’s gap and reload authoritative state.

Checkpoint: Gamma explicitly misses transient 42, later converges membership, and recovers revision 42 only through the authority.

Phase 3: Safe Pool Migration and Certification (8–14 hours)

Goals

  • Exercise mixed configuration safely.
  • Produce repeatable migration evidence.

Tasks

  1. Define stage-A and stage-B runtime configurations.
  2. Start a fixed-rate sequence probe.
  3. Roll alpha, beta, and gamma one at a time through compatibility.
  4. Roll them again to final configuration.
  5. Attribute gaps, validate cleanup, and publish the lab report.

Checkpoint: At least 1,000 healthy-network probes across the two stages show zero migration gap, and the report still preserves the expected partition loss separately.

Testing Strategy

6.1 Test Categories

Category Purpose Examples
Local unit Validate matrices, gaps, and verdicts Symmetric edges, missing sequence ranges
Multi-node integration Verify real distribution Full mesh, shard membership, cross-node probe
Partition Verify component-local behavior Gamma isolation and heal
Recovery Verify durable catch-up Cursor 41 to authority 42
Churn Verify process/node lifecycle Subscriber crash, adapter restart, node restart
Migration Verify mixed pool configuration Stage A and B under continuous probes
Security/cleanup Verify isolation Wrong credential denial, no residual ports/rules

6.2 Critical Test Cases

  1. Full mesh: Every node sees the other two directly and group views converge.
  2. Hub/spoke counterexample: Alpha and gamma both see beta but not each other; non-transitive membership is exposed.
  3. Normal fanout: Sequence 41 appears once on all expected subscribers.
  4. Partition delivery: Sequence 42 remains inside {alpha,beta}; gamma’s miss is expected.
  5. Local gamma publish: During isolation, gamma’s publish remains in its component and does not reach alpha/beta.
  6. Heal convergence: Node and group views converge within measured budgets.
  7. No replay: Sequence 42 does not spontaneously arrive on gamma after heal.
  8. Revision repair: Gamma reloads authoritative revision 42 and records the source.
  9. Adapter restart: Local subscriptions/members recover through supervision; temporary divergence is measured.
  10. Pool migration: Continuous healthy-network probes show no stage-induced gaps.
  11. Wrong credential: An unauthorized fourth node cannot join.
  12. Cleanup: Interrupted drill still removes partition controls and terminates nodes.

6.3 Test Data

run_id: lab-2026-07-15-01
nodes: [alpha@lab, beta@lab, gamma@lab]
topic: lab:tenant42:orders
initial_pool_size: 1
target_pool_size: 2

probes:
  41 -> before partition, expected [alpha,beta,gamma]
  42 -> during partition, publisher alpha, expected [alpha,beta]
  43 -> during partition, publisher gamma, expected [gamma]
  44 -> after heal, expected [alpha,beta,gamma]

authoritative revisions:
  before partition: 41
  during partition: 42
  gamma recovery target: 42

migration:
  stage A: pool_size=2 broadcast_pool_size=1 probes=1000
  stage B: pool_size=2 broadcast_pool_size=2 probes=1000

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Pitfall Symptom Solution
Assuming discovery equals topology Candidates exist but probes miss nodes Capture direct-peer matrix from every node
Checking only beta Hub appears healthy while edges disagree Require symmetric all-node snapshots
Waiting with arbitrary sleep Flaky convergence test Poll explicit conditions with deadline and evidence
Expecting replay after heal Gamma never sees 42 Reload/replay from durable authority
Hiding expected loss Dashboard reports false success Label expected transient misses and repair separately
One-step pool increase Gaps during mixed rollout Use broadcast_pool_size compatibility stage
Shared production cookie Lab can join privileged cluster Generate isolated per-run credential and network
Failed teardown Later runs start in a partitioned state Make cleanup idempotent and verify residual state

7.2 Debugging Strategies

  • Work bottom-up: node names/resolution → direct connections → group views → adapter forwarding → subscriber receipt.
  • Inspect every node: a global-looking view from one node may be uniquely complete.
  • Preserve divergence: log membership snapshots with observer identity and time.
  • Compare components: classify each delivery against the component graph at publication time.
  • Use sequence ranges: calculate missing sets per node rather than reading interleaved terminal logs.
  • Separate restart from reconnect: a restarted process has a new PID and may need to rejoin even if the node never disconnected.
  • Run cleanup doctor: before a new drill, confirm no old nodes, ports, or network filters remain.

7.3 Performance Traps

  • Excessive topology polling adds distribution traffic and can distort convergence measurements.
  • Broadcasting probes too quickly can make subscriber mailboxes the bottleneck instead of the network fault under study.
  • Storing every observation forever creates quadratic evidence growth.
  • Large PubSub pool sizes add processes and group membership traffic; bigger is not automatically faster.
  • Blocking report generation in subscriber processes delays receipt and produces misleading gaps.
  • DNS or discovery retry storms can hide the original partition under control-plane load.

Definition of Done

Minimum Viable Completion

  • Three nodes form and prove a symmetric full mesh.
  • A numbered probe reaches all nodes in normal state.
  • Gamma isolation produces the predicted component-local delivery.
  • Healing restores topology and membership visibility.
  • Gamma catches up from an authoritative revision source.

Full Completion

  • All minimum criteria plus captured intermediate membership divergence, bounded evidence, security documentation, and idempotent teardown.
  • The lab distinguishes node convergence, group convergence, transient non-replay, and durable state recovery.
  • A two-stage 1→2 pool migration runs under at least 1,000 continuous probes with zero migration-induced gaps.
  • The final report includes matrices, timelines, sequence sets, convergence durations, and residual-state checks.

Excellence (Going Above & Beyond)

  • The lab supports static and dynamic discovery while retaining the same evidence contract.
  • TLS distribution and credential rotation are automated and verified.
  • Asymmetric latency/loss tests produce explainable convergence and delivery histories.
  • A history checker automatically validates component-aware delivery and eventual revision recovery.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • Every merged source contribution is implemented as a phase of this one artifact, not as a separate project.
  • transient gaps and reload recovery match the delivery contract.

Project 106: Set-Theoretic Type Diagnostic Laboratory

Official topic: Gradual set-theoretic types — Elixir v1.20.2

Source file: lib/elixir/pages/references/gradual-set-theoretic-types.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: Level 2: Micro-SaaS / Pro Tool
  • Curriculum Difficulty: Level 4: Advanced
  • Knowledge Area: Compiler Types / Verification
  • Software or Tool: Elixir compiler type checker
  • Main Book: Programming Elixir >= 1.6

What you will build: Build a harness that compiles isolated fixtures, captures each diagnostic and exit status, and classifies inferred warnings, unions, intersections, negations, open and closed maps, function intersections, dynamic ranges, refinements, and documented false positives.

Why it teaches this official topic: The artifact makes sound gradual typing, unions, intersections, and negation, dynamic type ranges, type inference and refinements observable through one bounded build instead of isolated syntax examples.

Scope boundary: Own compiler-native inference diagnostics; exclude Dialyzer contracts, runtime validation, and generic test tooling.

Core challenges you will face:

  • sound gradual typing -> identify the accepted case, the counterexample, and the observable result at the Elixir compiler type checker boundary
  • unions, intersections, and negation -> identify the accepted case, the counterexample, and the observable result at the Elixir compiler type checker boundary
  • dynamic type ranges -> identify the accepted case, the counterexample, and the observable result at the Elixir compiler type checker boundary
  • type inference and refinements -> identify the accepted case, the counterexample, and the observable result at the Elixir compiler type checker boundary

Real World Outcome

Build a harness that compiles isolated fixtures, captures each diagnostic and exit status, and classifies inferred warnings, unions, intersections, negations, open and closed maps, function intersections, dynamic ranges, refinements, and documented false positives. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Every warning fixture has an explained value-set conflict.
  • Dynamic boundaries remain explicit rather than becoming any.
  • Known false positives are pinned with compiler-version evidence.

Acceptance transcript:

$ mix run scripts/verify_type_diagnostics.exs
SOURCE_TOPIC=references/gradual-set-theoretic-types.md
ARTIFACT=set-theoretic-type-diagnostic-laboratory
CHECK 01 PASS :: Every warning fixture has an explained value-set conflict
CHECK 02 PASS :: Dynamic boundaries remain explicit rather than becoming any
CHECK 03 PASS :: Known false positives are pinned with compiler-version evidence
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“How can gradual set-theoretic typing add sound information to dynamic Elixir code without requiring all boundaries to be typed?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. sound gradual typing
    • Working rule: Make “sound gradual typing” an explicit rule at the Elixir compiler type checker boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "sound-gradual-typing-positive", focus: "sound gradual typing", mode: :positive, expect: :observable} and %{id: "sound-gradual-typing-negative", focus: "sound gradual typing", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Gradual set-theoretic types
  2. unions, intersections, and negation
    • Working rule: Make “unions, intersections, and negation” an explicit rule at the Elixir compiler type checker boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "unions-intersections-and-negation-positive", focus: "unions, intersections, and negation", mode: :positive, expect: :observable} and %{id: "unions-intersections-and-negation-negative", focus: "unions, intersections, and negation", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Gradual set-theoretic types
  3. dynamic type ranges
    • Working rule: Make “dynamic type ranges” an explicit rule at the Elixir compiler type checker boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "dynamic-type-ranges-positive", focus: "dynamic type ranges", mode: :positive, expect: :observable} and %{id: "dynamic-type-ranges-negative", focus: "dynamic type ranges", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Gradual set-theoretic types
  4. type inference and refinements
    • Working rule: Make “type inference and refinements” an explicit rule at the Elixir compiler type checker boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "type-inference-and-refinements-positive", focus: "type inference and refinements", mode: :positive, expect: :observable} and %{id: "type-inference-and-refinements-negative", focus: "type inference and refinements", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Gradual set-theoretic types

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “sound gradual typing” be enforced?
    • Which check catches the risk “A runtime check is confused with a static refinement”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Every warning fixture has an explained value-set conflict”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Gradual set-theoretic types”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: sound gradual typing, unions, intersections, and negation, dynamic type ranges, type inference and refinements. Then trace the named counterexample “A runtime check is confused with a static refinement” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose sound gradual typing, and what does this project prove about it?”
  2. “What interaction between the concept ‘unions, intersections, and negation’ and the concept ‘sound gradual typing’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘A runtime check is confused with a static refinement’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with sound-gradual-typing-positive and a-runtime-check-is-confused-with-a-static-refinement-counterexample. The first must make the concept “sound gradual typing” observable and establish “Every warning fixture has an explained value-set conflict”; the second must reproduce “A runtime check is confused with a static refinement”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for references/gradual-set-theoretic-types.md
evaluate "sound gradual typing" through Elixir compiler type checker
compare actual evidence with "Every warning fixture has an explained value-set conflict"
run negative fixture for "A runtime check is confused with a static refinement"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/verify_type_diagnostics.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Gradual set-theoretic types Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
sound gradual typing Programming Elixir >= 1.6 Ch. 6: modules and type specifications
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement sound-gradual-typing-positive and prove “Every warning fixture has an explained value-set conflict”.
  3. Topic coverage: add fixtures for unions, intersections, and negation, dynamic type ranges, type inference and refinements.
  4. Failure campaign: reproduce each named risk: “A runtime check is confused with a static refinement”; “Dynamic is treated as an unsound top type”; “A compiler roadmap item is asserted as current behavior”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute sound-gradual-typing-positive, unions-intersections-and-negation-positive, dynamic-type-ranges-positive, type-inference-and-refinements-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute sound-gradual-typing-negative, unions-intersections-and-negation-negative, dynamic-type-ranges-negative, type-inference-and-refinements-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute a-runtime-check-is-confused-with-a-static-refinement-counterexample, dynamic-is-treated-as-an-unsound-top-type-counterexample, a-compiler-roadmap-item-is-asserted-as-current-behavior-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/verify_type_diagnostics.exs through the real Elixir compiler type checker boundary from a clean shell.
  • Mutation check: violate “Every warning fixture has an explained value-set conflict” and prove the suite reports fixture sound-gradual-typing-positive as failed.
  • Regression corpus: retain the risks “A runtime check is confused with a static refinement”; “Dynamic is treated as an unsound top type”; “A compiler roadmap item is asserted as current behavior” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “A runtime check is confused with a static refinement”

  • Why: This breaks one or more observable capabilities at the Elixir compiler type checker boundary while allowing the happy path to look correct.
  • Fix: Run a-runtime-check-is-confused-with-a-static-refinement-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_type_diagnostics.exs

Problem 2: “Dynamic is treated as an unsound top type”

  • Why: This breaks one or more observable capabilities at the Elixir compiler type checker boundary while allowing the happy path to look correct.
  • Fix: Run dynamic-is-treated-as-an-unsound-top-type-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_type_diagnostics.exs

Problem 3: “A compiler roadmap item is asserted as current behavior”

  • Why: This breaks one or more observable capabilities at the Elixir compiler type checker boundary while allowing the happy path to look correct.
  • Fix: Run a-compiler-roadmap-item-is-asserted-as-current-behavior-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/verify_type_diagnostics.exs

Definition of Done

  • Every warning fixture has an explained value-set conflict.
  • Dynamic boundaries remain explicit rather than becoming any.
  • Known false positives are pinned with compiler-version evidence.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 107: Quoted-Expression Transformation Sandbox

Official topic: Quote and unquote — Elixir v1.20.2

Source file: lib/elixir/pages/meta-programming/quote-and-unquote.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: Level 2: Micro-SaaS / Pro Tool
  • Curriculum Difficulty: Level 4: Advanced
  • Knowledge Area: Metaprogramming / AST
  • Software or Tool: quote, unquote, Macro.escape
  • Main Book: Metaprogramming Elixir

What you will build: Build an interactive sandbox that visualizes source to AST, metadata and context, injected and spliced AST, rendered source, escaped values, and explicit rejection of non-escapable runtime values.

Why it teaches this official topic: The artifact makes three-element AST nodes, quote and unquote, unquote splicing, value versus AST escaping observable through one bounded build instead of isolated syntax examples.

Scope boundary: Remain an AST and value teaching instrument; exclude migration linting and compiled-bytecode inspection.

Core challenges you will face:

  • three-element AST nodes -> identify the accepted case, the counterexample, and the observable result at the quote, unquote, Macro.escape boundary
  • quote and unquote -> identify the accepted case, the counterexample, and the observable result at the quote, unquote, Macro.escape boundary
  • unquote splicing -> identify the accepted case, the counterexample, and the observable result at the quote, unquote, Macro.escape boundary
  • value versus AST escaping -> identify the accepted case, the counterexample, and the observable result at the quote, unquote, Macro.escape boundary

Real World Outcome

Build an interactive sandbox that visualizes source to AST, metadata and context, injected and spliced AST, rendered source, escaped values, and explicit rejection of non-escapable runtime values. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Every fixture shows source AST and rendered form.
  • Injected values and injected AST remain distinguishable.
  • Unsupported runtime values fail with an escape explanation.

Acceptance transcript:

$ mix run scripts/ast_sandbox.exs
SOURCE_TOPIC=meta-programming/quote-and-unquote.md
ARTIFACT=quoted-expression-transformation-sandbox
CHECK 01 PASS :: Every fixture shows source AST and rendered form
CHECK 02 PASS :: Injected values and injected AST remain distinguishable
CHECK 03 PASS :: Unsupported runtime values fail with an escape explanation
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“Where is the boundary between Elixir code represented as data and ordinary runtime data inserted into that code?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. three-element AST nodes
    • Working rule: Make “three-element AST nodes” an explicit rule at the quote, unquote, Macro.escape boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "three-element-ast-nodes-positive", focus: "three-element AST nodes", mode: :positive, expect: :observable} and %{id: "three-element-ast-nodes-negative", focus: "three-element AST nodes", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Quote and unquote
  2. quote and unquote
    • Working rule: Make “quote and unquote” an explicit rule at the quote, unquote, Macro.escape boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "quote-and-unquote-positive", focus: "quote and unquote", mode: :positive, expect: :observable} and %{id: "quote-and-unquote-negative", focus: "quote and unquote", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Quote and unquote
  3. unquote splicing
    • Working rule: Make “unquote splicing” an explicit rule at the quote, unquote, Macro.escape boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "unquote-splicing-positive", focus: "unquote splicing", mode: :positive, expect: :observable} and %{id: "unquote-splicing-negative", focus: "unquote splicing", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Quote and unquote
  4. value versus AST escaping
    • Working rule: Make “value versus AST escaping” an explicit rule at the quote, unquote, Macro.escape boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "value-versus-ast-escaping-positive", focus: "value versus AST escaping", mode: :positive, expect: :observable} and %{id: "value-versus-ast-escaping-negative", focus: "value versus AST escaping", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Quote and unquote

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “three-element AST nodes” be enforced?
    • Which check catches the risk “An AST is passed where a runtime value is expected”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Every fixture shows source AST and rendered form”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Quote and unquote”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: three-element AST nodes, quote and unquote, unquote splicing, value versus AST escaping. Then trace the named counterexample “An AST is passed where a runtime value is expected” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose three-element AST nodes, and what does this project prove about it?”
  2. “What interaction between the concept ‘quote and unquote’ and the concept ‘three-element AST nodes’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘An AST is passed where a runtime value is expected’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with three-element-ast-nodes-positive and an-ast-is-passed-where-a-runtime-value-is-expected-counterexample. The first must make the concept “three-element AST nodes” observable and establish “Every fixture shows source AST and rendered form”; the second must reproduce “An AST is passed where a runtime value is expected”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for meta-programming/quote-and-unquote.md
evaluate "three-element AST nodes" through quote, unquote, Macro.escape
compare actual evidence with "Every fixture shows source AST and rendered form"
run negative fixture for "An AST is passed where a runtime value is expected"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/ast_sandbox.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Quote and unquote Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
three-element AST nodes Metaprogramming Elixir Ch. 1-2: the AST and quote
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement three-element-ast-nodes-positive and prove “Every fixture shows source AST and rendered form”.
  3. Topic coverage: add fixtures for quote and unquote, unquote splicing, value versus AST escaping.
  4. Failure campaign: reproduce each named risk: “An AST is passed where a runtime value is expected”; “Metadata makes structural comparison nondeterministic”; “Unquote splicing receives a non-list AST”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute three-element-ast-nodes-positive, quote-and-unquote-positive, unquote-splicing-positive, value-versus-ast-escaping-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute three-element-ast-nodes-negative, quote-and-unquote-negative, unquote-splicing-negative, value-versus-ast-escaping-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute an-ast-is-passed-where-a-runtime-value-is-expected-counterexample, metadata-makes-structural-comparison-nondeterministic-counterexample, unquote-splicing-receives-a-non-list-ast-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/ast_sandbox.exs through the real quote, unquote, Macro.escape boundary from a clean shell.
  • Mutation check: violate “Every fixture shows source AST and rendered form” and prove the suite reports fixture three-element-ast-nodes-positive as failed.
  • Regression corpus: retain the risks “An AST is passed where a runtime value is expected”; “Metadata makes structural comparison nondeterministic”; “Unquote splicing receives a non-list AST” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “An AST is passed where a runtime value is expected”

  • Why: This breaks one or more observable capabilities at the quote, unquote, Macro.escape boundary while allowing the happy path to look correct.
  • Fix: Run an-ast-is-passed-where-a-runtime-value-is-expected-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/ast_sandbox.exs

Problem 2: “Metadata makes structural comparison nondeterministic”

  • Why: This breaks one or more observable capabilities at the quote, unquote, Macro.escape boundary while allowing the happy path to look correct.
  • Fix: Run metadata-makes-structural-comparison-nondeterministic-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/ast_sandbox.exs

Problem 3: “Unquote splicing receives a non-list AST”

  • Why: This breaks one or more observable capabilities at the quote, unquote, Macro.escape boundary while allowing the happy path to look correct.
  • Fix: Run unquote-splicing-receives-a-non-list-ast-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/ast_sandbox.exs

Definition of Done

  • Every fixture shows source AST and rendered form.
  • Injected values and injected AST remain distinguishable.
  • Unsupported runtime values fail with an escape explanation.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 108: Hygienic Macro Expansion Observatory

Official topic: Macros — Elixir v1.20.2

Source file: lib/elixir/pages/meta-programming/macros.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: Level 2: Micro-SaaS / Pro Tool
  • Curriculum Difficulty: Level 4: Advanced
  • Knowledge Area: Metaprogramming / Hygiene
  • Software or Tool: Macro.expand, Macro.Env, var!
  • Main Book: Metaprogramming Elixir

What you will build: Build an interactive observatory that expands fixture macros, displays variable, import, alias, and caller contexts, detects deliberate hygiene leaks, and verifies that macro wrappers delegate runtime work to functions.

Why it teaches this official topic: The artifact makes macro expansion, variable hygiene, caller environment, responsible macro APIs observable through one bounded build instead of isolated syntax examples.

Scope boundary: Focus on Elixir expansion and hygiene; exclude Erlang parse transforms and general static analysis.

Core challenges you will face:

  • macro expansion -> identify the accepted case, the counterexample, and the observable result at the Macro.expand, Macro.Env, var! boundary
  • variable hygiene -> identify the accepted case, the counterexample, and the observable result at the Macro.expand, Macro.Env, var! boundary
  • caller environment -> identify the accepted case, the counterexample, and the observable result at the Macro.expand, Macro.Env, var! boundary
  • responsible macro APIs -> identify the accepted case, the counterexample, and the observable result at the Macro.expand, Macro.Env, var! boundary

Real World Outcome

Build an interactive observatory that expands fixture macros, displays variable, import, alias, and caller contexts, detects deliberate hygiene leaks, and verifies that macro wrappers delegate runtime work to functions. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Expansion output labels generated and caller variables.
  • Deliberate var leaks are detected by a fixture.
  • Generated wrappers remain small under an AST-size budget.

Acceptance transcript:

$ mix run scripts/macro_observe.exs
SOURCE_TOPIC=meta-programming/macros.md
ARTIFACT=hygienic-macro-expansion-observatory
CHECK 01 PASS :: Expansion output labels generated and caller variables
CHECK 02 PASS :: Deliberate var leaks are detected by a fixture
CHECK 03 PASS :: Generated wrappers remain small under an AST-size budget
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“How can a macro transform caller code while keeping names, environment, and generated work predictable?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. macro expansion
    • Working rule: Make “macro expansion” an explicit rule at the Macro.expand, Macro.Env, var! boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "macro-expansion-positive", focus: "macro expansion", mode: :positive, expect: :observable} and %{id: "macro-expansion-negative", focus: "macro expansion", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Macros
  2. variable hygiene
    • Working rule: Make “variable hygiene” an explicit rule at the Macro.expand, Macro.Env, var! boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "variable-hygiene-positive", focus: "variable hygiene", mode: :positive, expect: :observable} and %{id: "variable-hygiene-negative", focus: "variable hygiene", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Macros
  3. caller environment
    • Working rule: Make “caller environment” an explicit rule at the Macro.expand, Macro.Env, var! boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "caller-environment-positive", focus: "caller environment", mode: :positive, expect: :observable} and %{id: "caller-environment-negative", focus: "caller environment", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Macros
  4. responsible macro APIs
    • Working rule: Make “responsible macro APIs” an explicit rule at the Macro.expand, Macro.Env, var! boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "responsible-macro-apis-positive", focus: "responsible macro APIs", mode: :positive, expect: :observable} and %{id: "responsible-macro-apis-negative", focus: "responsible macro APIs", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Macros

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “macro expansion” be enforced?
    • Which check catches the risk “A macro captures caller state accidentally”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Expansion output labels generated and caller variables”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Macros”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: macro expansion, variable hygiene, caller environment, responsible macro APIs. Then trace the named counterexample “A macro captures caller state accidentally” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose macro expansion, and what does this project prove about it?”
  2. “What interaction between the concept ‘variable hygiene’ and the concept ‘macro expansion’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘A macro captures caller state accidentally’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with macro-expansion-positive and a-macro-captures-caller-state-accidentally-counterexample. The first must make the concept “macro expansion” observable and establish “Expansion output labels generated and caller variables”; the second must reproduce “A macro captures caller state accidentally”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for meta-programming/macros.md
evaluate "macro expansion" through Macro.expand, Macro.Env, var!
compare actual evidence with "Expansion output labels generated and caller variables"
run negative fixture for "A macro captures caller state accidentally"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix run scripts/macro_observe.exs from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Macros Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
macro expansion Metaprogramming Elixir Ch. 2-4: macros, hygiene, and environment
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement macro-expansion-positive and prove “Expansion output labels generated and caller variables”.
  3. Topic coverage: add fixtures for variable hygiene, caller environment, responsible macro APIs.
  4. Failure campaign: reproduce each named risk: “A macro captures caller state accidentally”; “Macro.Env is persisted beyond compilation”; “Large runtime logic is duplicated into every caller”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute macro-expansion-positive, variable-hygiene-positive, caller-environment-positive, responsible-macro-apis-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute macro-expansion-negative, variable-hygiene-negative, caller-environment-negative, responsible-macro-apis-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute a-macro-captures-caller-state-accidentally-counterexample, macro-env-is-persisted-beyond-compilation-counterexample, large-runtime-logic-is-duplicated-into-every-caller-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix run scripts/macro_observe.exs through the real Macro.expand, Macro.Env, var! boundary from a clean shell.
  • Mutation check: violate “Expansion output labels generated and caller variables” and prove the suite reports fixture macro-expansion-positive as failed.
  • Regression corpus: retain the risks “A macro captures caller state accidentally”; “Macro.Env is persisted beyond compilation”; “Large runtime logic is duplicated into every caller” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “A macro captures caller state accidentally”

  • Why: This breaks one or more observable capabilities at the Macro.expand, Macro.Env, var! boundary while allowing the happy path to look correct.
  • Fix: Run a-macro-captures-caller-state-accidentally-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/macro_observe.exs

Problem 2: “Macro.Env is persisted beyond compilation”

  • Why: This breaks one or more observable capabilities at the Macro.expand, Macro.Env, var! boundary while allowing the happy path to look correct.
  • Fix: Run macro-env-is-persisted-beyond-compilation-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/macro_observe.exs

Problem 3: “Large runtime logic is duplicated into every caller”

  • Why: This breaks one or more observable capabilities at the Macro.expand, Macro.Env, var! boundary while allowing the happy path to look correct.
  • Fix: Run large-runtime-logic-is-duplicated-into-every-caller-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix run scripts/macro_observe.exs

Definition of Done

  • Expansion output labels generated and caller variables.
  • Deliberate var leaks are detected by a fixture.
  • Generated wrappers remain small under an AST-size budget.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 109: Data-to-Macro Validation DSL Bake-Off

Official topic: Domain-Specific Languages (DSLs) — Elixir v1.20.2

Source file: lib/elixir/pages/meta-programming/domain-specific-languages.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: Level 2: Micro-SaaS / Pro Tool
  • Curriculum Difficulty: Level 4: Advanced
  • Knowledge Area: Language Design / DSL Trade-offs
  • Software or Tool: functions, macros, module attributes
  • Main Book: Metaprogramming Elixir

What you will build: Implement one validation language as data structures, ordinary functions, and macros plus modules, then compare conditional composition, testability, compile cost, module-attribute accumulation, and before-compile behavior.

Why it teaches this official topic: The artifact makes DSLs as data, function-based composition, macro-based syntax, use and before-compile hooks observable through one bounded build instead of isolated syntax examples.

Scope boundary: This is a comparative experiment; the following existing project remains the production pricing DSL.

Core challenges you will face:

  • DSLs as data -> identify the accepted case, the counterexample, and the observable result at the functions, macros, module attributes boundary
  • function-based composition -> identify the accepted case, the counterexample, and the observable result at the functions, macros, module attributes boundary
  • macro-based syntax -> identify the accepted case, the counterexample, and the observable result at the functions, macros, module attributes boundary
  • use and before-compile hooks -> identify the accepted case, the counterexample, and the observable result at the functions, macros, module attributes boundary

Real World Outcome

Implement one validation language as data structures, ordinary functions, and macros plus modules, then compare conditional composition, testability, compile cost, module-attribute accumulation, and before-compile behavior. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • All three variants express the same reference rules.
  • Compile-time and runtime costs are measured separately.
  • The final design decision names conditions where macros lose.

Acceptance transcript:

$ mix dsl.bakeoff
SOURCE_TOPIC=meta-programming/domain-specific-languages.md
ARTIFACT=data-to-macro-validation-dsl-bake-off
CHECK 01 PASS :: All three variants express the same reference rules
CHECK 02 PASS :: Compile-time and runtime costs are measured separately
CHECK 03 PASS :: The final design decision names conditions where macros lose
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“Which DSL representation adds the least power necessary while preserving composition, tests, and understandable compilation?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. DSLs as data
    • Working rule: Make “DSLs as data” an explicit rule at the functions, macros, module attributes boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "dsls-as-data-positive", focus: "DSLs as data", mode: :positive, expect: :observable} and %{id: "dsls-as-data-negative", focus: "DSLs as data", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Domain-Specific Languages (DSLs)
  2. function-based composition
    • Working rule: Make “function-based composition” an explicit rule at the functions, macros, module attributes boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "function-based-composition-positive", focus: "function-based composition", mode: :positive, expect: :observable} and %{id: "function-based-composition-negative", focus: "function-based composition", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Domain-Specific Languages (DSLs)
  3. macro-based syntax
    • Working rule: Make “macro-based syntax” an explicit rule at the functions, macros, module attributes boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "macro-based-syntax-positive", focus: "macro-based syntax", mode: :positive, expect: :observable} and %{id: "macro-based-syntax-negative", focus: "macro-based syntax", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Domain-Specific Languages (DSLs)
  4. use and before-compile hooks
    • Working rule: Make “use and before-compile hooks” an explicit rule at the functions, macros, module attributes boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "use-and-before-compile-hooks-positive", focus: "use and before-compile hooks", mode: :positive, expect: :observable} and %{id: "use-and-before-compile-hooks-negative", focus: "use and before-compile hooks", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Domain-Specific Languages (DSLs)

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “DSLs as data” be enforced?
    • Which check catches the risk “The macro version is selected only for prettier syntax”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “All three variants express the same reference rules”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Domain-Specific Languages (DSLs)”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: DSLs as data, function-based composition, macro-based syntax, use and before-compile hooks. Then trace the named counterexample “The macro version is selected only for prettier syntax” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose DSLs as data, and what does this project prove about it?”
  2. “What interaction between the concept ‘function-based composition’ and the concept ‘DSLs as data’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘The macro version is selected only for prettier syntax’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with dsls-as-data-positive and the-macro-version-is-selected-only-for-prettier-syntax-counterexample. The first must make the concept “DSLs as data” observable and establish “All three variants express the same reference rules”; the second must reproduce “The macro version is selected only for prettier syntax”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for meta-programming/domain-specific-languages.md
evaluate "DSLs as data" through functions, macros, module attributes
compare actual evidence with "All three variants express the same reference rules"
run negative fixture for "The macro version is selected only for prettier syntax"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix dsl.bakeoff from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Domain-Specific Languages (DSLs) Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
DSLs as data Metaprogramming Elixir Ch. 5-6: extending modules and DSLs
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement dsls-as-data-positive and prove “All three variants express the same reference rules”.
  3. Topic coverage: add fixtures for function-based composition, macro-based syntax, use and before-compile hooks.
  4. Failure campaign: reproduce each named risk: “The macro version is selected only for prettier syntax”; “Conditional rules cannot compose”; “Accumulated attributes leak across modules”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute dsls-as-data-positive, function-based-composition-positive, macro-based-syntax-positive, use-and-before-compile-hooks-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute dsls-as-data-negative, function-based-composition-negative, macro-based-syntax-negative, use-and-before-compile-hooks-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute the-macro-version-is-selected-only-for-prettier-syntax-counterexample, conditional-rules-cannot-compose-counterexample, accumulated-attributes-leak-across-modules-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix dsl.bakeoff through the real functions, macros, module attributes boundary from a clean shell.
  • Mutation check: violate “All three variants express the same reference rules” and prove the suite reports fixture dsls-as-data-positive as failed.
  • Regression corpus: retain the risks “The macro version is selected only for prettier syntax”; “Conditional rules cannot compose”; “Accumulated attributes leak across modules” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “The macro version is selected only for prettier syntax”

  • Why: This breaks one or more observable capabilities at the functions, macros, module attributes boundary while allowing the happy path to look correct.
  • Fix: Run the-macro-version-is-selected-only-for-prettier-syntax-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix dsl.bakeoff

Problem 2: “Conditional rules cannot compose”

  • Why: This breaks one or more observable capabilities at the functions, macros, module attributes boundary while allowing the happy path to look correct.
  • Fix: Run conditional-rules-cannot-compose-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix dsl.bakeoff

Problem 3: “Accumulated attributes leak across modules”

  • Why: This breaks one or more observable capabilities at the functions, macros, module attributes boundary while allowing the happy path to look correct.
  • Fix: Run accumulated-attributes-leak-across-modules-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix dsl.bakeoff

Definition of Done

  • All three variants express the same reference rules.
  • Compile-time and runtime costs are measured separately.
  • The final design decision names conditions where macros lose.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 110: Macro Recompilation Budget Gate

Official topic: Meta-programming anti-patterns — Elixir v1.20.2

Source file: lib/elixir/pages/anti-patterns/macro-anti-patterns.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: Level 2: Micro-SaaS / Pro Tool
  • Curriculum Difficulty: Level 4: Advanced
  • Knowledge Area: Compiler Tooling / Dependency Hygiene
  • Software or Tool: mix xref trace, mix compile –force
  • Main Book: Metaprogramming Elixir

What you will build: Build a gate that measures compile dependency edges, incremental compilation time, generated AST and BEAM-size deltas, and use nutrition labels, then replaces one unnecessary macro with an ordinary function before enforcing fixed budgets.

Why it teaches this official topic: The artifact makes compile-time dependencies, generated-code volume, use versus import transparency, tracked module construction, unnecessary macros observable through one bounded build instead of isolated syntax examples.

Scope boundary: Own compile graphs, generation volume, and use transparency; exclude migration rules and artifact reproducibility.

Core challenges you will face:

  • compile-time dependencies -> identify the accepted case, the counterexample, and the observable result at the mix xref trace, mix compile –force boundary
  • generated-code volume -> identify the accepted case, the counterexample, and the observable result at the mix xref trace, mix compile –force boundary
  • use versus import transparency -> identify the accepted case, the counterexample, and the observable result at the mix xref trace, mix compile –force boundary
  • tracked module construction -> identify the accepted case, the counterexample, and the observable result at the mix xref trace, mix compile –force boundary
  • unnecessary macros -> identify the accepted case, the counterexample, and the observable result at the mix xref trace, mix compile –force boundary

Real World Outcome

Build a gate that measures compile dependency edges, incremental compilation time, generated AST and BEAM-size deltas, and use nutrition labels, then replaces one unnecessary macro with an ordinary function before enforcing fixed budgets. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Incremental compile dependencies stay below the declared budget.
  • Generated AST and BEAM-size deltas stay below the declared budget.
  • Every use extension publishes its injected surface.
  • Dynamic module references appear in xref evidence.
  • The function replacement preserves behavior while removing needless expansion.

Acceptance transcript:

$ mix macro.budget
SOURCE_TOPIC=anti-patterns/macro-anti-patterns.md
ARTIFACT=macro-recompilation-budget-gate
CHECK 01 PASS :: Incremental compile dependencies stay below the declared budget
CHECK 02 PASS :: Generated AST and BEAM-size deltas stay below the declared budget
CHECK 03 PASS :: Every use extension publishes its injected surface
CHECK 04 PASS :: Dynamic module references appear in xref evidence
CHECK 05 PASS :: The function replacement preserves behavior while removing needless expansion
FAILURE_CASES=5 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“How can macro convenience be constrained by measurable compilation and dependency budgets?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. compile-time dependencies
    • Working rule: Make “compile-time dependencies” an explicit rule at the mix xref trace, mix compile –force boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "compile-time-dependencies-positive", focus: "compile-time dependencies", mode: :positive, expect: :observable} and %{id: "compile-time-dependencies-negative", focus: "compile-time dependencies", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Meta-programming anti-patterns
  2. generated-code volume
    • Working rule: Make “generated-code volume” an explicit rule at the mix xref trace, mix compile –force boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "generated-code-volume-positive", focus: "generated-code volume", mode: :positive, expect: :observable} and %{id: "generated-code-volume-negative", focus: "generated-code volume", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Meta-programming anti-patterns
  3. use versus import transparency
    • Working rule: Make “use versus import transparency” an explicit rule at the mix xref trace, mix compile –force boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "use-versus-import-transparency-positive", focus: "use versus import transparency", mode: :positive, expect: :observable} and %{id: "use-versus-import-transparency-negative", focus: "use versus import transparency", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Meta-programming anti-patterns
  4. tracked module construction
    • Working rule: Make “tracked module construction” an explicit rule at the mix xref trace, mix compile –force boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "tracked-module-construction-positive", focus: "tracked module construction", mode: :positive, expect: :observable} and %{id: "tracked-module-construction-negative", focus: "tracked module construction", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Meta-programming anti-patterns
  5. unnecessary macros
    • Working rule: Make “unnecessary macros” an explicit rule at the mix xref trace, mix compile –force boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "unnecessary-macros-positive", focus: "unnecessary macros", mode: :positive, expect: :observable} and %{id: "unnecessary-macros-negative", focus: "unnecessary macros", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Meta-programming anti-patterns

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “compile-time dependencies” be enforced?
    • Which check catches the risk “A runtime dependency is moved to compile time”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Incremental compile dependencies stay below the declared budget”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Meta-programming anti-patterns”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: compile-time dependencies, generated-code volume, use versus import transparency, tracked module construction, unnecessary macros. Then trace the named counterexample “A runtime dependency is moved to compile time” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose compile-time dependencies, and what does this project prove about it?”
  2. “What interaction between the concept ‘generated-code volume’ and the concept ‘compile-time dependencies’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘A runtime dependency is moved to compile time’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with compile-time-dependencies-positive and a-runtime-dependency-is-moved-to-compile-time-counterexample. The first must make the concept “compile-time dependencies” observable and establish “Incremental compile dependencies stay below the declared budget”; the second must reproduce “A runtime dependency is moved to compile time”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for anti-patterns/macro-anti-patterns.md
evaluate "compile-time dependencies" through mix xref trace, mix compile --force
compare actual evidence with "Incremental compile dependencies stay below the declared budget"
run negative fixture for "A runtime dependency is moved to compile time"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix macro.budget from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Meta-programming anti-patterns Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
compile-time dependencies Metaprogramming Elixir Ch. 3-6: responsible macros and DSLs
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement compile-time-dependencies-positive and prove “Incremental compile dependencies stay below the declared budget”.
  3. Topic coverage: add fixtures for generated-code volume, use versus import transparency, tracked module construction, unnecessary macros.
  4. Failure campaign: reproduce each named risk: “A runtime dependency is moved to compile time”; “A macro generates large repetitive functions”; “A use extension hides imported or aliased names”; “An alias is constructed dynamically and escapes tracking”; “A macro is retained even though an ordinary function provides the same contract”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute compile-time-dependencies-positive, generated-code-volume-positive, use-versus-import-transparency-positive, tracked-module-construction-positive, unnecessary-macros-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute compile-time-dependencies-negative, generated-code-volume-negative, use-versus-import-transparency-negative, tracked-module-construction-negative, unnecessary-macros-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute a-runtime-dependency-is-moved-to-compile-time-counterexample, a-macro-generates-large-repetitive-functions-counterexample, a-use-extension-hides-imported-or-aliased-names-counterexample, an-alias-is-constructed-dynamically-and-escapes-tracking-counterexample, a-macro-is-retained-even-though-an-ordinary-function-provides-the-same-contract-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix macro.budget through the real mix xref trace, mix compile –force boundary from a clean shell.
  • Mutation check: violate “Incremental compile dependencies stay below the declared budget” and prove the suite reports fixture compile-time-dependencies-positive as failed.
  • Regression corpus: retain the risks “A runtime dependency is moved to compile time”; “A macro generates large repetitive functions”; “A use extension hides imported or aliased names”; “An alias is constructed dynamically and escapes tracking”; “A macro is retained even though an ordinary function provides the same contract” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “A runtime dependency is moved to compile time”

  • Why: This breaks one or more observable capabilities at the mix xref trace, mix compile –force boundary while allowing the happy path to look correct.
  • Fix: Run a-runtime-dependency-is-moved-to-compile-time-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix macro.budget

Problem 2: “A macro generates large repetitive functions”

  • Why: This breaks one or more observable capabilities at the mix xref trace, mix compile –force boundary while allowing the happy path to look correct.
  • Fix: Run a-macro-generates-large-repetitive-functions-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix macro.budget

Problem 3: “A use extension hides imported or aliased names”

  • Why: This breaks one or more observable capabilities at the mix xref trace, mix compile –force boundary while allowing the happy path to look correct.
  • Fix: Run a-use-extension-hides-imported-or-aliased-names-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix macro.budget

Problem 4: “An alias is constructed dynamically and escapes tracking”

  • Why: This breaks one or more observable capabilities at the mix xref trace, mix compile –force boundary while allowing the happy path to look correct.
  • Fix: Run an-alias-is-constructed-dynamically-and-escapes-tracking-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix macro.budget

Problem 5: “A macro is retained even though an ordinary function provides the same contract”

  • Why: This breaks one or more observable capabilities at the mix xref trace, mix compile –force boundary while allowing the happy path to look correct.
  • Fix: Run a-macro-is-retained-even-though-an-ordinary-function-provides-the-same-contract-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix macro.budget

Definition of Done

  • Incremental compile dependencies stay below the declared budget.
  • Generated AST and BEAM-size deltas stay below the declared budget.
  • Every use extension publishes its injected surface.
  • Dynamic module references appear in xref evidence.
  • The function replacement preserves behavior while removing needless expansion.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 111: Compile-Time Pricing Policy DSL

Source: BEAM-P20. Validate pricing rules at compile time and emit source-located functions.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: Level 4: Open Core Infrastructure
  • Curriculum Difficulty: Level 4: Advanced
  • Knowledge Area: Metaprogramming, Domain Modeling
  • Software or Tool: Macro, Module, quote/unquote
  • Main Book: “Domain Modeling Made Functional”

What you will build: Validate pricing rules at compile time and emit source-located functions.

Why it teaches the BEAM ecosystem: It makes you prove that invalid policies fail usefully and generated behavior remains testable.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Validate pricing rules at compile time and emit source-located functions.

Build a “PricingPolicy” library plus example policy module supporting products, customer segments, quantity tiers, date windows, percentage/basis-point discounts, exclusive groups, caps, and explanation rendering.

Scope boundary: This is a compile-time language-design project, not a checkout service. Do not add a database, LiveView UI, distributed cache, remote rules, arbitrary user expressions, tax engine, currency conversion, or runtime policy editor.

$ mix compile
Compiling 8 files
Generated pricing_policy app
policy=Retail2026 products=3 segments=2 rules=7 warnings=0

$ mix pricing.explain Retail2026 SKU-RED --segment vip --quantity 12 --date 2026-07-15
base BRL 100.00 rule=product:SKU-RED
tier BRL -5.00 rule=bulk-10 quantity>=10
discount BRL -9.50 rule=vip-10 basis_points=1000
final BRL 85.50

3.7.1 How to Run

Compile a valid fixture policy, run an explanation command, then compile invalid fixture modules and verify file/line/rule diagnostics. Inspect the generated policy table and rerun tests after changing declaration order.

3.7.2 Golden Path Demo

Three products and seven rules compile. VIP bulk pricing yields the documented trace. Invalid policies fail for unknown segment, duplicate rule, and ambiguous exclusive overlap before runtime.

3.7.3 Exact Terminal Transcript

$ mix test test/pricing_policy_test.exs
24 tests, 0 failures

$ mix test test/compile_diagnostics_test.exs
diagnostic duplicate rule id cites both source locations
diagnostic unknown segment cites discount declaration
diagnostic ambiguous exclusive rules cites group and priority
3 tests, 0 failures

$ mix pricing.explain Retail2026 SKU-RED --segment vip --quantity 12 --date 2026-07-15
final_minor_units=8550 currency=BRL steps=3 status=ok

The Core Question You Are Answering

When is compile-time metaprogramming justified, and how do I keep a DSL safe, diagnosable, deterministic, and transparent at runtime?

Concepts You Must Understand First

Understand quoted AST, macro expansion, hygiene, unquote/escape, caller environment, module attribute registration/accumulation, before-compile callbacks, protocols, integer money, and compile-error testing.

Questions to Guide Your Design

  1. What smaller language does the DSL define?
  2. Which AST forms are accepted and rejected?
  3. Which rules are statically contradictory?
  4. What ordinary runtime API does compilation produce?
  5. How is arithmetic order explained and tested?
  6. What source metadata makes errors actionable?

Thinking Exercise

Take a three-line policy and manually sketch its AST at the macro boundary, normalized definition, generated runtime data, and final trace. Then add two exclusive equal-priority discounts and design the exact diagnostic.

The Interview Questions They Will Ask

  1. What does an Elixir macro receive and return?
  2. What is macro hygiene, and what problems remain?
  3. When should a normal function be preferred over a macro?
  4. How do accumulating module attributes and before-compile hooks interact?
  5. Why must arbitrary caller AST not be evaluated?
  6. How do you test generated code without coupling to private AST shape?

Hints in Layers

Hint 1: Implement price arithmetic and traces with plain structs/functions.

Hint 2: Make the first macro accept only literal product declarations.

Hint 3: Accumulate normalized definitions with file/line, then validate all references before generation.

Hint 4: Generate one small function delegating to the evaluator before considering per-rule clauses.

Books That Will Help

Topic Book Chapter
Elixir metaprogramming “Metaprogramming Elixir” by Chris McCord Ch. 1, The Language of Macros; Ch. 3, Advanced Compile-Time Code Generation
Macros and protocols “Programming Elixir >= 1.6” by Dave Thomas Ch. 20, Macros and Code Evaluation; Ch. 21, Linking Modules: Behaviours and Use
Pricing domain modeling “Domain Modeling Made Functional” by Scott Wlaschin Ch. 6, Domain Integrity and Consistency; Ch. 9, A Complete Example

Implementation Milestones

Phase 1: Foundation (5-7 hours)

Define runtime inputs/results/math/traces, protocol, example tests, and minimal product/segment definitions.

Phase 2: Core Functionality (6-9 hours)

Implement DSL grammar, source capture, attributes, callback validation, generated API, tiers/discounts/exclusivity.

Phase 3: Polish & Edge Cases (5-8 hours)

Add diagnostics, compile fixtures, hygiene tests, generated docs, introspection, deterministic order, and expansion review.

Testing Strategy

6.1 Test Categories

  • Runtime evaluator/math/trace unit tests
  • DSL declaration normalization tests
  • Valid fixture compilation and public API tests
  • Invalid fixture diagnostic tests
  • Hygiene/alias collision tests
  • Macro expansion broad-shape tests
  • Deterministic policy docs/introspection tests

6.2 Critical Test Cases

  1. Unsupported arbitrary expression fails without evaluation.
  2. Duplicate id diagnostic cites both definitions.
  3. Unknown references and mixed currencies fail compilation.
  4. Equal-priority exclusive overlap fails.
  5. Runtime date/quantity selects correct ordered rules and trace.
  6. Caller variable/alias names do not collide with generated internals.
  7. Reordered independent declarations produce defined deterministic behavior.
  8. Compilation does not capture current date.

6.3 Test Data

Keep minimal one-rule fixtures, full Retail2026 fixture, one invalid fixture per diagnostic, arithmetic boundaries, overlapping date/tier cases, rounding cases, and hygiene-conflict module names.

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Macro owns business logic: Runtime behavior is hard to test. Move evaluation to ordinary modules.

Mysterious compile error: Source metadata was discarded. Carry caller location with every definition.

Rules reverse order: Accumulating attributes were assumed ordered. Normalize and sort deliberately.

Build is environment-dependent: Compile phase read clock/network/database. Inject runtime values and keep compilation pure.

Caller collision: Generated names/aliases leaked. Use hygienic variables and qualified modules.

7.2 Debugging Strategies

Inspect one declaration’s quoted form, normalized definition, and generated expansion. Provide a compiler debug mode that prints normalized policy data, never arbitrary evaluated AST. Reproduce diagnostics with minimal fixture modules.

7.3 Performance Traps

Generating a clause for every combination can inflate compile time and BEAM size. Repeated macro expansion, huge escaped data, and runtime protocol consolidation choices also matter. Measure compilation and artifact size before optimizing.

Definition of Done

  • Runtime pricing works independently of macros.
  • DSL accepts only a documented restricted grammar.
  • All definitions preserve source file and line.
  • Cross-rule contradictions fail during compilation.
  • Generated API is small, deterministic, and inspectable.
  • Integer arithmetic and rounding order are documented.
  • Every price has an ordered explanation trace.
  • Compile diagnostics and hygiene have dedicated tests.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • invalid policies fail usefully and generated behavior remains testable.

Project 112: Compiler-Aware Migration Linter

Source: BEAM-P28. Trace compilation and analyze AST to find deprecated calls and safe migrations.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: Level 4: Open Core Infrastructure
  • Curriculum Difficulty: Level 4: Advanced
  • Knowledge Area: Compiler Tooling, Static Analysis
  • Software or Tool: Code, Macro, compiler tracers, Mix.Task
  • Main Book: “Engineering a Compiler”

What you will build: Trace compilation and analyze AST to find deprecated calls and safe migrations.

Why it teaches the BEAM ecosystem: It makes you prove that aliases, imports, macros, and generated code are distinguished.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Trace compilation and analyze AST to find deprecated calls and safe migrations.

Build mix migrate.audit, a Mix task with two complementary engines: an offline source scanner for patch previews and a compiler-tracer mode for high-confidence resolved-call detection. Rules identify deprecated or organization-banned module/function/arity combinations, attach migration guidance, and emit terminal plus versioned JSON output.

$ mix migrate.audit --rules config/migration-rules.exs --format terminal
lib/billing/charge.ex:42:11 [MIG-014] warning
LegacyMoney.to_float/1 loses decimal precision.
Use Money.to_decimal/1 and keep arithmetic in decimal form.
confidence=resolved-call autofix=unavailable

summary files=84 facts=391 findings=1 errors=0
exit=2 policy_violation

3.7.1 How to Run

$ mix deps.get
$ mix test
$ mix migrate.audit --fixture test/fixtures/legacy_app --format json

3.7.2 Golden Path Demo

The fixture contains one fully qualified deprecated call, one alias-resolved call, one ambiguous imported name, and one safe replacement. The tool reports the first two, labels the imported case as ambiguous only in offline mode, and offers a patch preview solely for the rule with proven textual preconditions.

3.7.3 Exact Terminal Transcript

$ mix migrate.audit --fixture test/fixtures/legacy_app --format summary
session=7f2c mode=compiler+source
files_parsed=6 compile_facts=18
MIG-001 resolved=2 ambiguous=1 ignored_generated=1
patch_previews=1 automatically_applied=0
result=policy_violation

The Core Question You Are Answering

“How can a tool use compiler knowledge to accelerate migrations without making claims or edits it cannot prove safe?”

Concepts You Must Understand First

  1. Quoted expressions and metadata — Metaprogramming Elixir by Chris McCord, Chapters 1-3.
  2. Macros and lexical environment — Metaprogramming Elixir, Chapters 4-6.
  3. Mix tasks and compilation — official Mix.Task, Mix.Tasks.Compile, and Code documentation.
  4. Types and public diagnostic contracts — Programming Elixir ≥ 1.6 by Dave Thomas, “Protocols” and “More Cool Stuff” chapters.

Questions to Guide Your Design

  1. Which findings require resolved compiler evidence, and which may be syntactic hints?
  2. How will output remain stable under parallel compilation?
  3. What is the exact refusal policy for a patch preview?
  4. How does the tool behave when its collector crashes?
  5. Which schema fields are public compatibility commitments?

Thinking Exercise

Trace four forms of fetch(value): a local function, an imported function, a macro, and a variable invocation. Write down what the offline AST knows, what Macro.Env adds, and what a compiler event may resolve. The correct design preserves “unknown” instead of guessing.

The Interview Questions They Will Ask

  1. “What information is lost when Elixir source is converted to quoted syntax?”
  2. “Why can a compiler tracer slow unrelated modules?”
  3. “How would you resolve aliases and imports without evaluating a project?”
  4. “What makes a source rewrite semantics-preserving?”
  5. “How would you version diagnostics consumed by CI and editors?”
  6. “How do you test deterministic output under parallel compilation?”

Hints in Layers

Hint 1: Begin with facts — Define a neutral call-fact schema before writing any migration rule.

Hint 2: Separate engines — Make source scanning and compiler tracing independent producers of the same fact shape.

Hint 3: Keep the tracer tiny — Adapt, enqueue, return. Parse configuration and render reports elsewhere.

Hint 4: Make refusal visible — A patch preview should explain why it was withheld, such as ambiguity or intersecting comments.

Books That Will Help

Topic Book Precise reading
Quoted syntax Metaprogramming Elixir — Chris McCord Chapters 1-3, “The Language of Macros” through AST traversal
Macro APIs Metaprogramming Elixir — Chris McCord Chapters 4-6, macro hygiene and compile-time hooks
Elixir abstractions Programming Elixir ≥ 1.6 — Dave Thomas “Protocols — Polymorphic Functions” and “Macros and Code Evaluation”
Compiler perspective The BEAM Book — Erik Stenman “Code Loading” and compiler/BEAM file discussions

Implementation Milestones

Phase 1: Source Facts and Rules (5-7 hours)

  • Define versioned rule, fact, finding, and refusal schemas.
  • Parse fixtures and traverse fully qualified calls.
  • Add alias-aware facts and deterministic terminal output.

Phase 2: Compiler Integration (6-9 hours)

  • Add the versioned event adapter and bounded collector.
  • Correlate resolved facts with source facts.
  • Measure clean and incremental compilation overhead.

Phase 3: Migration Guidance (5-7 hours)

  • Add source excerpts and conservative patch previews.
  • Add JSON output, stable fingerprints, and exit policy.
  • Support umbrella child paths and configuration inheritance.

Phase 4: Hardening (4-7 hours)

  • Run concurrency determinism tests.
  • Inject collector, parser, and configuration failures.
  • Document supported event/version matrix and known ambiguities.

Testing Strategy

6.1 Test Categories

Category Purpose Examples
Unit Validate node classification and rules aliases, imports, quoted blocks, arity
Property Stress AST walkers and normalization arbitrary valid nested quoted forms
Integration Compile fixture applications resolved function and macro events
Golden Protect output contracts terminal and JSON snapshots with normalized paths
Failure Verify tool resilience parser error, collector exit, invalid rule file
Performance Enforce tracer budget clean and incremental compilation baselines

6.2 Critical Test Cases

  1. Fully qualified and alias-resolved calls produce one deduplicated finding.
  2. A same-named local function is not reported as the remote deprecated API.
  3. An ambiguous imported call is never offered an automatic patch.
  4. A deprecated macro is classified distinctly from a function.
  5. Comments intersecting a replacement range cause a documented refusal.
  6. Unicode source before a finding yields the correct displayed column.
  7. Twenty parallel compile runs produce identical normalized JSON.
  8. Collector failure follows local and CI failure policies without deadlock.
  9. An unsupported compiler event is counted and ignored safely.
  10. Umbrella child paths and duplicate compilation facts normalize correctly.

6.3 Test Data

Maintain tiny fixture projects for aliases, imports, macro-generated calls, syntax errors, umbrella children, and comments around candidate replacements. Store expected facts separately from rendered output so renderer changes do not hide semantic regressions.

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Problem Why it happens Fix Quick test
Local call reported as remote API Matcher searches only by function name Require module/lexical evidence and confidence tiers Add a local same-name fixture
Compile becomes slow Tracer performs matching or I/O synchronously Capture bounded facts and analyze after compilation Compare incremental compile baseline
Duplicate findings Source and tracer facts are rendered independently Correlate and keep strongest evidence One known call must yield one fingerprint
Patch moves comments AST formatting is treated as concrete syntax Use exact ranges and refuse intersecting comments Place comments inside candidate call
CI findings churn Absolute paths or event order enter fingerprints Normalize paths and sort by source location Run from two checkout roots
Analyzer crashes on new Elixir Raw event matching is exhaustive and brittle Add a version adapter with safe unknown handling Feed a synthetic unknown event

7.2 Debugging Strategies

  • Add an opt-in fact dump that contains normalized neutral facts, not target secrets.
  • Render the AST path and lexical context for a single selected source range.
  • Track collector queue high-water mark and ignored-event counts.
  • Compare offline and compiler evidence for one finding before changing rules.
  • Reproduce path issues inside a temporary checkout with a different absolute root.

7.3 Performance Traps

  • Re-parsing rule configuration for every compiler event
  • Copying entire ASTs or source files into the collector
  • Linear matching against hundreds of wildcard rules
  • Holding full source excerpts for clean files
  • Synchronous calls from parallel compiler workers to one serialized analyzer

Definition of Done

  • Offline and compiler engines share a documented versioned fact schema.
  • Exact remote calls are detected without false positives in all reference fixtures.
  • Ambiguous findings state their confidence and never receive unsafe patches.
  • Output is byte-identical across repeated parallel runs after normalization.
  • JSON fields, exit statuses, and failure policies are documented.
  • Tracer overhead stays within the declared reference budget.
  • Tool failure, policy violation, and target parse failure are distinguishable.
  • Existing project behavior is unchanged when the tracer is enabled.
  • All tests pass without evaluating inspected source.
  • README includes supported Elixir versions and event compatibility limits.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • aliases, imports, macros, and generated code are distinguished.

Project 113: TCP Device Telemetry Gateway

Source: BEAM-P25. Build framed binary parsing, connection limits, heartbeats, and backpressure over gen_tcp.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir and Erlang
  • Alternative Programming Languages: Gleam
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: Level 4: Open Core Infrastructure
  • Curriculum Difficulty: Level 4: Advanced
  • Knowledge Area: TCP, Binary Protocols, Connection Lifecycle
  • Software or Tool: :gen_tcp, DynamicSupervisor, bitstrings
  • Main Book: “TCP/IP Illustrated, Volume 1”

What you will build: Build framed binary parsing, connection limits, heartbeats, and backpressure over gen_tcp.

Why it teaches the BEAM ecosystem: It makes you prove that partial frames, slow clients, and reconnect storms stay bounded.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Build framed binary parsing, connection limits, heartbeats, and backpressure over gen_tcp.

Build a listener, acceptor pool, dynamically supervised connection processes, binary protocol parser/encoder, device session rules, bounded telemetry sink, metrics reporter, and simulator capable of valid, fragmented, bursty, slow, and malformed clients.

$ telemetry-sim connect --devices 1000 --rate 2/s --fragment random
connected=1000 hello_ok=1000 frames_sent=120000 acks=120000
checksum_errors=0 sequence_gaps=0 disconnects=0

$ gatewayctl sessions --top-buffer 3
device=sensor-0441 buffer=37 mailbox=0 last_seq=881 state=established
device=sensor-0088 buffer=16 mailbox=1 last_seq=902 state=established

3.7.1 How to Run (Copy/Paste)

$ mix test
$ mix run priv/demo_gateway.exs
$ telemetry-sim run priv/scenarios/mixed_clients.json
$ gatewayctl metrics

3.7.2 Golden Path Demo (Deterministic)

The mixed scenario starts 200 normal devices, one random-fragment device, one burst client, one slowloris client, and three malformed clients. Valid frames reach the sink exactly once; bad sessions close with expected reasons; healthy sessions remain.

3.7.3 Exact terminal transcript

$ mix run priv/demo_gateway.exs
listener port=4545 acceptors=8 active_mode=once max_frame=4110
clients connected=206 hello_ok=203
valid_frames=20000 sink_accepted=20000 acknowledgements=20000
closed checksum_limit=1 oversized_frame=1 protocol_order=1 frame_timeout=1
healthy_remaining=202 parser_mismatches=0
max_connection_buffer=4109 max_connection_mailbox=2 listener_restarts=0
DEMO PASS

The Core Question You Are Answering

“How can a BEAM process turn an arbitrary TCP byte stream into trustworthy bounded messages without losing socket lifecycle control?”

Concepts You Must Understand First

  1. TCP streams — TCP/IP Illustrated, Volume 1, 2nd Edition, Chapters 12–17.
  2. Elixir binaries — Programming Elixir 1.6, Chapter 11, “Strings and Binaries”.
  3. BEAM processes — Elixir in Action, 3rd Edition, Chapters 5–6.
  4. Supervision — Designing for Scalability with Erlang/OTP, supervision chapters.

Questions to Guide Your Design

  1. What maximum bytes can one untrusted connection retain?
  2. When exactly is the socket owner transferred and reception armed?
  3. Which downstream condition delays active-once rearming?
  4. Which disconnects are normal versus faults worth alerting?
  5. How will protocol evolution remain backward compatible?

Thinking Exercise

Draw a timeline where the peer sends data immediately after connect, the child starts slowly, the transfer succeeds, and the peer closes. Identify which process may receive each message and how the handshake prevents mailbox loss.

The Interview Questions They Will Ask

  1. Why can TCP split or combine application writes?
  2. Compare passive, active, and active-once socket modes.
  3. What is a controlling process, and how do you hand off safely?
  4. How would you defend against an attacker declaring a huge payload length?
  5. Why can active-once still lead to downstream overload?
  6. How do iodata and binary subterms affect memory behavior?

Hints in Layers

Hint 1: Parser before sockets — Prove one pure incremental decoder against arbitrary chunk boundaries.

Hint 2: One connection lifecycle — Start a waiting process, transfer ownership, then arm reception.

Hint 3: Make slowness visible — Track buffer, mailbox, last activity, and sink admission separately.

Hint 4: Attack transport assumptions — Randomize chunks and send timing while keeping logical frames fixed.

Books That Will Help

Topic Book Chapter
TCP semantics TCP/IP Illustrated, Vol. 1, 2nd Edition Ch. 12–17
Binaries Programming Elixir 1.6 Ch. 11
Process architecture Elixir in Action, 3rd Edition Ch. 5–6
Supervision Designing for Scalability with Erlang/OTP Supervision chapters

Implementation Milestones

Phase 1: Protocol and Pure Parser (5-7 hours)

  • Specify frames, build encoder/decoder pseudocode, exhaustive split tests, and semantic validation.

Phase 2: Socket Ownership and Sessions (7-11 hours)

  • Build listener, acceptors, dynamic connection supervision, active-once loop, timeouts, and ACKs.

Phase 3: Capacity and Failure Evidence (8-12 hours)

  • Add bounded sink, simulator, overload policy, metrics, load/fault scenarios, and runbook.

Testing Strategy

6.1 Test Categories

Category Purpose Examples
Parser property Chunk boundaries do not change meaning every split/random partitions
Protocol rejection Bound untrusted fields length, version, checksum
Ownership integration Correct controlling process immediate-send handoff
Lifecycle Timeouts and closes idle, slow frame, peer reset
Overload Bound mailboxes and sink burst and slow consumer
Capacity Measure target concurrency thousands of simulated devices

6.2 Critical Test Cases

  1. Every two-way split of a valid frame emits the same one event.
  2. Random chunks of 100 concatenated frames emit all frames in order.
  3. Oversized length is rejected before payload wait/allocation.
  4. Immediate peer data after accept reaches the connection owner, not the acceptor mailbox.
  5. Active-once never produces more than one outstanding socket data message per connection under the controlled scenario.
  6. Slow frame assembly and non-reading peer meet their respective deadlines.
  7. Sink overload activates documented pause/reject/close behavior without unbounded mailbox growth.
  8. Malformed-client storm leaves listener and healthy sessions running.

6.3 Test Data

Generate valid HELLO, telemetry, heartbeat, ACK, maximum frames, bad magic/version/type/length/checksum, duplicate/gapped sequence, partial header/payload, random chunks, and one-byte trickle streams.

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Problem: “Parser fails only outside localhost.”

  • Why: It assumes one receive contains one frame.
  • Fix: Keep an incremental buffer and parse complete frames in a loop.
  • Quick test: Feed every possible split and randomized chunk grouping.

Problem: “Data appears in the acceptor mailbox.”

  • Why: Socket activation occurred before controlling-process transfer.
  • Fix: Use waiting child, transfer, ready signal, then active-once.
  • Quick test: Have the peer send immediately during handoff.

Problem: “Memory grows under burst traffic.”

  • Why: Full active mode or downstream casts create unbounded mailboxes.
  • Fix: Use active-once and bounded sink admission with explicit overload policy.
  • Quick test: Slow the sink and chart mailbox/buffer high-water marks.

7.2 Debugging Strategies

  • Log connection ID, device ID after authentication, parser outcome, buffer bytes, and disconnect reason.
  • Inspect process mailbox length and socket statistics for a single troubled session.
  • Replay captured bytes through the pure parser without a socket.
  • Use deterministic simulator seeds so timing scenarios can be repeated.

7.3 Performance Traps

  • Repeatedly appending large binaries and retaining huge parent binaries for tiny suffixes.
  • Flattening iodata before every send.
  • Parsing unlimited frames in one process turn.
  • Centralizing all frame parsing or session state in one GenServer.

Definition of Done

  • Protocol specification defines byte order, versions, maximums, checksum, and session order.
  • Pure parser passes exhaustive split and randomized coalescing tests.
  • Socket handoff proves the intended controlling process receives data.
  • Active-once is rearmed only after processing and admission.
  • Handshake, frame, idle, and send deadlines are independently tested.
  • Receive buffer, mailbox, and sink remain within declared bounds under burst load.
  • Malformed sessions close without restarting listener or harming healthy clients.
  • Mixed-client demo ends with exact sink/frame agreement and DEMO PASS.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • partial frames, slow clients, and reconnect storms stay bounded.

Project 114: Nerves Cold-Chain Sensor Gateway

Source: BEAM-P26. Build firmware with sensor sampling, offline buffering, secure reconnect, health, and safe update behavior.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: Level 4: Open Core Infrastructure
  • Curriculum Difficulty: Level 4: Advanced
  • Knowledge Area: Embedded Systems, Fleet Reliability
  • Software or Tool: Nerves, Circuits, fwup, OTP releases
  • Main Book: “Making Embedded Systems”

What you will build: Build firmware with sensor sampling, offline buffering, secure reconnect, health, and safe update behavior.

Why it teaches the BEAM ecosystem: It makes you prove that power and network interruption preserve data.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Build firmware with sensor sampling, offline buffering, secure reconnect, health, and safe update behavior.

Build a Nerves firmware for one supported board and real I2C temperature sensor. It includes a sensor owner, calibrated reading model, alarm state machine, durable offline buffer, connectivity-aware uploader to a local test server, health/status CLI, signed update client, and tentative firmware validation gate.

$ coldchainctl status
firmware=1.3.0 slot=B validation=confirmed uptime=02:14:33
sensor=sht31 quality=good temperature_c=4.27 last_sample_age_ms=812
alarm=normal buffer_pending=0 network=online last_uploaded_seq=8842

$ coldchainctl simulate-network down
network=offline sampling=continues
after=10m buffer_pending=10 first_seq=8843 last_seq=8852

3.7.1 How to Run (Copy/Paste)

$ export MIX_TARGET=<supported_target>
$ mix deps.get
$ mix firmware
$ mix firmware.burn
$ coldchainctl run-drill offline-buffer
$ coldchainctl run-drill firmware-rollback

3.7.2 Golden Path Demo (Deterministic)

On real hardware, disconnect networking while the sensor continues sampling, reboot once, reconnect, and prove the server receives one contiguous deduplicated sequence. Then reject a tampered artifact, validate a signed healthy image, and automatically roll back a signed deliberately non-validating image.

3.7.3 Exact serial/CLI transcript

$ coldchainctl run-drill full
hardware sensor=sht31 bus=i2c-1 status=reading
network forced_offline=true samples_added=30 alarm_events=1
reboot requested=true buffer_reopened=true pending=30
network restored=true uploaded=30 duplicate_server_records=0 sequence_gaps=0
update tampered_image signature=invalid installed=false
update good_image version=1.3.1 boot=tentative health=passed validation=confirmed
update rollback_fixture version=1.3.2 boot=tentative health=failed reason=sensor_supervision_unstable
watchdog_reset=true rollback_version=1.3.1 rollback_recorded=true
DRILL PASS

The Core Question You Are Answering

“How can an unattended BEAM device preserve trustworthy temperature evidence and recover from a bad update when both hardware and connectivity fail?”

Concepts You Must Understand First

  1. Nerves firmware lifecycle — Nerves Getting Started, “Creating and Burning Firmware”.
  2. OTP supervision — Designing for Scalability with Erlang/OTP, supervision and restart chapters.
  3. I2C transactions — sensor datasheet plus The Book of I2C, protocol and bus chapters.
  4. Durable delivery — Enterprise Integration Patterns, “Store and Forward” and “Idempotent Receiver”.
  5. Embedded reliability — Making Embedded Systems, 2nd Edition, watchdog, state, and fault chapters.

Questions to Guide Your Design

  1. What evidence makes one reading trustworthy or explicitly degraded?
  2. How much data may be lost in sudden power loss, and how is that measured?
  3. Which alarms require local action even with no network?
  4. Which health probes are strong enough to validate firmware?
  5. How will signing-key rotation avoid stranding old devices?

Thinking Exercise

Draw two timelines: a 14-day network outage and a bad tentative firmware boot. Track sampling, storage pressure, alarms, publisher state, firmware slots, watchdog resets, and what a remote operator learns after connectivity returns.

The Interview Questions They Will Ask

  1. Why use monotonic and wall time together on an embedded gateway?
  2. How do hysteresis and dwell time reduce alarm noise?
  3. How do you make store-and-forward upload idempotent?
  4. What does a firmware signature prove, and what does it not prove?
  5. Why should firmware validation wait for health evidence?
  6. How does an A/B layout survive power loss during update?

Hints in Layers

Hint 1: Pure domain first — Test reading quality and alarm transition tables on the host.

Hint 2: One hardware owner — Let one supervised process own the bus and expose structured results.

Hint 3: Prove offline before cloud — Persist, reboot, and replay into a local receiver before adding update logic.

Hint 4: Trial means untrusted — Create a deliberately non-validating signed test image and prove rollback physically.

Books That Will Help

Topic Book Chapter
Embedded architecture Making Embedded Systems, 2nd Edition State machines, watchdogs, fault handling
I2C The Book of I2C Protocol and transaction chapters
OTP recovery Designing for Scalability with Erlang/OTP Supervision chapters
Durable messaging Enterprise Integration Patterns Store and Forward; Idempotent Receiver

Implementation Milestones

Phase 1: Physical Sampling and Alarm Domain (6-9 hours)

  • Wire/read real sensor, classify quality, persist sequences, and exercise hysteresis/stale alarms.

Phase 2: Offline Delivery and Device Operations (6-10 hours)

  • Add durable queue, network observer, idempotent batch receiver, storage pressure, reboot/power drills.

Phase 3: Authenticated Firmware and Rollback (8-13 hours)

  • Establish signed artifacts, inactive-slot install, tentative health gate, validation, watchdog, rollback, and runbook.

Testing Strategy

6.1 Test Categories

Category Purpose Examples
Pure domain Deterministic reading/alarm behavior dwell, hysteresis, stale quality
Storage Power/reboot continuity append, acknowledge, torn write
Network Ambiguous delivery and outage accepted-then-timeout, long offline period
Hardware Real bus/sensor behavior unplug/replug, invalid sample
Firmware security Reject unauthenticated artifacts tamper, wrong target, old version
Rollback Prove tentative safety health pass/fail, repeated reset

6.2 Critical Test Cases

  1. Oscillation around threshold does not chatter; sustained excursion enters and clears according to policy.
  2. Sensor unplug raises stale alarm without stopping storage/network/update supervision.
  3. Network outage plus reboot preserves a contiguous pending sequence.
  4. Server acceptance followed by client timeout does not duplicate records after retry.
  5. Storage high-water and critical-water paths raise alarms and apply documented retention.
  6. Tampered or wrong-target firmware never becomes boot candidate.
  7. Healthy tentative image validates only after all local probes pass.
  8. Signed non-validating image resets and returns to previous known-good version.
  9. Power interruption during inactive-slot installation leaves current active firmware bootable.

6.3 Test Data

Use fixed temperature traces for normal, short spike, sustained high, recovery, impossible value, and sensor loss. Use sequence batches with duplicate/gap responses. Build non-production signed good, tampered, wrong-target, and rollback-fixture firmware artifacts.

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Problem: “Temperature alarm chatters.”

  • Why: Entry and exit use one threshold with no dwell.
  • Fix: Use separate thresholds, consecutive/duration evidence, and explicit state.
  • Quick test: Replay a trace oscillating by one hundredth around the threshold.

Problem: “Offline data disappears after reboot.”

  • Why: Queue or acknowledgement state exists only in process memory.
  • Fix: Persist before acceptance and delete only confirmed sequence ranges.
  • Quick test: Power cycle with pending records, then inspect range continuity.

Problem: “Bad firmware never rolls back.”

  • Why: It was validated immediately or the health deadline/watchdog is absent.
  • Fix: Keep trial tentative until device-local probes pass; withhold validation on the fixture.
  • Quick test: Boot signed non-validating image and observe slot/version after reset.

7.2 Debugging Strategies

  • Inspect I2C bus/address separately from decoded sensor values.
  • Show sensor quality, buffer range, alarm state, slot, trial deadline, and validation in one local status command.
  • Preserve a bounded boot/update journal across rollback.
  • Compare server receipt ranges and device pending ranges when diagnosing duplicates/gaps.

7.3 Performance Traps

  • Writing flash for every noisy intermediate state without a loss/endurance budget.
  • Spawning upload work per sample during an outage.
  • Retaining unbounded logs or acknowledged readings.
  • Making firmware validation depend on a slow or unavailable cloud endpoint.

Definition of Done

  • Real target reads a physically connected temperature sensor.
  • Readings include exact units, sequence, calibration, time, and quality metadata.
  • Hysteresis/dwell and stale-sensor alarms pass deterministic traces.
  • Offline readings survive reboot and upload once in contiguous order.
  • Storage pressure and sudden-power-loss behavior are measured and documented.
  • Firmware authenticity and target/version checks occur before installation.
  • Healthy tentative firmware validates after local health gates.
  • Deliberately non-validating signed firmware rolls back to prior known-good image.
  • Full physical drill ends with DRILL PASS and retained local evidence.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • power and network interruption preserve data.

Project 115: Elixir/Rustler Ports-versus-NIF Lab

Sources: BEAM-P27, PHX-P20. Implement a perceptual-hash workload through a port and Rustler NIF, including dirty-scheduler and crash tests.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Rust, C
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: Level 4: Open Core Infrastructure
  • Curriculum Difficulty: Level 4: Advanced
  • Knowledge Area: Native Interop
  • Software or Tool: Port protocol, Rustler NIF, dirty schedulers
  • Main Book: Erlang NIF/Port docs

What you will build: Implement a perceptual-hash workload through a port and Rustler NIF, including dirty-scheduler and crash tests.

Why it teaches the BEAM ecosystem: It makes you prove that benchmarks quantify performance and isolation without scheduler starvation.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Integrated Scope

This is one consolidated project, not separate source builds. Implement the following contributions as phases of the same artifact:

  • Use BEAM-P27 to implement and benchmark the Rustler perceptual-hash NIF safely.
  • Add PHX-P20’s port implementation and dirty-scheduler/crash comparison around the same workload.

Real World Outcome

Build target: Implement a perceptual-hash workload through a port and Rustler NIF, including dirty-scheduler and crash tests.

Implement identical native capability via Port and NIF paths, benchmark both, and choose policy by risk and latency.

deterministic_outcome:

  • contract tests pass for both paths
  • benchmark report includes fault scenarios
  • deployment policy chooses boundary per workload

The Core Question You Are Answering

Where should native code run for performance without unacceptable reliability risk?

Concepts You Must Understand First

  • BEAM process model and failure isolation
  • OTP supervision semantics
  • Runtime observability discipline

Questions to Guide Your Design

  1. What is your safety invariant?
  2. What is your bounded recovery target?
  3. What is your fallback behavior under stress?

Thinking Exercise

Create a risk matrix: performance gain vs crash isolation for three workloads (trusted CPU, untrusted parser, external model inference).

The Interview Questions They Will Ask

  1. What tradeoff did you choose and why?
  2. How do you prove correctness under failure?
  3. Which metric is your leading indicator of incident risk?
  4. “Which measurement would tell you that Elixir/Rustler Ports-versus-NIF Lab is approaching its operating limit?”

Hints in Layers

Hint 1: Starting Point Define one canonical request/response schema for both paths.

Hint 2: Next Level Use identical workload generator for fair comparison.

Hint 3: Technical Details Add timeout wrappers and circuit-breaker around native calls.

Hint 4: Tools/Debugging Track scheduler utilization during NIF stress runs.

Books That Will Help

Topic Book Chapter
NIF behavior Erlang docs NIF tutorial and API docs
Port architecture Erlang docs C nodes and ports tutorial

Implementation Milestones

Integrated basic-to-advanced progression

  1. Use BEAM-P27 to implement and benchmark the Rustler perceptual-hash NIF safely.
  2. Add PHX-P20’s port implementation and dirty-scheduler/crash comparison around the same workload.

Milestone 1 — Contract and fixture: define one representative input, output, invariant, and failure case.

Milestone 2 — Core artifact: Implement a perceptual-hash workload through a port and Rustler NIF, including dirty-scheduler and crash tests.

Milestone 3 — Failure behavior: add timeouts, invalid inputs, crashes, retries, or partitions appropriate to the project.

Milestone 4 — Evidence: automate the definition of done and record a reproducible result.

  1. Baseline behavior validated.
  2. Instrumentation and dashboards available.
  3. Fault injection and recovery validated.
  4. Final report with tradeoffs and next steps.

Testing Strategy

6.1 Test Strategy

  • Unit tests for core transitions
  • Integration tests for runtime flows
  • Fault scenario tests for recovery

6.2 Verification Steps

  • Run full test suite.
  • Run deterministic lab script.

Common Pitfalls and Debugging

Problem 1: “NIF benchmark great, production unstable”

  • Why: benchmark lacked failure and long-tail scenarios.
  • Fix: include fault injection and sustained saturation runs.
  • Quick test: run 30-minute soak with failure injection every minute.

Problem 2: “Port throughput too low”

  • Why: chatty protocol and small message framing overhead.
  • Fix: batch messages and optimize binary framing.
  • Quick test: compare messages/sec before and after batching.

Definition of Done

  • Core functionality works on reference scenarios.
  • Failure path behavior matches design policy.
  • SLO metrics are captured and reproducible.
  • Findings are documented with evidence.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • Every merged source contribution is implemented as a phase of this one artifact, not as a separate project.
  • benchmarks quantify performance and isolation without scheduler starvation.

Project 116: Nx Demand Forecasting Engine

Source: BEAM-P29. Build feature tensors, numerical forecasting, evaluation splits, and batched serving.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Python for result comparison
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: Level 4: Open Core Infrastructure
  • Curriculum Difficulty: Level 4: Advanced
  • Knowledge Area: Numerical Computing, Forecasting
  • Software or Tool: Nx, Nx.Defn, EXLA, Livebook
  • Main Book: “AI Engineering”

What you will build: Build feature tensors, numerical forecasting, evaluation splits, and batched serving.

Why it teaches the BEAM ecosystem: It makes you prove that results are reproducible and beat a visible baseline.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Build feature tensors, numerical forecasting, evaluation splits, and batched serving.

Build demand_forecast, a CLI-oriented forecasting engine for daily item demand. It imports a documented CSV schema, validates and groups series, creates leakage-free windows, trains a small Nx model, compares it with last-value and weekly seasonal baselines, writes a forecast CSV, and stores a reproducibility manifest with the selected parameters.

$ mix forecast.train --input data/daily_demand.csv --lookback 28 --horizon 7 --seed 1042
dataset items=120 rows=175200 rejected=3
split train=2023-01-01..2024-06-30 validation=2024-07-01..2024-09-30 test=2024-10-01..2024-12-31
tensor inputs={18340,28,4} targets={18340,7} dtype=f32
baseline last_value       test_mae=8.41
baseline weekly_seasonal  test_mae=6.92
model linear_window       test_mae=6.31 test_rmse=10.84
artifact=artifacts/linear-window-7d manifest_sha256=8ce1...

3.7.1 How to Run

$ mix deps.get
$ mix test
$ mix forecast.train --input test/fixtures/demand.csv --seed 1042
$ mix forecast.predict --artifact artifacts/reference --from 2025-01-01

3.7.2 Golden Path Demo

The deterministic fixture contains weekly seasonality, promotions, missing days, and one invalid row. The engine rejects the invalid row, derives training-only normalization, trains the reference model, beats the last-value baseline, and explains whether it beats the stronger seasonal baseline.

3.7.3 Exact Terminal Transcript

$ mix forecast.benchmark --artifact artifacts/reference --batch 64
backend=EXLA.Client dtype=f32 input={64,28,4}
eager_median_ms=2.84
jit_first_call_ms=118.72
jit_warm_median_ms=0.43
compiled_variants=1 synchronized=true

The Core Question You Are Answering

“How do I make a numerical forecast fast on the BEAM without confusing tensor validity, compiled speed, and genuine predictive value?”

Concepts You Must Understand First

  1. Matrix/vector shape and element-wise versus matrix operations.
  2. Time-series chronology, windows, horizon, and leakage.
  3. Nx tensor, backend, and container contracts.
  4. Nx.Defn restrictions, JIT specialization, and differentiation.
  5. MAE, RMSE, baseline comparison, and reproducibility.

Questions to Guide Your Design

  1. What domain meaning does every axis carry?
  2. How are missing and out-of-stock observations represented?
  3. Can any training transform see validation or test dates?
  4. Which batch shapes compile, and how is recompilation observed?
  5. What evidence proves the learned model adds value over seasonality?

Thinking Exercise

Draw the lineage of one test prediction backward through its target, input window, preprocessing statistics, model parameters, validation selection, and training rows. If any arrow reaches a later test observation, the design leaks future information.

The Interview Questions They Will Ask

  1. “How do Nx broadcasting bugs produce valid but incorrect results?”
  2. “What code belongs outside a defn?”
  3. “Why is a random train/test split usually invalid for forecasting?”
  4. “How do you benchmark a JIT-compiled function honestly?”
  5. “What makes a model artifact safe to reload?”
  6. “What would you do when the learned model loses to seasonal naive?”

Hints in Layers

Hint 1: Start with baselines — Build evaluation and two naive predictors before any trainable model.

Hint 2: Annotate shapes — Put symbolic input/output shapes in module documentation and assert them at boundaries.

Hint 3: Separate worlds — Keep CSV, dates, IDs, and reporting in ordinary Elixir; keep tensor math in a small numerical core.

Hint 4: Record the experiment — Treat the manifest as required output, not cleanup after training.

Books That Will Help

Topic Book Precise reading
Nx fundamentals Machine Learning in Elixir and Livebook — Moriarity, Tate, DeBenedetto Chapter “The Nx Numerical Computing Library”
Data preparation Machine Learning in Elixir and Livebook Chapter “Data Preprocessing with Explorer,” adapting the concepts to the project loader
Neural/numerical models Machine Learning in Elixir and Livebook Chapter “Neural Networks with Axon” for parameter/loss context, even if the core model remains manual
Forecast evaluation Forecasting: Principles and Practice, 3rd ed. — Hyndman and Athanasopoulos Chapters 3 “The Forecaster’s Toolbox” and 5 “The Time Series Regression Model”

Implementation Milestones

Phase 1: Data Contract and Baselines (5-7 hours)

  • Validate rows and build chronological series.
  • Freeze splits and generate windows without tensors.
  • Implement last-value and weekly seasonal baselines plus metrics.

Phase 2: Tensor Pipeline (5-8 hours)

  • Define axis/dtype contracts and build masked batches.
  • Test singleton and incomplete batches.
  • Verify normalization uses only training data.

Phase 3: Numerical Model (6-9 hours)

  • Implement prediction, loss, gradients, and updates in defn pseudocode design.
  • Add finite-value checks and deterministic initialization.
  • Select a configuration using validation results.

Phase 4: Artifact and Performance (4-8 hours)

  • Evaluate the untouched test interval against baselines.
  • Persist parameters and complete manifest.
  • Benchmark eager, cold JIT, and warmed JIT modes.

Testing Strategy

6.1 Test Categories

Category Purpose Examples
Unit Validate parsing and series rules duplicates, gaps, returns, closures
Shape Protect tensor contracts singleton batch, horizon seven, masks
Numerical Check model math hand-calculated tiny loss and update
Leakage Protect chronology future sentinel values never affect training
Property Stress window generation arbitrary series and split boundaries
Reproducibility Compare repeated runs manifests, metrics, parameter digest
Performance Characterize execution eager, cold JIT, warm JIT, shape variants

6.2 Critical Test Cases

  1. Duplicate item/date input is rejected with both source line numbers.
  2. A window never includes a target outside its split.
  3. Validation/test outliers do not alter normalization parameters.
  4. {batch} versus {batch, 1} target mismatch fails an assertion.
  5. Padded targets do not contribute to loss or metrics.
  6. All-zero demand yields a defined metric report without division surprises.
  7. A deliberately high learning rate triggers a non-finite training diagnostic.
  8. Two seeded reference runs produce equivalent metrics and manifests.
  9. Loading an artifact with reordered features is rejected.
  10. Baselines and model score exactly the same item/date rows.

6.3 Test Data

Use a tiny hand-computable series, a deterministic seasonal series, a multi-item fixture with gaps, a zero-demand series, a one-item singleton case, and a larger generated fixture for performance. Keep split dates and expected windows visible in fixture documentation.

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Problem Why it happens Fix Quick test
Suspiciously low loss Target broadcast across examples Assert exact prediction/target shapes Use a two-row hand-computed batch
Great test result, poor production result Random split or preprocessing leakage Freeze chronological lineage Add future sentinel values
Frequent latency spikes New shapes trigger compilation Plan and count compiled variants Alternate batch sizes in benchmark
Percentage metric explodes Demand can be zero Choose explicit zero-safe metrics Test all-zero series
Artifact predicts nonsense Feature order differs at load Validate full manifest compatibility Swap two feature columns
Training becomes non-finite Scale or learning rate is unstable Normalize, reduce step size, add finite checks Use an intentionally unstable fixture

7.2 Debugging Strategies

  • Print shape, dtype, axis labels, and finite summaries at subsystem boundaries.
  • Reproduce a loss calculation on a two-example tensor by hand.
  • Compare model predictions against both baselines for a single item and horizon.
  • Inspect the exact date lineage for one suspicious test prediction.
  • Count compilation variants and backend transfers during benchmarks.

7.3 Performance Traps

  • Converting each prediction separately from tensor to host data
  • Recompiling for many small shape variations
  • Building every possible window eagerly in memory
  • Timing asynchronous execution without synchronization
  • Using oversized dtypes or retaining gradients during evaluation

Definition of Done

  • Input, rejection, forecast, and artifact schemas are documented.
  • Every tensor boundary asserts shape, dtype, and axis meaning.
  • Chronological leakage tests pass with future sentinel values.
  • Last-value and seasonal baselines are scored on identical test rows.
  • The learned model’s result is reported honestly whether it wins or loses.
  • Repeated seeded runs meet the declared reproducibility tolerance.
  • Cold JIT time is separated from warm execution time.
  • Artifact loads reject incompatible feature order, dtype, or model version.
  • Edge cases have explicit policy rather than silent row deletion.
  • Tests pass on the default backend before optional optimized-backend tests.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • results are reproducible and beat a visible baseline.

Project 117: Nx and Bumblebee Image Triage Lab

Source: LIVE-P10. Build a Livebook inference workbench with preprocessing, serving, provenance, and evaluation.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Python; Julia for external numerical comparison
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: Level 4: Open Core Infrastructure
  • Curriculum Difficulty: Level 4: Advanced
  • Knowledge Area: Tensors, pretrained models, inference serving, evaluation
  • Software or Tool: Livebook, Kino.Input.image, Nx, Bumblebee, Nx.Serving
  • Main Book: Machine Learning in Elixir and Livebook

What you will build: Build a Livebook inference workbench with preprocessing, serving, provenance, and evaluation.

Why it teaches the BEAM ecosystem: It makes you prove that cold start, memory, latency, confidence, and failures are measured.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Build a Livebook inference workbench with preprocessing, serving, provenance, and evaluation.

Build a Livebook lab and app preview for triaging training images into a small, documented label set such as intact package, damaged package, unreadable label, contamination, and unknown. Select a model that is supported by the current Bumblebee release and whose license permits the exercise. The system must:

  • accept a bounded JPEG or PNG through a per-user image input;
  • reject malformed, oversized, or unsupported inputs before inference;
  • display preprocessing and tensor evidence;
  • run a pinned model through Nx.Serving;
  • show ranked suggestions, score, latency phases, and model revision;
  • abstain when the evidence is weak or outside the supported label policy;
  • require accept, correct, or none-of-these input from the human;
  • evaluate a fixed labeled fixture set;
  • discard or explicitly persist user data according to a written retention policy.
IMAGE TRIAGE
Input: training-fixture-014.jpg
Decoded: 1280 x 853 RGB, 412 KiB
Preprocess: orientation normalized -> center crop -> 224 x 224 -> model normalization
Tensor: [1, 224, 224, 3] f32, backend=EXLA host, approx=0.57 MiB

Model: approved-repository@immutable-revision
Artifact digest: sha256:EXAMPLE_REDACTED
Top suggestions:
  damaged_package .... 0.81
  contamination ...... 0.11
  intact_package ..... 0.05

Decision: SUGGEST — human confirmation required
Queue / inference / total: 3 / 47 / 61 ms
Warm path: yes

Open the app preview from two browser profiles. Upload distinct canary images and verify private previews and results. In each session, the user sees an input-contract card, tensor card, provenance card, ranked result, and decision controls. A corrupt or oversized image produces a bounded error before the serving process is called. A deliberately unfamiliar image results in abstention under the documented policy.

The evaluation section produces an evidence report such as:

EVALUATION FIXTURE r3
Images: 120 labeled + 20 out-of-distribution + 8 corrupt
Macro precision / recall: 0.78 / 0.74
Abstention rate: 16.7%
Correct among non-abstained: 84.0%
Corrupt rejected before inference: 8 / 8
Cross-client canary leak scan: PASS
Artifact offline startup: PASS
Retention scan after session close: PASS

The learner can point to the exact input, artifact, preprocessing, serving, evaluation, privacy, and human-decision contracts rather than merely displaying a prediction.

The Core Question You Are Answering

“What evidence must surround a model prediction before it can safely influence a real workflow?”

If the answer is only “the label and score,” the project is not ready. The required answer includes input validity, preprocessing, shape/type, artifact identity, latency phases, evaluation, uncertainty, privacy, and human authority.

Concepts You Must Understand First

  1. Tensor shape, type, axes, and backend
    • Can you explain the meaning of every dimension and copy?
    • Primary reference: Nx
  2. Numerical definitions and compilation
  3. Serving lifecycle
    • How do batch size and timeout affect latency and throughput?
    • Primary reference: Nx.Serving
  4. Bumblebee artifact contracts
    • Which repository files define model, featurizer, tokenizer, and labels?
    • Primary reference: Bumblebee
  5. Classification evaluation
    • Why do per-class errors and abstention matter?
    • Book reference: AI Engineering — evaluation and inference chapters
  6. Kino per-user interaction

Questions to Guide Your Design

  1. What exact file signatures, byte limits, and dimensions are accepted?
  2. What happens to EXIF orientation, alpha, grayscale, and animated images?
  3. Does crop or letterbox preserve the defect the model should see?
  4. Which immutable model revision and license are approved?
  5. How is label mapping verified against the model output?
  6. What score or margin causes abstention, and how was it chosen?
  7. Where can private content exist, and when is each copy deleted?
  8. Is the serving process shared, and if so, what data can cross that boundary safely?

Thinking Exercise

Trace one 12-megapixel phone image on paper. Mark:

  • compressed bytes in the browser and runtime;
  • decoded pixel allocation;
  • resized allocation;
  • tensor allocation and any backend transfer;
  • batch padding or copy;
  • model intermediates;
  • result and preview retention.

Then decide which allocations are rejected, bounded, reused, or deleted. Repeat for a corrupt image and a second concurrent client.

The Interview Questions They Will Ask

  1. “How can broadcasting or reshaping hide a semantic tensor bug?”
  2. “Why separate cold-start, queue, inference, and total latency?”
  3. “What does Nx.Serving provide beyond calling a model function?”
  4. “How do fixed shapes affect compilation and batching?”
  5. “Why is a model score not necessarily a calibrated probability?”
  6. “How do you make a pretrained model deployment reproducible and offline-capable?”

Hints in Layers

Hint 1: Prove the input contract first

Reject malicious and oversized fixtures before loading any model. The validation pipeline should be testable independently.

Hint 2: Make shape visible

Render expected versus actual axes and type immediately before serving.

Hint 3: Warm once and measure phases

Do not combine download, loading, compilation, queue, and execution into one latency number.

Hint 4: Evaluate decisions, not screenshots

Use a labeled manifest, confusion matrix, per-class metrics, abstention, and human correction. One successful picture proves almost nothing.

Books That Will Help

Topic Book Chapter
Nx-native ML workflow Machine Learning in Elixir and Livebook Nx, transfer learning, and pretrained-model chapters
Inference systems AI Engineering by Chip Huyen Evaluation and inference chapters
Decision metrics Data Science for Business Chapters 7–8
Reliable service boundaries Release It!, 2nd ed. Timeouts, capacity, and stability patterns

Implementation Milestones

Phase 1: Input and Artifact Contracts (6–8 hours)

Goals: validate inputs without model execution and select an approved artifact.

Tasks:

  1. Build valid, corrupt, oversized, unusual-color, and out-of-distribution fixtures.
  2. Write input and retention contracts.
  3. Verify model support, task, labels, revision, digest, and license.
  4. Define exact preprocessing and compile shapes.

Checkpoint: every invalid fixture fails at the intended bounded stage, and offline artifact verification passes.

Phase 2: Serving and Interactive Decision (7–11 hours)

Goals: produce visible tensor evidence, warm serving, and private per-session results.

Tasks:

  1. Connect preprocessing to Nx tensors with shape assertions.
  2. Create a bounded serving path and latency instrumentation.
  3. Apply suggest/abstain policy.
  4. Add accept/correct/none controls without mutating raw output.
  5. Test two simultaneous clients with distinct canaries.

Checkpoint: warm requests are bounded, instrumented, isolated, and human-confirmed.

Phase 3: Evaluation and Failure Hardening (7–13 hours)

Goals: evaluate the workflow, not just the model call.

Tasks:

  1. Run the fixed labeled fixture manifest.
  2. Report per-class metrics, confusion, abstention, and failures.
  3. Stress queue and memory under bounded concurrency.
  4. Test offline restart, corrupt cache, serving timeout, and session cleanup.

Checkpoint: evaluation report, privacy scan, retention scan, and clean replay pass.

Testing Strategy

6.1 Test Categories

Category Purpose Examples
Input contract Reject unsafe data early wrong magic bytes, huge dimensions, alpha/grayscale policy
Tensor contract Prove numerical boundary axis order, dtype, backend, normalized range
Artifact Preserve reproducibility digest mismatch, missing cache, offline startup
Decision Validate suggest/abstain behavior threshold boundary, tie, unknown class
Evaluation Measure real task quality confusion matrix, per-class recall, OOD abstention
Concurrency/privacy Protect multiple users simultaneous canary uploads, queue saturation, cleanup
Failure recovery Keep UI truthful timeout, serving crash, corrupt image, memory budget

6.2 Critical Test Cases

  1. Magic-byte mismatch: a renamed non-image is rejected before decode.
  2. Decompression bomb dimensions: dimensions exceed policy and no tensor is allocated.
  3. Axis sentinel: a synthetic color pattern proves channel and axis order.
  4. Artifact mismatch: wrong digest fails closed and does not silently fetch another revision.
  5. Cold versus warm: preparation and five warm requests are reported separately.
  6. Threshold edge: just-below and just-above scores enter different documented states.
  7. OOD image: unsupported content produces abstention or an explicit limitation finding.
  8. Cross-client canaries: image A, result A, and correction A never appear in session B.
  9. Queue saturation: bounded overload returns a visible busy/timeout state without unbounded memory.
  10. Session close: uploaded bytes and private correction are absent from retained runtime evidence.

6.3 Test Data

Fixture manifest fields:
  id, relative_path, sha256, expected_label_or_ood,
  width, height, format, known_edge_case, license/source

Required groups:
  representative labeled images
  ambiguous in-domain images
  class-imbalanced slice
  out-of-distribution images
  corrupt/truncated files
  oversized-dimension headers
  two private canary images

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Pitfall Symptom Solution
Input bounds checked after decode Memory spike before rejection Inspect bytes/header and enforce dimensions first
Axis order assumed Plausible but wrong predictions Use a synthetic channel/shape sentinel
First request reported as inference Misleading multi-second latency Separate download, load, compile, queue, execute
Artifact fetched during startup Offline deployment fails Prefetch, pin, digest, and verify cache
Score labeled “confidence” Users over-trust result Use score wording and measured decision policy
Shared Kino input Users see another image Use multi-session/per-user controls and canary test
Correction overwrites model output Evaluation evidence disappears Store raw output and human action separately

7.2 Debugging Strategies

  • Render the contract: shape, type, axes, backend, and ranges before model execution.
  • Time each stage: identify whether delay is queue, compile, artifact, or inference.
  • Use sentinel images: controlled colors and geometry reveal orientation/channel errors.
  • Disable network: expose implicit model fetches.
  • Run one client, then two: isolate privacy problems from model problems.
  • Inspect process memory between requests: detect retained uploads or repeated model copies.

7.3 Performance Traps

Variable shapes can cause recompilation; repeated device copies waste bandwidth; decoding full-resolution uploads before bounds wastes memory; large batch windows increase interactive latency; one model per session can exhaust memory; unbounded correction logs retain private data. Measure peak memory and queue time under the expected concurrent-session budget.

Definition of Done

Minimum Viable Completion:

  • One bounded image reaches a visible, asserted tensor contract and pinned model.
  • The result can suggest or abstain and requires a human action.
  • Corrupt and oversized fixtures fail safely.

Full Completion:

  • Complete artifact provenance, fixed preprocessing, offline startup, phase-specific latency, Nx.Serving bounds, labeled evaluation, per-class metrics, OOD tests, two-client isolation, retention scan, and clean replay all pass.

Excellence (Going Above & Beyond):

  • Demonstrate a supervised shared serving architecture with measured batching, capacity model, calibrated decision threshold, immutable container artifact, and privacy review—without changing the human-owned decision boundary.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • cold start, memory, latency, confidence, and failures are measured.

Phase 7 - State Machines, Distribution, VM Internals, and Releases

Project 118: Durable gen_statem OTP Control Plane

Sources: BEAM-P30, ERL-P10, PHX-P16. Progress from a protocol machine to a durable workflow using timeouts, postponed events, dynamic supervision, Registry, ETS, and metadata persistence.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir and Erlang
  • Alternative Programming Languages: Gleam
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: Level 4: Open Core Infrastructure
  • Curriculum Difficulty: Level 4: Advanced
  • Knowledge Area: State Machines, Temporal Workflows
  • Software or Tool: :gen_statem, Ecto, OTP supervision
  • Main Book: “Designing for Scalability with Erlang/OTP”

What you will build: Progress from a protocol machine to a durable workflow using timeouts, postponed events, dynamic supervision, Registry, ETS, and metadata persistence.

Why it teaches the BEAM ecosystem: It makes you prove that restart reconstructs state without repeating effects.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Integrated Scope

This is one consolidated project, not separate source builds. Implement the following contributions as phases of the same artifact:

  • Start with ERL-P10 transition tables, event types, state-enter actions, and timer semantics.
  • Add BEAM-P30 durable deadlines, postponed events, idempotent commands, and recovery.
  • Host that one workflow as the PHX-P16 supervised control plane with Registry, ETS, and persisted metadata.

Real World Outcome

Build target: Progress from a protocol machine to a durable workflow using timeouts, postponed events, dynamic supervision, Registry, ETS, and metadata persistence.

Build an escrow workflow service with one supervised :gen_statem process per active escrow, a Registry for routing, a versioned journal adapter, a provider-dispatch adapter, and an operator CLI. The reference workflow covers submission, risk review, approval, capture, cancellation, expiry, and manual review after uncertain provider outcomes.

$ escrowctl submit --id ESC-42 --amount 12500 --currency BRL --command C1
accepted escrow=ESC-42 sequence=1 state=risk_review deadline=2026-07-15T18:00:00Z

$ escrowctl approve ESC-42 --command C2
accepted sequence=2 state=approved

$ escrowctl capture ESC-42 --command C3
accepted sequence=3 state=capture_pending provider_key=ESC-42-capture-v1

3.7.1 How to Run

$ mix deps.get
$ mix test
$ mix escrow.demo --scenario crash-after-provider-success

3.7.2 Golden Path Demo

Submit, approve, and capture one escrow. Kill its machine after capture_requested is durable. Restart it, replay the journal, retry the provider with the same idempotency key, receive the original provider outcome, and reach captured with exactly one provider effect.

3.7.3 Exact Terminal Transcript

$ mix escrow.demo --scenario crash-after-provider-success
ESC-42 sequence=3 state=capture_pending action=provider_capture
provider key=ESC-42-capture-v1 result=success reference=PAY-9001
FAULT injected=kill_before_local_confirmation
RECOVERY snapshot=none replayed=3 state=capture_pending
RETRY provider key=ESC-42-capture-v1 result=already_succeeded reference=PAY-9001
JOURNAL sequence=4 event=capture_confirmed
FINAL state=captured provider_effect_count=1 invariant=ok

The Core Question You Are Answering

“How can a BEAM process coordinate a long-running money workflow when commands, deadlines, provider outcomes, and crashes may arrive in any order?”

Concepts You Must Understand First

  1. OTP process lifecycle, links, and supervision.
  2. :gen_statem event types, callback modes, actions, and timeouts.
  3. Domain-event journals and optimistic sequence checks.
  4. Idempotency keys and at-least-once delivery.
  5. Monotonic elapsed time versus persisted wall-clock deadlines.

Questions to Guide Your Design

  1. Which states and transitions are legally meaningful to the domain?
  2. At what durable point may a client receive “accepted”?
  3. Which side effects require stable external idempotency keys?
  4. What happens when a result arrives after its deadline or state change?
  5. How will recovery distinguish historical effects from pending obligations?

Thinking Exercise

Draw two timelines for the same capture: provider succeeds before local crash, and provider succeeds after local retry. Demonstrate why a stable provider key and journaled intent converge both timelines to one captured outcome.

The Interview Questions They Will Ask

  1. “When should you use :gen_statem instead of GenServer?”
  2. “What is the difference between state timeout, event timeout, and generic timeout?”
  3. “How do postponed events become a memory or correctness problem?”
  4. “Why can’t supervision provide durable business recovery?”
  5. “What exactly-once guarantee can you honestly make across a payment provider?”
  6. “How do you recover timers and side effects after replay?”

Hints in Layers

Hint 1: Write the table first — Define events, guards, journal fact, next state, reply, and actions before callbacks.

Hint 2: Journal before acceptance — A transition that is only in process memory is not an accepted financial fact.

Hint 3: Side effects are obligations — Record provider intent, then fulfill it with a stable key outside the machine.

Hint 4: Replay is pure — Rebuild state first; derive timers and unfinished work only after replay ends.

Books That Will Help

Topic Book Precise reading
Stateful OTP Elixir in Action, 3rd ed. — Saša Jurić Chapters 6 “Generic Server Processes” and 7 “Building a Concurrent System”
Failure boundaries Elixir in Action, 3rd ed. Chapter 9 “Isolating Error Effects”
OTP behaviours Designing for Scalability with Erlang/OTP — Cesarini and Vinoski Chapters covering generic behaviours and finite-state machines
State-machine contrast Learn You Some Erlang for Great Good! — Fred Hébert “Rage Against the Finite-State Machines,” read with current gen_statem docs because its legacy behaviour differs

Implementation Milestones

Integrated basic-to-advanced progression

  1. Start with ERL-P10 transition tables, event types, state-enter actions, and timer semantics.
  2. Add BEAM-P30 durable deadlines, postponed events, idempotent commands, and recovery.
  3. Host that one workflow as the PHX-P16 supervised control plane with Registry, ETS, and persisted metadata.

Milestone 1 — Contract and fixture: define one representative input, output, invariant, and failure case.

Milestone 2 — Core artifact: Progress from a protocol machine to a durable workflow using timeouts, postponed events, dynamic supervision, Registry, ETS, and metadata persistence.

Milestone 3 — Failure behavior: add timeouts, invalid inputs, crashes, retries, or partitions appropriate to the project.

Milestone 4 — Evidence: automate the definition of done and record a reproducible result.

Phase 1: Domain and Pure Reducer (5-7 hours)

  • Define states, event schemas, transition invariants, and deadlines.
  • Build a pure event reducer and transition-table tests.
  • Add command IDs and deterministic duplicate outcomes.

Phase 2: :gen_statem Runtime (6-9 hours)

  • Implement chosen callback mode, replies, internal events, and timeouts.
  • Add Registry, DynamicSupervisor, and operator inspection.
  • Prove callbacks remain responsive while provider work is pending.

Phase 3: Durable Intent and Recovery (7-11 hours)

  • Add expected-sequence journal and snapshots.
  • Add provider intent dispatcher with stable keys.
  • Recover state, deadlines, and unfinished obligations after injected crashes.

Phase 4: Race and Operations Hardening (6-9 hours)

  • Test expiry/approval and cancellation/provider races.
  • Add unknown-callback quarantine and schema versioning.
  • Document operator actions for uncertain provider outcomes.

Testing Strategy

6.1 Test Categories

Category Purpose Examples
Transition Verify legal table every state/event pair
Trace/Property Check invariants over event sequences terminal monotonicity, non-negative sequence
Timeout Verify temporal policy before, at, and after deadline
Idempotency Prevent duplicate effects repeated commands and callbacks
Recovery Rebuild deterministic state every crash point around append/dispatch/result
Concurrency Expose ownership races two starters, append conflict
Security Protect financial metadata redaction and actor authorization boundary

6.2 Critical Test Cases

  1. Every unspecified state/event pair returns an explicit stable rejection.
  2. Duplicate accepted and rejected command IDs return their original outcomes.
  3. Crash before journal append leaves no accepted transition.
  4. Crash after append but before reply recovers the accepted command result.
  5. Crash after provider success but before confirmation creates one provider effect.
  6. Duplicate and out-of-order provider callbacks are harmless or quarantined.
  7. Expiry and approval at the same boundary follow the documented rule in both arrival orders.
  8. Replay rejects missing or duplicate journal sequence numbers.
  9. Old event schema is upcast or rejected explicitly.
  10. A split-owner append conflict causes one owner to stop and reload.

6.3 Test Data

Use a deterministic fake clock, journal, and provider. Create trace fixtures for happy capture, risk rejection, cancellation, expiry, uncertain provider response, duplicate callbacks, corrupt snapshot, and old event schemas. The provider records keys and effect count so exactly-one external effect is observable.

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Problem Why it happens Fix Quick test
Machine blocks during capture Provider called inside callback Journal intent and dispatch asynchronously Delay fake provider while inspecting state
Money movement repeats Retry generates new provider key Derive stable key from escrow and operation Crash after provider success
Restart loses deadline Only timer reference was stored Persist absolute deadline and reconstruct Restart halfway to expiry
Invalid commands accumulate Everything is postponed Postpone only bounded future-valid events Send repeated impossible captures
Replay repeats notifications Event reducer performs side effects Keep replay pure; derive unfinished work afterward Count fake side effects during replay
Two processes advance one escrow Runtime registry assumed infallible Expected-sequence append and ownership conflict policy Race two starts

7.2 Debugging Strategies

  • Render the transition table row selected for each event.
  • Include escrow ID, state, journal sequence, event class, and correlation in structured logs.
  • Compare in-memory sequence with durable tail after any suspicious transition.
  • Use :sys tracing and :gen_statem debugging options in controlled tests.
  • Re-run a production-like journal through the pure reducer without starting a machine.

7.3 Performance Traps

  • Unbounded command-deduplication data held forever in every process
  • Replaying an entire long journal on every activation without verified snapshots
  • One global dispatcher serialized across unrelated escrows
  • Large journal payloads copied into process messages
  • Keeping terminal machines active indefinitely instead of passivating them safely

Definition of Done

  • A reviewed transition table covers every state/event pair.
  • Illegal commands never append journal events.
  • Accepted commands are journaled before acceptance is reported.
  • Duplicate commands and provider callbacks are deterministic.
  • All external actions originate from durable intent with stable keys.
  • Recovery performs pure replay before installing timers or dispatching work.
  • Crash injection around every durability boundary converges correctly.
  • Deadline race policy is documented and tested in both event orders.
  • Operator output exposes pending obligations and journal sequence.
  • Sensitive values are redacted from logs, test snapshots, and errors.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • Every merged source contribution is implemented as a phase of this one artifact, not as a separate project.
  • restart reconstructs state without repeating effects.

Project 119: Distributed KV and Mnesia Work-Order Ledger

Sources: BEAM-P3, BEAM-P35, ERL-P9. Evolve explicit ETS sharding into Mnesia tables, transactions, disk copies, and recovery policy.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir/Erlang
  • Alternative Programming Languages: Erlang
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: Level 4: Open Core Infrastructure
  • Curriculum Difficulty: Level 4: Advanced
  • Knowledge Area: Distributed State, Transactions, Operational Recovery
  • Software or Tool: Mnesia, Distributed Erlang, Supervisor
  • Main Book: “Designing Data-Intensive Applications”

What you will build: Evolve explicit ETS sharding into Mnesia tables, transactions, disk copies, and recovery policy.

Why it teaches the BEAM ecosystem: It makes you prove that node loss and concurrent updates preserve ledger invariants.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Integrated Scope

This is one consolidated project, not separate source builds. Implement the following contributions as phases of the same artifact:

  • Use BEAM-P3 to expose partitioning, ownership, and replication decisions explicitly.
  • Introduce ERL-P9 Mnesia schema, transactions, and copy types.
  • Finish as BEAM-P35’s auditable work-order ledger with node-loss and concurrent-update recovery drills.

Real World Outcome

Build target: Evolve explicit ETS sharding into Mnesia tables, transactions, disk copies, and recovery policy.

Build maint-ledger, a three-node service used by a factory or field-service team to report, triage, assign, start, complete, and cancel maintenance work. Each transition records the current order, an immutable versioned event, and a durable notification outbox entry in one Mnesia transaction. Operators can inspect node/table readiness, remove a node from service, add or restore replicas, simulate a 2+1 network partition, create a backup, and restore it into an isolated recovery cluster.

$ maint-ledger report --site CWB-01 --asset press-7 --severity high --request req-101
committed work_order=WO-1842 state=reported version=1 node=maint-a

$ maint-ledger transition WO-1842 triage --expect-version 1 --request req-102
committed work_order=WO-1842 state=triaged version=2 audit_event=WO-1842/2

$ maint-ledger history WO-1842 --node maint-c
1 reported actor=operator-4 request=req-101
2 triaged actor=planner-2 request=req-102

$ maint-ledger cluster status
ready_nodes=3 database_nodes=3 critical_tables=ready majority_policy=enabled backup_age=04h12m

The learner opens three terminals or container logs showing maint-a, maint-b, and maint-c. A work order created on maint-a is immediately readable on maint-c with matching history. After maint-c is killed abruptly, two nodes continue committing transitions. When it returns, it remains outside traffic while tables load and then reports the caught-up version. During a 2+1 partition, the majority commits one transition while the minority returns a clear majority-unavailable error. Healing produces an explicit recovery event and checklist rather than an automatic “all good.” Finally, the learner restores a backup into an isolated cluster and validates every current version against its event history.

$ maint-ledger drill netsplit --isolate maint-c
partition majority=[maint-a,maint-b] minority=[maint-c]

$ maint-ledger transition WO-1842 start-work --expect-version 4 --node maint-a
committed work_order=WO-1842 state=in_progress version=5 replicas_available=2/3

$ maint-ledger transition WO-1842 cancel --expect-version 4 --node maint-c
aborted reason=no_majority table=work_orders ready=false

$ maint-ledger drill heal
event=inconsistent_database affected=maint-c action=traffic_blocked
authority_candidate=[maint-a,maint-b] evidence_version=5 operator_decision=required

$ maint-ledger restore verify ./backups/maint-2026-07-15.bup --cluster recovery
tables=3 work_orders=1842 event_chains_valid=1842 outbox_orphans=0 checksum=ok promotable=true

The Core Question You Are Answering

“When three BEAM nodes hold durable replicas, what proves that one committed work-order history remains authoritative through node loss, a network split, and restoration from backup?”

Answer with invariants, table-copy policy, readiness evidence, and operator decisions—not with “Mnesia handles it.”

Concepts You Must Understand First

  1. Distributed Erlang identity and connectivity
    • Why are node names, hostname resolution, cookies/TLS, and ports part of database operation?
    • Book Reference: Designing for Scalability with Erlang/OTP — distribution sections.
  2. Mnesia schema and copy types
    • Which metadata is distributed, and where is each table held?
    • What persists for each copy type?
  3. Transactions and locks
    • Which work-order invariants require one atomic activity?
    • Why are dirty writes unsafe here?
  4. Supervision versus readiness
    • Why can every child be alive while tables remain inaccessible?
  5. Partition consistency policy
    • Which island may write, and what evidence chooses authority after healing?
  6. Backup versus replication
    • Which failures are copied to every replica?
    • How is a backup proven restorable?

Questions to Guide Your Design

  1. Which node names and data directories remain stable for the cluster lifetime?
  2. Which tables form one invariant and therefore need compatible replica/majority policy?
  3. Which state is ephemeral enough for ram_copies?
  4. Can any application path issue a dirty critical write?
  5. What abort reasons are retryable, conflicting, or operationally fatal?
  6. What exact checks make a node ready for reads and writes?
  7. What happens when a returning node has an empty versus intact directory?
  8. Which island may write during a 2+1 split?
  9. Who authorizes master-node or force-load recovery?
  10. Where are backups stored, how are they checksummed, and when was the last successful restore?
  11. How are schema transformations coordinated with backup and rollback?

Thinking Exercise

Four failures, four different recoveries

Draw one timeline each for: application-process crash, one BEAM node crash with intact disk, one node’s disk loss, and a 2+1 network partition. For each, mark surviving processes, table replicas, majority, allowed writes, readiness, required operator action, and whether backup is needed. If two diagrams look identical, revisit the failure assumptions.

The Interview Questions They Will Ask

  1. “What is the difference between ram_copies, disc_copies, and disc_only_copies?”
  2. “How do Mnesia transactions differ from dirty operations?”
  3. “Why does replication not eliminate the need for backup?”
  4. “How do you prevent a minority partition from accepting conflicting work-order updates?”
  5. “Why must an application wait for tables after Mnesia starts?”
  6. “What would you inspect before calling force_load_table or selecting master nodes?”

Hints in Layers

Hint 1: Make one invariant visible

Start with one current table and one history table. Prove they never diverge before adding outbox or clustering.

Hint 2: Add replicas deliberately

Begin on one disposable node, then bootstrap three stable names and add copies through an explicit administrative flow. Print table metadata after every change.

Hint 3: Readiness is a report

Represent readiness as evidence for each required table and policy. A boolean alone hides the reason an operator needs.

Hint 4: Treat recovery as destructive

Copy directories and backup artifacts before force-load, fallback, truncation, or restore experiments. Automate evidence collection, not the authority decision.

Books That Will Help

Topic Book/Paper Chapter/Section
Mnesia architecture Mnesia — A Distributed Robust DBMS for Telecommunications Applications — Wikström, Nilsson Full paper
OTP distribution and recovery Designing for Scalability with Erlang/OTP — Cesarini, Vinoski Distribution and operations sections
Erlang databases and OTP Erlang Programming — Cesarini, Thompson Mnesia and distributed programming sections
Partition trade-offs Designing Data-Intensive Applications — Kleppmann Replication, transactions, and distributed-system trouble chapters

Implementation Milestones

Integrated basic-to-advanced progression

  1. Use BEAM-P3 to expose partitioning, ownership, and replication decisions explicitly.
  2. Introduce ERL-P9 Mnesia schema, transactions, and copy types.
  3. Finish as BEAM-P35’s auditable work-order ledger with node-loss and concurrent-update recovery drills.

Milestone 1 — Contract and fixture: define one representative input, output, invariant, and failure case.

Milestone 2 — Core artifact: Evolve explicit ETS sharding into Mnesia tables, transactions, disk copies, and recovery policy.

Milestone 3 — Failure behavior: add timeouts, invalid inputs, crashes, retries, or partitions appropriate to the project.

Milestone 4 — Evidence: automate the definition of done and record a reproducible result.

Phase 1: Transactional single-node ledger (10-14 hours)

  • Define state machine, current/event/outbox records, and transaction result mapping.
  • Prove expected-version conflicts and event/current invariants.
  • Add dispatcher idempotency without external effects inside transactions.
  • Checkpoint: forced transaction abort leaves no partial current/event/outbox state.

Phase 2: Three durable replicas and readiness (12-18 hours)

  • Bootstrap stable nodes/directories and critical disc_copies.
  • Add table waits, replica audit, cluster status, and traffic admission.
  • Kill/rejoin one node and measure continuation/catch-up.
  • Checkpoint: two ready nodes continue while a returning node remains unready until tables validate.

Phase 3: Partition and disaster recovery (13-23 hours)

  • Enable/test majority policy and Mnesia event subscription.
  • Run a 2+1 partition and controlled heal procedure.
  • Create/checksum/offload backup and restore it into isolation.
  • Measure RPO/RTO and complete operator runbooks.
  • Checkpoint: recovery verifier proves current/event/outbox invariants before promotion.

Testing Strategy

6.1 Test Categories

Category Purpose Examples
State-machine tests Prove domain transitions allowed/forbidden transitions and version increments
Transaction tests Prove atomic invariant abort after each planned write, concurrent expected versions
Replica tests Prove placement and durability table-copy audit, node stop/rejoin, empty data directory
Readiness tests Prove traffic gating table timeout, schema drift, unresolved inconsistency
Partition tests Prove majority policy 2+1 split, minority transaction, dirty-write guard
Backup tests Prove recoverability checksum, isolated restore, invariant scan
Performance tests Measure operating envelope transaction latency, abort rate, catch-up, restore duration

6.2 Critical Test Cases

  1. Atomic transition: Current row, audit event, and outbox item appear together or not at all.
  2. Optimistic conflict: Two callers use version 4; exactly one reaches version 5 and the other receives a conflict.
  3. Coordinator failure: Node/process loss during a transaction never exposes partial invariant tables.
  4. Clean node stop: Two-node majority remains ready and commits protected writes.
  5. Abrupt node loss: Same availability goal, with explicit event/catch-up evidence.
  6. Returning intact replica: Node stays unready until required tables load and latest version is visible.
  7. Lost data directory: Node is not treated as an intact replica; controlled replica restoration is required.
  8. Minority partition: Normal critical transaction aborts for no majority.
  9. Dirty-write prohibition: Application API contains no route that bypasses the transactional policy; a drill demonstrates why.
  10. Heal event: Inconsistent-database evidence blocks readiness until the runbook resolves authority.
  11. Logical delete: Delete reaches every replica, proving replica count is not backup.
  12. Isolated restore: Backup restores and every current order has a contiguous event chain and valid outbox references.
  13. Corrupt backup: Checksum or restore failure produces not-promotable status.
  14. Schema mismatch: Application refuses traffic when table attributes/version do not match expected metadata.

6.3 Test Data

WO-100: reported -> triaged -> assigned -> in_progress -> completed
WO-101: reported -> cancelled
WO-102: competing assigned and cancelled transitions from same version
WO-103: pending outbox delivery with provider timeout
cluster fixtures: healthy-3, node-down-1, empty-rejoin, split-2-plus-1
backup fixtures: valid, checksum-mismatch, missing event, orphan outbox

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Pitfall Symptom Solution
Schema bootstrap on every boot Conflicting create/change operations Separate administrative bootstrap/migrations
Shared Mnesia directory Unpredictable files and corruption risk One unique persistent directory per node
Renamed node with old data Tables wait or schema references ghost node Treat node identity as durable configuration
API ready after mnesia:start Requests fail with table unavailable Wait/audit every required table
Mixed replica policy Multi-table transaction loses expected availability Align critical table holders/copy/majority settings
Dirty invariant update Current state without matching event Prohibit dirty writes to critical tables
External call in transaction Duplicate notification after transaction retry/abort Durable outbox after commit
Majority assumed universal Dirty or differently configured table writes on minority Test every critical access path
Automatic force load Stale island becomes authoritative Require evidence and operator decision
Replicas called backups Logical delete exists everywhere Off-cluster backup and restore drills
Untested backup Artifact exists but cannot recreate valid schema/state Isolated restore plus invariant verification

7.2 Debugging Strategies

  • Inspect table metadata: Compare configured and actual replica holders, copy types, majority, load source, size, and accessibility.
  • Separate distribution from database state: Test node ping/RPC, then Mnesia running nodes, then table readiness.
  • Classify aborts: Count conflicts, no-majority, unavailable-table, lock/contention, and application validation separately.
  • Subscribe to system events: Preserve the first partition/inconsistency evidence before attempting recovery.
  • Trace one work-order version: Compare current record, ordered event key, and outbox event ID on each ready node.
  • Recover only from copies: Duplicate directories and backup artifacts before destructive investigation.

7.3 Performance Traps

Replicated transactions pay network and disk costs, hot work orders contend on locks, long transaction functions retain locks, and large records increase replication overhead. disc_only_copies can reduce memory but slow access substantially. Backup/restore and replica catch-up compete for I/O. Measure normal and degraded modes separately. Do not substitute dirty writes for a hot design without first partitioning contention or changing the domain workflow.

Definition of Done

  • Three stable database nodes use unique persistent Mnesia directories.
  • Critical tables have documented type, attributes, disc_copies placement, and majority policy.
  • Current work order, audit event, and outbox intent commit atomically.
  • No external network side effect occurs inside a Mnesia transaction.
  • Dirty critical writes are absent and guarded by design/tests.
  • Every node remains unready until required tables and replica policy validate.
  • One-node clean and abrupt loss preserve tested majority operation.
  • Returning replicas catch up before traffic admission.
  • The one-node minority cannot commit protected transitions during a 2+1 partition.
  • Healing a partition produces evidence and an operator-controlled authority decision.
  • Backup artifacts are checksummed, stored outside the cluster failure domain, and restored in isolation.
  • Restore verification checks current versions, contiguous event chains, and outbox references.
  • Runbooks cover bootstrap, node rejoin, netsplit, backup, online restore, and disaster recovery.
  • RPO/RTO results distinguish replica failure from total-cluster loss.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • Every merged source contribution is implemented as a phase of this one artifact, not as a separate project.
  • node loss and concurrent updates preserve ledger invariants.

Project 120: Elixir and OTP Upgrade Readiness Matrix

Official topic: Compatibility and deprecations — Elixir v1.20.2

Source file: lib/elixir/pages/references/compatibility-and-deprecations.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: Level 2: Micro-SaaS / Pro Tool
  • Curriculum Difficulty: Level 4: Advanced
  • Knowledge Area: Compatibility / Release Engineering
  • Software or Tool: CI matrix, asdf or mise, compiler warnings
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build a CI matrix over supported Elixir and OTP pairs, inventory experimental and deprecated usage, classify soft, hard, and removal stages, and publish a migration-risk and exception report.

Why it teaches this official topic: The artifact makes Elixir version compatibility, independent OTP support, experimental feature policy, deprecation stages observable through one bounded build instead of isolated syntax examples.

Scope boundary: Decide source and toolchain upgrade readiness; leave packaging and hot code upgrade execution to later release projects.

Core challenges you will face:

  • Elixir version compatibility -> identify the accepted case, the counterexample, and the observable result at the CI matrix, asdf or mise, compiler warnings boundary
  • independent OTP support -> identify the accepted case, the counterexample, and the observable result at the CI matrix, asdf or mise, compiler warnings boundary
  • experimental feature policy -> identify the accepted case, the counterexample, and the observable result at the CI matrix, asdf or mise, compiler warnings boundary
  • deprecation stages -> identify the accepted case, the counterexample, and the observable result at the CI matrix, asdf or mise, compiler warnings boundary

Real World Outcome

Build a CI matrix over supported Elixir and OTP pairs, inventory experimental and deprecated usage, classify soft, hard, and removal stages, and publish a migration-risk and exception report. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • Every supported pair has a recorded compile and test result.
  • Deprecations are classified by stage and target version.
  • Unsupported pairs fail before release construction.

Acceptance transcript:

$ mix compatibility.matrix
SOURCE_TOPIC=references/compatibility-and-deprecations.md
ARTIFACT=elixir-and-otp-upgrade-readiness-matrix
CHECK 01 PASS :: Every supported pair has a recorded compile and test result
CHECK 02 PASS :: Deprecations are classified by stage and target version
CHECK 03 PASS :: Unsupported pairs fail before release construction
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“What evidence is required before declaring an application compatible with a new Elixir and OTP pair?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. Elixir version compatibility
    • Working rule: Make “Elixir version compatibility” an explicit rule at the CI matrix, asdf or mise, compiler warnings boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "elixir-version-compatibility-positive", focus: "Elixir version compatibility", mode: :positive, expect: :observable} and %{id: "elixir-version-compatibility-negative", focus: "Elixir version compatibility", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Compatibility and deprecations
  2. independent OTP support
    • Working rule: Make “independent OTP support” an explicit rule at the CI matrix, asdf or mise, compiler warnings boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "independent-otp-support-positive", focus: "independent OTP support", mode: :positive, expect: :observable} and %{id: "independent-otp-support-negative", focus: "independent OTP support", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Compatibility and deprecations
  3. experimental feature policy
    • Working rule: Make “experimental feature policy” an explicit rule at the CI matrix, asdf or mise, compiler warnings boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "experimental-feature-policy-positive", focus: "experimental feature policy", mode: :positive, expect: :observable} and %{id: "experimental-feature-policy-negative", focus: "experimental feature policy", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Compatibility and deprecations
  4. deprecation stages
    • Working rule: Make “deprecation stages” an explicit rule at the CI matrix, asdf or mise, compiler warnings boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "deprecation-stages-positive", focus: "deprecation stages", mode: :positive, expect: :observable} and %{id: "deprecation-stages-negative", focus: "deprecation stages", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Compatibility and deprecations

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “Elixir version compatibility” be enforced?
    • Which check catches the risk “Newest Elixir is tested only with newest OTP”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “Every supported pair has a recorded compile and test result”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Compatibility and deprecations”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: Elixir version compatibility, independent OTP support, experimental feature policy, deprecation stages. Then trace the named counterexample “Newest Elixir is tested only with newest OTP” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose Elixir version compatibility, and what does this project prove about it?”
  2. “What interaction between the concept ‘independent OTP support’ and the concept ‘Elixir version compatibility’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘Newest Elixir is tested only with newest OTP’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with elixir-version-compatibility-positive and newest-elixir-is-tested-only-with-newest-otp-counterexample. The first must make the concept “Elixir version compatibility” observable and establish “Every supported pair has a recorded compile and test result”; the second must reproduce “Newest Elixir is tested only with newest OTP”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for references/compatibility-and-deprecations.md
evaluate "Elixir version compatibility" through CI matrix, asdf or mise, compiler warnings
compare actual evidence with "Every supported pair has a recorded compile and test result"
run negative fixture for "Newest Elixir is tested only with newest OTP"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run mix compatibility.matrix from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Compatibility and deprecations Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
Elixir version compatibility Elixir in Action, 3rd Edition Ch. 9-10: releases and upgrades
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement elixir-version-compatibility-positive and prove “Every supported pair has a recorded compile and test result”.
  3. Topic coverage: add fixtures for independent OTP support, experimental feature policy, deprecation stages.
  4. Failure campaign: reproduce each named risk: “Newest Elixir is tested only with newest OTP”; “Experimental APIs receive stability guarantees”; “Warnings are silenced without a migration owner”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute elixir-version-compatibility-positive, independent-otp-support-positive, experimental-feature-policy-positive, deprecation-stages-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute elixir-version-compatibility-negative, independent-otp-support-negative, experimental-feature-policy-negative, deprecation-stages-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute newest-elixir-is-tested-only-with-newest-otp-counterexample, experimental-apis-receive-stability-guarantees-counterexample, warnings-are-silenced-without-a-migration-owner-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run mix compatibility.matrix through the real CI matrix, asdf or mise, compiler warnings boundary from a clean shell.
  • Mutation check: violate “Every supported pair has a recorded compile and test result” and prove the suite reports fixture elixir-version-compatibility-positive as failed.
  • Regression corpus: retain the risks “Newest Elixir is tested only with newest OTP”; “Experimental APIs receive stability guarantees”; “Warnings are silenced without a migration owner” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “Newest Elixir is tested only with newest OTP”

  • Why: This breaks one or more observable capabilities at the CI matrix, asdf or mise, compiler warnings boundary while allowing the happy path to look correct.
  • Fix: Run newest-elixir-is-tested-only-with-newest-otp-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix compatibility.matrix

Problem 2: “Experimental APIs receive stability guarantees”

  • Why: This breaks one or more observable capabilities at the CI matrix, asdf or mise, compiler warnings boundary while allowing the happy path to look correct.
  • Fix: Run experimental-apis-receive-stability-guarantees-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix compatibility.matrix

Problem 3: “Warnings are silenced without a migration owner”

  • Why: This breaks one or more observable capabilities at the CI matrix, asdf or mise, compiler warnings boundary while allowing the happy path to look correct.
  • Fix: Run warnings-are-silenced-without-a-migration-owner-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: mix compatibility.matrix

Definition of Done

  • Every supported pair has a recorded compile and test result.
  • Deprecations are classified by stage and target version.
  • Unsupported pairs fail before release construction.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 121: Operator-Ready Two-Node Release Runbook

Official topic: Releases — Elixir v1.20.2

Source file: lib/elixir/pages/mix-and-otp/releases.md

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Gleam, OCaml
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: Level 2: Micro-SaaS / Pro Tool
  • Curriculum Difficulty: Level 4: Advanced
  • Knowledge Area: Release Engineering / Operations
  • Software or Tool: mix release and release commands
  • Main Book: Elixir in Action, 3rd Edition

What you will build: Build a release, boot two named instances with separate runtime ports, verify node connectivity, operate them through remote, rpc, eval, and stop commands, and record release environment and VM argument decisions.

Why it teaches this official topic: The artifact makes self-contained releases, runtime release configuration, operating-system scripts, distributed release naming and VM arguments observable through one bounded build instead of isolated syntax examples.

Scope boundary: Teach baseline release construction and day-two operation; exclude air-gap provenance, Phoenix cloud deployment, Livebook consoles, and hot upgrades.

Core challenges you will face:

  • self-contained releases -> identify the accepted case, the counterexample, and the observable result at the mix release and release commands boundary
  • runtime release configuration -> identify the accepted case, the counterexample, and the observable result at the mix release and release commands boundary
  • operating-system scripts -> identify the accepted case, the counterexample, and the observable result at the mix release and release commands boundary
  • distributed release naming and VM arguments -> identify the accepted case, the counterexample, and the observable result at the mix release and release commands boundary

Real World Outcome

Build a release, boot two named instances with separate runtime ports, verify node connectivity, operate them through remote, rpc, eval, and stop commands, and record release environment and VM argument decisions. A reviewer must be able to run one verification command and see both the happy path and the topic-specific failure evidence without reading the implementation.

Observable capabilities:

  • A clean host boots the packaged artifact without Mix.
  • Two instances run from one artifact with runtime-only differences.
  • Remote operation and graceful stop commands have captured evidence.

Acceptance transcript:

$ MIX_ENV=prod mix release && scripts/verify_release_runbook.sh
SOURCE_TOPIC=mix-and-otp/releases.md
ARTIFACT=operator-ready-two-node-release-runbook
CHECK 01 PASS :: A clean host boots the packaged artifact without Mix
CHECK 02 PASS :: Two instances run from one artifact with runtime-only differences
CHECK 03 PASS :: Remote operation and graceful stop commands have captured evidence
FAILURE_CASES=3 EXPLICIT
RESULT PASS

The transcript is a contract, not canned output: each PASS line must come from an assertion over the finished artifact. Preserve the command, fixture versions, and result in the project evidence folder.

The Core Question You Are Answering

“What must an operator know to boot, inspect, control, and stop multiple instances of one Elixir release safely?”

Answer it using the artifact, the embedded concepts, and recorded counterexamples. Use the official page only as an optional primary-source check. A correct answer must explain both the language/runtime rule and the design consequence when the rule is ignored.

Concepts You Must Understand First

  1. self-contained releases
    • Working rule: Make “self-contained releases” an explicit rule at the mix release and release commands boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "self-contained-releases-positive", focus: "self-contained releases", mode: :positive, expect: :observable} and %{id: "self-contained-releases-negative", focus: "self-contained releases", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Releases
  2. runtime release configuration
    • Working rule: Make “runtime release configuration” an explicit rule at the mix release and release commands boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "runtime-release-configuration-positive", focus: "runtime release configuration", mode: :positive, expect: :observable} and %{id: "runtime-release-configuration-negative", focus: "runtime release configuration", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Releases
  3. operating-system scripts
    • Working rule: Make “operating-system scripts” an explicit rule at the mix release and release commands boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "operating-system-scripts-positive", focus: "operating-system scripts", mode: :positive, expect: :observable} and %{id: "operating-system-scripts-negative", focus: "operating-system scripts", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Releases
  4. distributed release naming and VM arguments
    • Working rule: Make “distributed release naming and VM arguments” an explicit rule at the mix release and release commands boundary. The project must show which input it accepts, which counterexample it rejects, and which output or lifecycle decision changes; a prose-only mention does not count.
    • Concrete fixtures: %{id: "distributed-release-naming-and-vm-arguments-positive", focus: "distributed release naming and VM arguments", mode: :positive, expect: :observable} and %{id: "distributed-release-naming-and-vm-arguments-negative", focus: "distributed release naming and VM arguments", mode: :counterexample, expect: :diagnosed}.
    • Required diagnostic: Record {:pass | :fail, fixture_id, expected, actual}. The negative fixture passes only when the verifier names the violated rule rather than merely returning an error.
    • Primary reference: Releases

Questions to Guide Your Design

  1. Public contract
    • Which inputs are accepted, rejected, or normalized?
    • Which result shapes make the official topic visible to a caller?
  2. Boundary ownership
    • Where in the artifact should the rule “self-contained releases” be enforced?
    • Which check catches the risk “Compile-time values differ between intended instances”?
  3. Evidence
    • Which deterministic fixture establishes the guarantee “A clean host boots the packaged artifact without Mix”?
    • What observable output distinguishes a real check from a mocked success?
  4. Scope control
    • What will you deliberately leave out so the project remains about the official topic “Releases”?

Thinking Exercise

Trace one input before coding

Draw the path from input to observable result. Mark where each of these concepts changes the path: self-contained releases, runtime release configuration, operating-system scripts, distributed release naming and VM arguments. Then trace the named counterexample “Compile-time values differ between intended instances” and show exactly where its diagnostic diverges from the successful path.

Questions to answer:

  • Which step establishes the invariant rather than merely checking it later?
  • What evidence would reveal an accidental widening of the accepted contract?
  • If the artifact is rerun, which outputs must be deterministic?

The Interview Questions They Will Ask

  1. “How does Elixir implement or expose self-contained releases, and what does this project prove about it?”
  2. “What interaction between the concept ‘runtime release configuration’ and the concept ‘self-contained releases’ does the project expose, and which trade-off changes?”
  3. “Which fixture demonstrates the risk ‘Compile-time values differ between intended instances’, and how does the verifier diagnose it?”
  4. “Which part of the design is guaranteed by the language or runtime, and which part is your application policy?”
  5. “How would you evolve this artifact without weakening its original contract?”

Hints in Layers

Hint 1: Reduce the fixture Start with self-contained-releases-positive and compile-time-values-differ-between-intended-instances-counterexample. The first must make the concept “self-contained releases” observable and establish “A clean host boots the packaged artifact without Mix”; the second must reproduce “Compile-time values differ between intended instances”.

Hint 2: Make outcomes explicit Represent success as {:pass, fixture_id, evidence}, an expected rejection as {:rejected, fixture_id, reason}, and a harness defect as {:error, fixture_id, exception}. Generate the acceptance transcript only from these real outcomes.

Hint 3: Shape the implementation Use this structural pseudocode:

load fixture manifest for mix-and-otp/releases.md
evaluate "self-contained releases" through mix release and release commands
compare actual evidence with "A clean host boots the packaged artifact without Mix"
run negative fixture for "Compile-time values differ between intended instances"
emit fixture id, expected value, actual value, and diagnostic

Hint 4: Verify from the outside Run MIX_ENV=prod mix release && scripts/verify_release_runbook.sh from a clean shell. Fail the check if an expected assertion, failure case, or source-topic marker is absent.

Books That Will Help

Topic Book or documentation Focus
Releases Official Elixir v1.20.2 page Optional primary-source verification; this project brief is self-contained
self-contained releases Elixir in Action, 3rd Edition Ch. 10: releases
Project discipline The Pragmatic Programmer, 20th Anniversary Edition Ch. 4-7: contracts, evidence, and change

Implementation Milestones

  1. Contract and fixture: write accepted inputs, rejected inputs, invariants, and the expected transcript.
  2. Smallest vertical slice: implement self-contained-releases-positive and prove “A clean host boots the packaged artifact without Mix”.
  3. Topic coverage: add fixtures for runtime release configuration, operating-system scripts, distributed release naming and VM arguments.
  4. Failure campaign: reproduce each named risk: “Compile-time values differ between intended instances”; “Node names and distribution modes are inconsistent”; “Eval is used as if the full application were started”.
  5. Evidence and explanation: make the verifier, documentation, and decision log reproducible from a clean checkout.

Testing Strategy

  • Unit fixtures: execute self-contained-releases-positive, runtime-release-configuration-positive, operating-system-scripts-positive, distributed-release-naming-and-vm-arguments-positive; each fixture records the input, boundary decision, and observable result for its named concept.
  • Concept counterexamples: execute self-contained-releases-negative, runtime-release-configuration-negative, operating-system-scripts-negative, distributed-release-naming-and-vm-arguments-negative; each proves that the verifier can diagnose a violated boundary for its named concept.
  • Named risk regressions: execute compile-time-values-differ-between-intended-instances-counterexample, node-names-and-distribution-modes-are-inconsistent-counterexample, eval-is-used-as-if-the-full-application-were-started-counterexample; each passes only when the named risk is detected with the expected diagnostic.
  • Contract tests: assert {status, fixture_id, expected, actual} result shapes and every CHECK nn marker in the acceptance transcript.
  • Integration test: run MIX_ENV=prod mix release && scripts/verify_release_runbook.sh through the real mix release and release commands boundary from a clean shell.
  • Mutation check: violate “A clean host boots the packaged artifact without Mix” and prove the suite reports fixture self-contained-releases-positive as failed.
  • Regression corpus: retain the risks “Compile-time values differ between intended instances”; “Node names and distribution modes are inconsistent”; “Eval is used as if the full application were started” under stable fixture IDs tied to the official topic.

Common Pitfalls and Debugging

Problem 1: “Compile-time values differ between intended instances”

  • Why: This breaks one or more observable capabilities at the mix release and release commands boundary while allowing the happy path to look correct.
  • Fix: Run compile-time-values-differ-between-intended-instances-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: MIX_ENV=prod mix release && scripts/verify_release_runbook.sh

Problem 2: “Node names and distribution modes are inconsistent”

  • Why: This breaks one or more observable capabilities at the mix release and release commands boundary while allowing the happy path to look correct.
  • Fix: Run node-names-and-distribution-modes-are-inconsistent-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: MIX_ENV=prod mix release && scripts/verify_release_runbook.sh

Problem 3: “Eval is used as if the full application were started”

  • Why: This breaks one or more observable capabilities at the mix release and release commands boundary while allowing the happy path to look correct.
  • Fix: Run eval-is-used-as-if-the-full-application-were-started-counterexample alone, compare its expected and actual evidence, then move the check to the earliest boundary that can name this violation.
  • Diagnostic evidence: Preserve the fixture ID, expected value, actual value, and the named violated rule in the regression corpus.
  • Quick test: MIX_ENV=prod mix release && scripts/verify_release_runbook.sh

Definition of Done

  • A clean host boots the packaged artifact without Mix.
  • Two instances run from one artifact with runtime-only differences.
  • Remote operation and graceful stop commands have captured evidence.
  • Every named failure case is reproducible and produces explicit evidence.
  • The acceptance transcript is generated from a clean environment.
  • The project notes link the exact Elixir v1.20.2 source page and explain the scope boundary.
  • No complete solution was copied from the documentation; the artifact demonstrates independent understanding.

Project 122: Self-Contained Air-Gapped Mix Release

Source: BEAM-P36. Build a release with the correct ERTS and assets for a clean offline host.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir/Erlang
  • Alternative Programming Languages: Erlang
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: Level 4: Open Core Infrastructure
  • Curriculum Difficulty: Level 4: Advanced
  • Knowledge Area: Release Engineering, Runtime Configuration, Deployment
  • Software or Tool: Mix releases, ERTS, tar, system service manager
  • Main Book: “Release It!”

What you will build: Build a release with the correct ERTS and assets for a clean offline host.

Why it teaches the BEAM ecosystem: It makes you prove that deployment needs no source tree or package fetch and remains reproducible.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Build a release with the correct ERTS and assets for a clean offline host.

Build AirgapProbe, a small supervised HTTP/status service plus a release/deployment harness. The service exposes build identity and a health result, owns no important state inside the release directory, and includes bounded release-task entry points for configuration preflight and readiness inspection. The harness assembles a production Mix release with ERTS, creates a tarball after assembly, emits checksum/provenance evidence, transfers it into a clean compatible target, installs it under an immutable version directory, exercises release commands, promotes it, and proves rollback with a deliberately unhealthy candidate.

The application is deliberately simple because release engineering—not HTTP framework breadth—is the learning target. Use a minimal endpoint or supervised listener already familiar to the learner. Do not add clustering, a database migration framework, hot-code upgrades, or a custom release packager to the core scope.

$ release-lab build --version 1.4.0 --target x86_64-unknown-linux-gnu
compiled mix_env=prod
assembled release=airgap_probe version=1.4.0 include_erts=true
policy cookie_fallback=removed runtime_cookie=required
packaged artifact=airgap_probe-1.4.0.tar.gz step_order=assemble,policy,tar
manifest artifact_sha256=9d6b...7e21 source_dirty=false native_assets=0

$ release-lab verify airgap_probe-1.4.0.tar.gz
checksum=ok layout=ok bundled_erts=present forbidden_secrets=0
target expected=x86_64-unknown-linux-gnu actual=x86_64-unknown-linux-gnu compatible=true

3.7.1 How to Run

Use a controlled builder matching the chosen Linux target. Transfer only the tarball, checksum, provenance manifest, and public verification material into a disposable clean VM/container. The target must have basic OS tools and declared shared libraries but no installed Erlang or Elixir packages. Keep two terminals: Terminal A runs the foreground service; Terminal B performs health and release-management commands.

3.7.2 Golden Path Demo

The learner proves four claims in order: the transferred bytes match the manifest; the artifact contains ERTS; the target has no system BEAM/Elixir commands; and the generated release wrapper can evaluate a preflight, start the application, accept a remote shell/RPC, report its PID and health, and stop cleanly. A second candidate intentionally fails its readiness gate, leaving or restoring the stable pointer to version 1.4.0.

3.7.3 Exact Clean-Host Terminal Transcript

$ command -v elixir >/dev/null || echo "elixir=absent"
elixir=absent
$ command -v mix >/dev/null || echo "mix=absent"
mix=absent
$ command -v erl >/dev/null || echo "erl=absent"
erl=absent

$ sha256sum -c airgap_probe-1.4.0.tar.gz.sha256
airgap_probe-1.4.0.tar.gz: OK
$ mkdir -p /opt/airgap_probe/releases/1.4.0
$ tar -xzf airgap_probe-1.4.0.tar.gz -C /opt/airgap_probe/releases/1.4.0
$ cd /opt/airgap_probe/releases/1.4.0
$ test -d erts-* && echo "bundled_erts=present"
bundled_erts=present

$ export PROBE_PORT=4100
$ export PROBE_DATA_DIR=/var/lib/airgap_probe
$ export PROBE_SIGNING_SECRET='<injected-by-target-secret-store>'
$ export RELEASE_NODE=airgap_probe@127.0.0.1
$ export RELEASE_DISTRIBUTION=name
$ export RELEASE_COOKIE='<injected-release-cookie>'
$ bin/airgap_probe eval 'AirgapProbe.ReleaseTasks.preflight()'
preflight=ok release=1.4.0 data_dir=writable secret=present

Terminal A:
$ bin/airgap_probe start
12:00:00.000 [info] release=airgap_probe version=1.4.0 bundled_erts=true
12:00:00.020 [info] listening=127.0.0.1:4100 readiness=ready

Terminal B:
$ bin/airgap_probe pid
4127
$ curl --silent http://127.0.0.1:4100/health
{"status":"ready","release":"1.4.0","erts":"bundled"}
$ bin/airgap_probe rpc 'AirgapProbe.ReleaseTasks.identity()'
release=airgap_probe version=1.4.0 node=airgap_probe@127.0.0.1
$ bin/airgap_probe remote
Interactive Elixir (press Ctrl+C to exit)
iex(airgap_probe@127.0.0.1)1> AirgapProbe.ReleaseTasks.identity()
release=airgap_probe version=1.4.0 node=airgap_probe@127.0.0.1
iex(airgap_probe@127.0.0.1)2> <Ctrl+C>
$ bin/airgap_probe stop
ok
$ curl --silent --max-time 1 http://127.0.0.1:4100/health || echo "service=stopped"
service=stopped

The Core Question You Are Answering

“What exactly must an Elixir release contain—and what must the target still provide—so one verified tarball can run and be operated without installing Erlang, Elixir, Mix, or application source?”

Concepts You Must Understand First

  1. OTP applications, dependency modes, supervision startup, and shutdown order.
  2. Mix compile environment versus config/runtime.exs boot configuration.
  3. ERTS, boot scripts, release directory layout, and release command wrappers.
  4. CPU architecture, OS/vendor, ABI/libc, dynamic loaders, shared libraries, NIFs, and Ports.
  5. Cryptographic digests versus signatures, provenance, and reproducibility claims.
  6. Unix foreground processes, signals, service managers, writable state, and immutable directories.
  7. Distribution node names/cookies and the execution contexts of eval, rpc, and remote.
  8. Backward-compatible configuration and data evolution needed for whole-artifact rollback.

Questions to Guide Your Design

  1. What exact target triple and OS/system-library policy does one artifact support?
  2. Which included applications are required, and which mode starts each one?
  3. How will the build prove ERTS exists before packaging?
  4. Which values are compile-time facts, runtime configuration, computed release variables, or secrets?
  5. How will remote commands receive the same node/cookie contract without leaking it into shell history?
  6. Which files must be writable, and why are none inside the version directory?
  7. What evidence distinguishes VM alive, application ready, and dependency ready?
  8. Which native libraries or executables constrain portability?
  9. What exact checks happen before extraction, before start, and before promotion?
  10. What data/configuration compatibility must remain true for the previous artifact to boot?

Thinking Exercise

Draw two deployment timelines. In the first, a correct 1.4.0 artifact is verified, started, promoted, stopped, and restarted without a system toolchain. In the second, 1.5.0 passes checksum but fails because one NIF needs an unavailable shared library. Mark every filesystem path, process, pointer value, health result, and deployment record. Explain why current must remain on 1.4.0 and why checksum success did not imply runtime compatibility.

The Interview Questions They Will Ask

  1. “What does include_erts: true include, and why does it not make a release platform-independent?”
  2. “What is the difference between assembly and the tar release step?”
  3. “Why is runtime.exs different from config.exs, and why can it not use Mix?”
  4. “How do eval, rpc, and remote differ?”
  5. “Why can a pure BEAM application still depend on target system libraries?”
  6. “How would you prove an Elixir release works on a server with no Erlang installation?”

Hints in Layers

Hint 1: Inspect before compressing — Treat the uncompressed release tree as the first artifact. Verify ERTS, boot/config files, applications, priv, and forbidden paths.

Hint 2: Make target identity an input — Refuse to build a generically named “Linux artifact.” Name and record the target contract.

Hint 3: Test the transferred bytes — Copy only tar/manifest into the clean host and move the original _build tree out of reach.

Hint 4: Keep eval honest — Preflight tasks must explicitly start only what they need and must not assume the service node exists.

Hint 5: Fail before switching — Extraction and candidate boot happen under a version path; the stable pointer changes only after health.

Hint 6: Debug native failures from the loader outward — Inspect executable format, target triple, NIF/Port location, dynamic dependencies, permissions, and only then application code.

Books That Will Help

Topic Book Precise reading
Deployment pipelines Continuous Delivery — Jez Humble and David Farley Chapter 5 “Anatomy of the Deployment Pipeline” and Chapter 10 “Deploying and Releasing Applications”
Production process behavior Release It!, 2nd Edition — Michael T. Nygard “Processes on Machines” and stability-pattern sections; connect to health and restart boundaries
Linux processes and shared libraries How Linux Works, 3rd Edition — Brian Ward Chapters on process management, shared libraries, and system startup
Shell artifact operations The Linux Command Line, 2nd Edition — William E. Shotts Chapters on archives, checksums, permissions, environment, and process control

Implementation Milestones

Phase 1: Release Anatomy and Runtime Contract (5-7 hours)

  • Build the supervised probe service and distinguish liveness/readiness.
  • Define required runtime values and safe failure diagnostics.
  • Initialize release templates and document RELEASE_* policy.
  • Assemble with ERTS and inspect the release tree.

Checkpoint: The uncompressed release starts through its wrapper, reports build identity, rejects missing runtime values, and contains no secret fixture.

Phase 2: Tar, Integrity, and Target Evidence (5-8 hours)

  • Add :tar after :assemble.
  • Stream artifact checksum and write sanitized provenance.
  • Inventory release files, OTP applications, NIF/shared objects, Ports, and executable assets.
  • Define target preflight and artifact naming.

Checkpoint: A verifier rejects altered bytes, wrong release identity, missing ERTS, wrong target identity, and forbidden files.

Phase 3: Clean-Host Operations (6-9 hours)

  • Provision matching clean target without Erlang/Elixir/Mix.
  • Verify, extract, inject runtime values, and execute preflight.
  • Exercise start, PID, health, RPC, remote shell, stop, signals, logs, and writable paths.
  • Capture the deterministic terminal transcript.

Checkpoint: The exact transferred tarball completes the transcript while all three system toolchain commands remain absent.

Phase 4: Immutable Promotion and Rollback (6-10 hours)

  • Add version directories plus current/previous pointers.
  • Implement bounded readiness and promotion records.
  • Inject wrong-ABI/native-library and unhealthy-candidate failures.
  • Roll back and prove service/data compatibility.
  • Optionally feed the artifact into consolidated Project 128’s BEAM artifact and reproducibility auditor.

Checkpoint: A failed 1.5.0 candidate cannot corrupt or replace healthy 1.4.0, and the rollback record explains every decision.

Testing Strategy

6.1 Test Categories

Category Purpose Examples
Runtime Contract Prove boot-time parsing and secrecy required/malformed vars, no secret echo
Release Layout Verify assembled target system ERTS, boot files, apps, priv, executable wrapper
Step Ordering Verify package pipeline tar cannot be accepted without completed assembly evidence
Artifact Integrity Detect transfer/change valid, truncated, bit-flipped, wrong manifest
Compatibility Enforce target boundary wrong architecture, OS, ABI, missing library
Native Boundary Exercise NIF/Port inventory correct asset, wrong ELF architecture, missing dependency
Clean Target Prove no system runtime absent elixir/mix/erl, bundled service boots
Command Semantics Test operations eval before start; pid/rpc/remote/stop after start
Process Lifecycle Verify signals and external supervision SIGTERM, graceful shutdown, restart limits
Deployment Verify state transitions verify, extract, preflight, health, promote
Rollback Preserve last known-good unhealthy candidate, pointer restoration, data readability
Provenance Validate evidence revision, lock/toolchain/target, sanitized environment

6.2 Critical Test Cases

  1. Release tree contains an erts-* directory and runs when system erl is absent.
  2. Tar artifact is produced only from a successful assembled release and contains one coherent top-level layout.
  3. Generated cookie fallback is absent from the tar, a missing injected cookie fails closed, and the injected cookie enables service and remote commands.
  4. Missing runtime secret fails boot with variable name but not value or surrounding environment.
  5. A value changed only at target boot changes behavior without rebuilding the tarball.
  6. eval preflight succeeds before the service starts and does not claim the application is running.
  7. pid, rpc, and remote fail with a classified identity/cookie diagnostic when policy is intentionally mismatched.
  8. Correct node/cookie settings make PID, RPC, remote shell, and stop work against the running release.
  9. Wrong target triple is rejected before promotion.
  10. Missing system library or wrong-architecture NIF is detected by preflight/smoke testing.
  11. Bit-flipped tarball fails digest verification before extraction.
  12. Release source, Mix cache, dependency cache, and build tree are unavailable on clean-host test.
  13. SIGTERM produces orderly application shutdown and bounded exit.
  14. Candidate health failure leaves current unchanged.
  15. Post-promotion failure switches to previous, starts it, and proves shared data remains readable.
  16. Provenance contains no cookie, secret, database URL, or complete unfiltered environment dump.

6.3 Test Data

Maintain two valid versions, one deliberately unhealthy candidate, one truncated archive, one wrong-target manifest, one missing-library fixture, one malformed runtime configuration set, and one small shared-data format explicitly readable by both valid versions. Use deterministic release identity and health outputs while allowing timestamps/PIDs to be normalized only in assertions where they are inherently variable.

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Problem Why it happens Fix Quick test
Target says executable not found although file exists Wrong loader, ABI, architecture, or shared library Compare target triple and loader dependencies Inspect executable format and dependency resolution
Release works only on build machine Tested _build tree with installed toolchain Transfer only tar/manifest to clean target Hide source/build paths and remove toolchain from target
Secret appears in archive Read or generated during build Move to runtime.exs/provider and rebuild from clean tree Scan archive and manifest for secret canary
runtime.exs crashes on Mix call Mix does not exist in release runtime Use Config/System/application APIs only Boot on clean target
Remote shell cannot connect Node name, distribution, cookie, hostname, or ports differ Publish one remote-command environment contract Compare service and helper identities safely
eval cannot call application service Applications are not started in eval VM Explicitly start required apps or keep task pure Run preflight with service stopped
Tarball misses files Ad hoc archive or undeclared priv/overlay Use official release tar step and layout allow-list Compare assembled and tar inventories
Health passes too early PID or socket-open used as readiness Gate on application/dependency invariants Delay dependency and observe readiness
Rollback old code fails Candidate changed shared data incompatibly Expand-contract/versioned data or restore plan Run old release against post-candidate fixture
Release directory changes over time Logs/data/config written beneath current root Externalize writable state Snapshot file hashes before/after run

7.2 Debugging Strategies

  • Start with artifact identity: filename, digest, release name/version, target, and selected RELEASE_VSN.
  • Inspect the extracted erts-*, lib, releases, wrapper permissions, and start_erl.data before application logs.
  • Separate wrapper/environment failures, VM loader failures, boot-script failures, runtime configuration failures, application startup failures, and readiness failures.
  • For native load errors, inspect file architecture and dynamic dependencies on both builder and target; do not repeatedly change Elixir code first.
  • Use safe release identity/RPC tasks rather than printing the full environment or cookie.
  • Run eval preflight with service stopped, then run rpc inspection with service running to expose context confusion.
  • Compare immutable release-tree hashes before and after execution to locate accidental writes.
  • Preserve failed-candidate logs and deployment records without leaving the failed process running.

7.3 Performance Traps

  • Recompressing already compressed large assets without measuring build time or size
  • Including unused applications, debug/source artifacts, caches, or fixtures
  • Hashing by reading the whole tar into memory instead of streaming
  • Running expensive external checks during every health probe
  • Starting remote helper VMs in high-frequency monitoring loops
  • Retaining unlimited versions or logs beneath release storage
  • Rebuilding on every target rather than promoting one target-specific artifact

Definition of Done

  • Release definition explicitly includes ERTS and places :tar after :assemble.
  • Assembled tree contains expected ERTS, boot, application, configuration, and priv artifacts.
  • Versioned tarball, SHA-256, and sanitized provenance are produced together.
  • Generated cookie fallback is absent from the tar and release operations require target-injected RELEASE_COOKIE.
  • Build and target architecture, OS/vendor, ABI, and system-library policy are declared and checked.
  • NIFs, Ports, executables, and dynamic dependencies are inventoried or explicitly reported absent.
  • Required target values are loaded by runtime.exs; no production secret is embedded in artifact bytes.
  • RELEASE_* node, cookie, version, temp, mode, and distribution policy are documented.
  • Clean compatible target proves elixir, mix, and erl absent before running the service.
  • Exact transferred tarball completes eval, start, pid, health, rpc, remote, and stop evidence.
  • Foreground service responds correctly to shutdown and external supervision.
  • Installation uses immutable version directories and external writable data/log/config paths.
  • Candidate promotion requires bounded readiness, not only PID existence.
  • Deliberately unhealthy candidate leaves or restores the last known-good release.
  • Rollback test includes explicit shared-data/configuration compatibility evidence.
  • Scope documentation distinguishes whole-artifact deployment from P9 hot upgrade and P32 artifact auditing.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • deployment needs no source tree or package fetch and remains reproducible.

Project 123: Distributed Service Directory and Fleet Router

Source: BEAM-P37. Advertise capabilities through :pg, route to monitored pids, and recover from stale membership.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir/Erlang
  • Alternative Programming Languages: Erlang, Gleam with Erlang interop
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: Level 4: Open Core Infrastructure
  • Curriculum Difficulty: Level 4: Advanced
  • Knowledge Area: Process Registration, Discovery, Distributed Routing
  • Software or Tool: Registry, DynamicSupervisor, :pg, :global, Node monitors
  • Main Book: “Designing for Scalability with Erlang/OTP”

What you will build: Advertise capabilities through :pg, route to monitored pids, and recover from stale membership.

Why it teaches the BEAM ecosystem: It makes you prove that churn cannot create duplicate effects or poison discovery.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Advertise capabilities through :pg, route to monitored pids, and recover from stale membership.

Build a three-node worker-fleet lab and operator CLI. Each node owns a local Registry and DynamicSupervisor. Workers represent real media operations—thumbnail generation, metadata extraction, and document preview—and advertise protocol-versioned capabilities through :pg. A router discovers a compatible current worker, monitors it, and submits a request with a stable identity. A topology monitor records nodeup/nodedown; failure commands crash workers, disconnect nodes, reconnect them, and compare membership views. A separate experiment registers one disposable lab coordinator through :global and exposes its full-connectivity assumptions.

$ fleetctl nodes
NODE                       STATUS   SINCE                 SOURCE
fleet-a@127.0.0.1          up       2026-07-15T16:00:00Z  local
fleet-b@127.0.0.1          up       2026-07-15T16:00:02Z  static_seed
fleet-c@127.0.0.1          up       2026-07-15T16:00:03Z  static_seed

$ fleetctl services thumbnail --version 2
OBSERVED_FROM=fleet-a@127.0.0.1 CONSISTENCY=strong_eventual MEMBERS=3
worker=thumb-a1 node=fleet-a@127.0.0.1 pid=#PID<...> generation=g7 state=ready
worker=thumb-b1 node=fleet-b@127.0.0.1 pid=#PID<...> generation=g3 state=ready
worker=thumb-c1 node=fleet-c@127.0.0.1 pid=#PID<...> generation=g9 state=ready

$ fleetctl route thumbnail job-42 --version 2
request=job-42/thumbnail-v2 selected=thumb-b1 node=fleet-b@127.0.0.1 generation=g3
result=ok artifact=artifacts/job-42-thumb-v2.jpg duration_ms=84 deduplicated=false

The finished project is a repeatable service-discovery and routing lab that an engineer can operate from one terminal. It displays both node connectivity and worker membership, routes real fixture transformations to remote worker processes, and proves that a logical worker survives as an identity while its PID does not. Operators can inject process and network failures, see exactly which mechanism reports each failure, and verify that healthy workers remain available. The project produces a runbook, event timeline, and capability matrix suitable for reviewing a real distributed Elixir service.

3.7.1 How to Run

  1. Build the lab release and create three node-specific runtime configurations.
  2. Start the nodes on loopback using stable long or short names consistently.
  3. Verify the topology command before starting workers.
  4. Seed deterministic thumbnail, metadata, and preview workers.
  5. Run route and failure-drill commands from the operator CLI.
  6. For non-loopback use, enable TLS distribution and the restricted network profile first.

3.7.2 Golden Path Demo

Start all three nodes, observe three version-two thumbnail workers, route three fixture jobs across different nodes, crash the selected worker, observe its old PID disappear, route through another worker, verify the restarted logical worker has a new PID and generation, disconnect one node, continue routing on two nodes, reconnect, and wait until all per-node group views converge.

3.7.3 Exact Terminal Transcript

$ fleetctl drill kill-worker thumb-b1
event=worker_exit worker=thumb-b1 old_generation=g3 reason=injected_failure
event=worker_started worker=thumb-b1 new_generation=g4 pid_changed=true
event=group_join capability=thumbnail/v2 node=fleet-b@127.0.0.1

$ fleetctl drill disconnect-node fleet-c@127.0.0.1
event=nodedown node=fleet-c@127.0.0.1 reason=disconnect
routes_remaining capability=thumbnail/v2 count=2

$ fleetctl route thumbnail job-43 --version 2
request=job-43/thumbnail-v2 selected=thumb-a1 node=fleet-a@127.0.0.1 generation=g7
result=ok artifact=artifacts/job-43-thumb-v2.jpg duration_ms=71

$ fleetctl drill reconnect-node fleet-c@127.0.0.1 --wait-converged
event=nodeup node=fleet-c@127.0.0.1
event=membership_converged capability=thumbnail/v2 observers=3 members=3

The Core Question You Are Answering

“How can a caller find a compatible current process anywhere in a BEAM cluster without pretending that names, PIDs, membership views, or network connections are permanent?”

Concepts You Must Understand First

  1. Processes, mailboxes, PIDs, links, and monitors.
  2. GenServer client/server APIs and supported name forms.
  3. Supervisor child specifications, restart values, and DynamicSupervisor.
  4. Registry unique/duplicate keys, entry ownership, metadata, and :via.
  5. Distributed node names, connections, remote PIDs, and node monitoring.
  6. :pg membership and strong eventual consistency.
  7. :global full-connectivity assumptions and non-durable name semantics.
  8. Idempotency and uncertain outcomes in remote work.

Questions to Guide Your Design

  1. Which identities are fixed atoms, dynamic terms, PIDs, or durable strings?
  2. Who owns starting a worker, and how do two simultaneous start requests resolve one winner?
  3. What event makes a warming worker eligible to join its capability group?
  4. How does the router distinguish no compatible member from a disconnected node?
  5. What state is authoritative, and what state is only one node’s current observation?
  6. Which outcomes permit safe retry, and which remain uncertain?
  7. How will you prove a restarted worker has a new process incarnation?
  8. What should happen when :pg views differ during a partition?
  9. Why is :global excluded from the ordinary fleet-routing path?
  10. Which runtime secrets and identifiers must be redacted from logs?

Thinking Exercise

Trace one job through simultaneous worker death and node loss

Draw a timeline containing Registry lookup, :pg membership read, monitor installation, request send, worker acknowledgement, node disconnection, retry decision, supervisor restart, re-registration, group rejoin, and rediscovery.

Questions to answer:

  • At which points can the selected PID become stale?
  • Which observer can know whether work completed?
  • Would retry duplicate an external effect?
  • Which identity stays stable after restart?
  • How would the trace differ if only the worker crashed while the node stayed connected?

The Interview Questions They Will Ask

  1. “What is the difference between node discovery, process registration, and service discovery?”
  2. “When would you use an atom name, Registry, :pg, or :global?”
  3. “Why does Registry lookup not eliminate stale-PID races?”
  4. “How do DynamicSupervisor and Registry divide responsibility?”
  5. “What does strong eventual consistency mean for :pg membership?”
  6. “Why is :global not automatically a consensus-backed leader election?”

Hints in Layers

Hint 1: Make identity visible

Print logical ID, node, PID, and generation together. If your CLI cannot show which part changed, your tests cannot prove rediscovery.

Hint 2: Keep the mechanisms separate

Build local supervision and Registry lookup first. Add node monitoring next. Add :pg only after local restarts are correct. Keep the :global experiment outside routing.

Hint 3: Query late

Resolve group membership near dispatch time. A long-lived PID cache creates another invalidation subsystem before the basic directory is correct.

Hint 4: Design the failure result before retry

Give every routed operation a stable request ID and classify process death, node loss, and timeout. Do not add automatic retry until duplicate effects are controlled.

Hint 5: Observe convergence from every node

During a partition drill, record each node’s membership view and observation timestamp. The differences are the lesson, not a test harness inconvenience.

Books That Will Help

Topic Book Chapters / Focus
Processes and OTP Elixir in Action by Saša Jurić Processes, generic server processes, fault tolerance, distributed systems
Supervision architecture Designing for Scalability with Erlang/OTP by Francesco Cesarini and Steve Vinoski Supervision, process architecture, distribution, operational tradeoffs
Distributed failure Designing Data-Intensive Applications by Martin Kleppmann Replication, partitions, consistency, failure reasoning
Erlang concurrency Programming Erlang by Joe Armstrong Processes, registered names, distributed programming, OTP

Implementation Milestones

Phase 1: Local Identity and Lifecycle (6-8 hours)

  • Define worker logical IDs, capabilities, generation tokens, and client APIs.
  • Start fixed infrastructure, local Registry, and DynamicSupervisor.
  • Implement unique :via worker names and a duplicate Registry comparison.
  • Prove worker crash, name cleanup, restart, and new generation.
  • Add duplicate-start race tests and dynamic-atom safety tests.

Phase 2: Node Formation and Remote Messaging (5-7 hours)

  • Start three named loopback nodes from deterministic configuration.
  • Implement candidate-node and topology-monitor boundaries.
  • Record nodeup/nodedown events and connection reasons.
  • Send a fixture request to a remote PID and {name, node} reference.
  • Document code-version and security assumptions.

Phase 3: Distributed Capability Directory (7-10 hours)

  • Define versioned :pg group names and readiness rules.
  • Join workers to capability groups and render per-node views.
  • Implement deterministic route selection, monitors, deadlines, and outcome classification.
  • Add stable request identity and simulated work deduplication.
  • Prove local preference and remote fallback without permanent PID caching.

Phase 4: Failure and Convergence Drills (6-9 hours)

  • Crash a selected worker before and after acknowledgement.
  • Disconnect and reconnect a node during routed work.
  • Capture divergent :pg views and wait for convergence.
  • Verify old PIDs are never reported as revived.
  • Produce event timelines, telemetry assertions, and operator runbook.

Phase 5: Global Comparison and Hardening (4-8 hours)

  • Register one disposable lab coordinator through :global.
  • Exercise duplicate registration, death cleanup, and partition behavior.
  • Publish a mechanism capability matrix and explain why routing uses :pg.
  • Add TLS distribution profile, redaction checks, and restricted network guidance.
  • Measure directory lookup and routing overhead before proposing caches.

Testing Strategy

6.1 Test Categories

Category Goal Representative Evidence
Pure unit tests Validate group keys, filtering, ordering, and retry classification deterministic inputs/outputs
Local registration tests Prove fixed names, unique/duplicate Registry, :via, and cleanup process lifecycle assertions
Start-race tests Prove one logical local owner under concurrent creation barrier-controlled callers
Supervision tests Prove new PID/generation and correct restart intensity injected worker exits
Multi-node integration Prove remote PID and {name, node} communication three loopback nodes
Membership tests Prove :pg join, leave, stale view tolerance, and convergence per-node snapshots
Network failure tests Prove nodedown invalidation and reconnect rediscovery controlled disconnect
Delivery tests Prove deduplication and uncertain-timeout classification lost reply fixtures
Global comparison tests Document singleton registration/death/conflict behavior isolated experiment
Security tests Reject unsafe IDs and verify secret redaction adversarial identifiers/log scan
Performance tests Measure lookup and route selection under growing membership latency percentiles and scheduler load

6.2 Critical Test Cases

  1. A fixed infrastructure atom name resolves only on its local node.
  2. A dynamic worker string registers through Registry without increasing atoms based on input.
  3. A unique key rejects a second live owner; the losing start resolves the existing worker.
  4. A duplicate registry returns all local subscribers for one capability key.
  5. Killing a worker removes the old entry and produces a new PID and generation after restart.
  6. A lookup followed by immediate death produces a classified process-down outcome, not a crash in the router.
  7. A remote request succeeds through a PID and through {registered_name, node} for the fixed test service.
  8. All three nodes eventually observe the same stable :pg membership after concurrent joins.
  9. A version-one worker is never selected for a version-two request.
  10. Disconnecting the selected node invalidates it and leaves other compatible workers routable.
  11. Reconnection discovers new process incarnations instead of reusing stored PIDs.
  12. Per-node membership snapshots may differ during a partition and converge afterward.
  13. A request completed before reply loss returns the deduplicated prior result on safe retry.
  14. An operation without deduplication returns uncertain outcome rather than automatic duplicate dispatch.
  15. :global duplicate registration and process death behave as documented in the full-mesh lab.
  16. The non-loopback profile refuses to start without the required secure-distribution configuration.

6.3 Test Data

Use deterministic node names, worker IDs, capability versions, and small immutable media fixtures. Include duplicate worker IDs, hostile Unicode and atom-like IDs, unsupported versions, slow work, crash-before-ack, crash-after-ack, lost reply, node disconnect, reconnect with new generation, concurrent group joins, and partial-connectivity timelines. Store expected artifact digests so a deduplicated retry can prove it returned the original result.

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Problem 1: “The worker restarted, but calls still target the dead PID.”

  • Why: A caller cached the concrete PID instead of resolving the logical identity again.
  • Fix: Rediscover near dispatch and invalidate route snapshots through process/node monitors and expiry.
  • Quick test: Crash a worker and assert the next route reports the same logical ID with different PID and generation.

Problem 2: “Registry works locally but no remote node can see it.”

  • Why: Elixir Registry is local; connecting nodes does not distribute its entries.
  • Fix: Use Registry for local identity and :pg for distributed capability groups.
  • Quick test: Compare local Registry output with per-node :pg membership.

Problem 3: “Two callers started duplicate work for one worker ID.”

  • Why: Both observed a missing registration and performed side effects before ownership was resolved.
  • Fix: Make unique registration/start resolution precede irreversible work and return the existing winner to the loser.
  • Quick test: Release two barrier-controlled start calls simultaneously and count live owners and effects.

Problem 4: “All nodes are connected, but one service is missing.”

  • Why: Node readiness was confused with process capability readiness, or group propagation is still converging.
  • Fix: Report node and group layers separately; join only after worker readiness and allow bounded convergence.
  • Quick test: Delay one worker’s group join while keeping its node connected.

Problem 5: “A timeout caused the same job to run twice.”

  • Why: The remote side completed, but the reply was lost and the router retried without stable identity.
  • Fix: Use request deduplication or return uncertain outcome for non-idempotent work.
  • Quick test: Drop the first successful reply, retry, and compare artifact digest and execution count.

Problem 6: “The partition test produces different member lists.”

  • Why: :pg views are strongly eventually consistent and visibility depends on direct connectivity.
  • Fix: Label each observed view and test convergence after connectivity stabilizes rather than demanding instant equality.
  • Quick test: Capture all observers before, during, and after the partition.

Problem 7: “The global coordinator is being treated as durable leadership.”

  • Why: Name uniqueness was mistaken for consensus, persistence, or exactly-once ownership.
  • Fix: Isolate the comparison, document full-mesh assumptions, and keep durable decisions in a suitable durable coordination mechanism.
  • Quick test: Kill the coordinator and show its name cleanup does not restore its internal state.

7.2 Debugging Strategies

  1. Print node, logical ID, PID, generation, observer, and timestamp on every diagnostic line.
  2. Inspect local Registry and :pg separately before debugging the router.
  3. Subscribe to node events with reasons and correlate them with process :DOWN messages.
  4. Trace one request ID end-to-end instead of relying on aggregate counters.
  5. Compare membership from every node when topology is suspect.
  6. Check node name domains, DNS/hosts mapping, distribution ports, TLS certificates, and clock-independent deadlines.
  7. Use controlled failure hooks rather than random kills so ordering is reproducible.
  8. Verify code and protocol version compatibility before attributing failures to distribution.

7.3 Performance Traps

  • One unpartitioned local Registry may become a hotspot under extreme local churn; measure and configure partitions deliberately.
  • Sorting every huge group on every request costs O(M log M); keep the first implementation correct, then benchmark selection alternatives.
  • Broad :pg groups create propagation traffic and large membership reads; use meaningful capability scopes.
  • High-cardinality PID, worker ID, or node labels can overwhelm metrics; keep them in traces/logs, not metric dimensions.
  • Aggressive node reconnect loops amplify outages; use bounded backoff and topology-aware policy.
  • Monitoring every member permanently duplicates discovery state; monitor selected work or build a deliberate cache subsystem.
  • Synchronous global-name operations in a large or unstable topology can create latency and operational coupling.

Definition of Done

  • Three nodes form the repeatable loopback cluster and expose nodeup/nodedown state.
  • Fixed infrastructure uses bounded local names; dynamic worker IDs never become atoms.
  • Unique and duplicate Registry semantics are demonstrated and tested.
  • Workers are started under DynamicSupervisor and resolved through :via Registry names.
  • Concurrent creation yields one local owner per logical worker key.
  • Worker crash produces automatic cleanup, restart, re-registration, new PID, and new generation.
  • Remote PID and {name, node} messaging are observable in the golden path.
  • Versioned :pg groups discover compatible workers across three nodes.
  • Directory output identifies observer, timestamp, node, PID, generation, and consistency model.
  • Router handles stale PID, process-down, node-down, incompatible capability, and timeout separately.
  • Retry is enabled only for idempotent or deduplicated work.
  • Node disconnect leaves surviving members routable; reconnect rediscovery uses new PIDs.
  • Partition drill captures divergent views and verified convergence.
  • Controlled :global comparison documents duplicate registration, death, and topology assumptions.
  • TLS distribution and restricted-network requirements are documented and tested for non-loopback use.
  • No Registry, :pg, :global, PID, or supervisor state is described as durable business truth.
  • Runbook and mechanism capability matrix allow another engineer to repeat every drill.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • churn cannot create duplicate effects or poison discovery.

Project 124: Safe Attached-Runtime Livebook Console

Source: LIVE-P11. Attach a read-only notebook console to a disposable remote runtime with bounded diagnostics.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang; Gleam on a disposable BEAM target
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: Level 4: Open Core Infrastructure
  • Curriculum Difficulty: Level 4: Advanced
  • Knowledge Area: Distributed Elixir, live diagnostics, trust boundaries
  • Software or Tool: Livebook runtimes, Remote Execution Smart Cell, disposable Phoenix node
  • Main Book: Elixir in Action, Third Edition

What you will build: Attach a read-only notebook console to a disposable remote runtime with bounded diagnostics.

Why it teaches the BEAM ecosystem: It makes you prove that operators inspect processes without mutation or exfiltration authority.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Attach a read-only notebook console to a disposable remote runtime with bounded diagnostics.

Create a training repository with:

  • one disposable local Phoenix or OTP application started as a named node with a unique training cookie;
  • synthetic workers, queues, supervised restarts, and safe mock metrics;
  • a Livebook console with three explicitly separated demonstrations: standalone, Remote Execution, and attached;
  • an allowlisted catalog containing process summary, queue-depth summary, application versions, scheduler summary, and one training-worker health check;
  • timeout, row, byte, concurrency, and refresh bounds;
  • a redacted transcript showing evaluator node, target node alias, diagnostic identifier, start/end time, result count, bytes, and outcome;
  • failure drills for disconnect, timeout, oversized result, stale process, and target restart.

No operation may mutate target application state, start/stop target children, execute arbitrary strings, inspect secrets, read user data, or connect to any non-disposable node.

TRIAGE CONSOLE — DISPOSABLE TARGET ONLY
Mode: Remote Execution from standalone runtime
Evaluator: notebook-training-node
Target alias: disposable-app-A
Target marker: LIVEBOOK_TRAINING_TARGET=true [VERIFIED]

Diagnostic: queue_depths.v1
Timeout: 2,000 ms
Result limit: 100 rows / 256 KiB
Refresh limit: once per 5 seconds
Mutation capability exposed by UI: NONE
RESULT
Observed at: 2026-07-15T18:42:03Z
Rows: 6
Encoded bytes: 1,284
Target execution: 7 ms
Round trip: 11 ms
Truncated: false
Status: PASS

Start the disposable target and open the console in standalone mode. The comparison view shows that local Kino and analytical dependencies belong to the notebook node. Use Remote Execution to retrieve one synthetic queue summary and render a local table. Switch a copy of the notebook to attached mode; node identity proves evaluation now occurs inside the target and the package setup path is unavailable.

Then perform controlled failure drills:

SAFETY DRILL SUMMARY
non-training target marker ........ REFUSED
target disconnect ................. BOUNDED FAILURE
diagnostic timeout ................ TASK TERMINATED / UI RESPONSIVE
oversized result .................. TRUNCATED AT SOURCE
stale PID after restart ........... RESELECTED BY TRAINING NAME
cookie value in evidence scan ..... NOT FOUND
production host patterns scan ..... NOT FOUND

The final notebook ends with a comparison and recommendation: use standalone plus a narrow read-only API for repeatable production diagnostics; use this attached-mode knowledge only to understand risk.

The Core Question You Are Answering

“Where does notebook code execute, and how does that location change dependencies, authority, risk, and failure?”

Answer with observed evaluator node, dependency location, process visibility, and failure behavior—not a diagram alone.

Concepts You Must Understand First

  1. Livebook runtime types
    • What processes evaluate cells in standalone and attached modes?
    • Primary reference: Livebook runtimes
  2. Remote execution use case
  3. Distributed Elixir
    • What do node naming, connection, cookies, and remote process semantics imply?
    • Primary reference: Elixir Node
  4. Process observation
    • Which process information is safe and bounded to request?
    • Primary reference: Elixir Process
  5. Task failure and deadlines
    • How are timeout, exit, and cleanup represented?
    • Primary reference: Elixir Task
  6. Operational stability
    • Why can observability overload the observed system?
    • Book reference: Release It!, 2nd ed. — stability and operations chapters

Questions to Guide Your Design

  1. What unforgeable-enough local evidence distinguishes the disposable target from any other node in this lab?
  2. Which five diagnostics are necessary, and why is every other operation excluded?
  3. Where are row, byte, time, concurrency, and frequency bounds enforced?
  4. Which data is summarized on target instead of copied to Livebook?
  5. What happens when the target restarts between process selection and observation?
  6. How does the notebook remove topology and cookie data before save?
  7. What production requirement would justify building an API instead?

Thinking Exercise

Create three trust maps—standalone, Remote Execution, and attached. For each, fill in:

Question Answer to determine
Where is the evaluator? notebook node or target node
Where are Kino dependencies? notebook or target code path
What credential enables access? none, API credential, or distribution secret
Which processes can code see? notebook only or target process space
What failure affects the target? bounded request, remote execution, or evaluator work inside target
What output crosses the boundary? none, bounded summary, or direct cell result

Then write the safest architecture for a repeated production diagnostic. It should normally be a narrow API, not attachment.

The Interview Questions They Will Ask

  1. “How does Livebook attached runtime differ from Remote Execution?”
  2. “Why is an Erlang cookie a sensitive shared secret rather than user identity?”
  3. “Why can attached mode not freely use Mix.install?”
  4. “How can process inspection affect scheduler and memory behavior?”
  5. “How do you design a read-only diagnostic catalog?”
  6. “When should a diagnostic move behind an HTTP or application API?”

Hints in Layers

Hint 1: Make the target disposable by construction

Use loopback, synthetic data, an explicit marker, a unique cookie, and a separate repository/configuration.

Hint 2: Prove location before inspecting anything

Render evaluator alias, target alias, and dependency availability at the top of every mode.

Hint 3: Summarize remotely

Filter and cap on the target. Do not transfer all PIDs or states and then decide what to show.

Hint 4: Fail closed

If the training marker, allowlist, deadline, or result cap cannot be verified, refuse the operation.

Books That Will Help

Topic Book Chapter
Distributed Elixir Elixir in Action, 3rd ed. Distribution chapter
Supervision and process design Designing Elixir Systems with OTP Chapters 3–8
Operational safety Release It!, 2nd ed. Stability patterns and operations chapters
Access boundaries Foundations of Information Security Authentication and access-control chapters

Implementation Milestones

Phase 1: Disposable Target and Catalog (6–9 hours)

Goals: create synthetic workload, training marker, diagnostic catalog, and target-side bounds.

Tasks:

  1. Seed supervised synthetic workers and queues.
  2. Define five read-only diagnostic result schemas.
  3. Add target-side timeout, row, and byte policies.
  4. Test high process count, stale process, and restart fixtures.

Checkpoint: catalog tests prove bounded outputs without Livebook.

Phase 2: Runtime Comparison (7–10 hours)

Goals: observe evaluator and dependency location in all three modes.

Tasks:

  1. Create the standalone comparison notebook.
  2. Add one Remote Execution diagnostic and local Kino rendering.
  3. Create a separate attached-runtime notebook copy.
  4. Record node identity, code availability, and failure behavior.

Checkpoint: evidence clearly distinguishes all modes and contains no raw cookie.

Phase 3: Failure, Redaction, and Recommendation (7–11 hours)

Goals: harden failure handling and document production judgment.

Tasks:

  1. Test disconnect, timeout, target restart, oversized result, and wrong marker.
  2. Scan saved notebook and exports for canary secrets/topology.
  3. Verify task cleanup and UI responsiveness.
  4. Write the narrow-API production migration recommendation.

Checkpoint: all safety drills pass and no non-disposable target is contacted.

Testing Strategy

6.1 Test Categories

Category Purpose Examples
Catalog unit Prove operations are read-only and bounded large process set, sorted top-K, byte cap
Environment gate Prevent wrong target missing marker, wrong alias, non-loopback target
Mode evidence Prove evaluator/dependency location node identity, code availability
Failure Bound operational faults disconnect, timeout, target exit, stale PID
Redaction Protect saved evidence cookie canary, hostname canary, process metadata
Cleanup Avoid leaked listeners/tasks repeated run, reconnect, target shutdown

6.2 Critical Test Cases

  1. Wrong target marker: console refuses before any diagnostic.
  2. Unsupported diagnostic: arbitrary identifier is rejected locally and remotely.
  3. Parameter abuse: excessive limits are reduced to server policy or rejected.
  4. Slow diagnostic: deadline returns timeout and terminates waiting work.
  5. Oversized result: target returns bounded/truncated summary; full data never crosses.
  6. Target disconnect: UI remains responsive and reports connection failure distinctly.
  7. Target restart: old PID is never reused as logical identity; current synthetic name is resolved again.
  8. Evidence scan: seeded cookie and topology canaries are absent from .livemd, logs, and export.
  9. Attached dependency attempt: limitation is shown as expected behavior, not “fixed” by changing target packages.
  10. No production contact: network evidence contains only documented loopback/disposable nodes.

6.3 Test Data

Synthetic target fixture:
  50 normal workers
  5 workers with growing bounded training queues
  1 deliberately slow diagnostic source
  1 restartable worker with logical training name
  1 oversized synthetic metadata source

Canaries:
  cookie-like secret value
  fake internal hostname
  fake customer identifier

Expected:
  bounded summaries only; all canaries absent from saved evidence

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Pitfall Symptom Solution
Attached notebook runs setup packages Dependency setup fails or risks target change Keep attached notebook dependency-free; render rich UI locally through remote mode
Arbitrary MFA accepted “Read-only” tool can call mutating functions Fixed catalog with no user-selected module/function
Full process list transferred Browser freezes and target allocates heavily Aggregate and cap at target
Cookie logged during debugging Secret appears in cell output or Git Use secret configuration and canary scans; never inspect raw value
Old PID retained Diagnostic observes wrong/dead incarnation Resolve current logical training name on each request
Reconnect tasks leak Repeated timeout messages or duplicated output Supervised deadlines and idempotent cleanup

7.2 Debugging Strategies

  • Start with identity: verify evaluator and target aliases before any result.
  • Test target module directly: distinguish catalog bugs from distribution bugs.
  • Observe encoded bytes: row count alone may hide large payloads.
  • Force each failure separately: disconnect, timeout, and target crash are different states.
  • Inspect current process references: stale PIDs often explain inconsistent results.
  • Scan saved evidence last: runtime redaction is incomplete until .livemd and exports are checked.

7.3 Performance Traps

Avoid repeated global process enumeration, copying process dictionaries or full states, high-frequency polling, sorting unbounded results, synchronous long diagnostics in a UI listener, and transferring large terms before truncation. Use target-side sampling and fixed refresh minimums.

Definition of Done

Minimum Viable Completion:

  • One disposable target, one allowlisted diagnostic, and clear standalone versus attached evaluator evidence.
  • Timeout and result cap work.
  • No cookie appears in saved output.

Full Completion:

  • All three modes, five diagnostic catalog entries, environment gate, target-side bounds, disconnect/timeout/restart/oversize drills, redaction scan, idempotent cleanup, and production-API recommendation are complete.
  • Evidence proves only a disposable loopback target was contacted.

Excellence (Going Above & Beyond):

  • Replace one repeated diagnostic with a mock authenticated read-only API featuring scoped authorization, rate limiting, freshness, and independent audit; compare its authority map with Remote Execution and attachment.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • operators inspect processes without mutation or exfiltration authority.

Project 125: WAN Netsplit Recovery Drill

Source: BEAM-P12. Partition nodes, allow only declared operations, heal, and reconcile.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Erlang or Elixir
  • Alternative Programming Languages: Gleam
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: Level 4: Open Core Infrastructure
  • Curriculum Difficulty: Level 4: Advanced
  • Knowledge Area: Distributed Systems, Failure Recovery
  • Software or Tool: Distributed Erlang + Supervision
  • Main Book: “Designing for Scalability with Erlang/OTP”

What you will build: Partition nodes, allow only declared operations, heal, and reconcile.

Why it teaches the BEAM ecosystem: It makes you prove that post-heal invariants and promised availability are automatically certified.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Partition nodes, allow only declared operations, heal, and reconcile.

A drill toolkit that can isolate sites, trigger controlled conflicts, heal links, and verify converged state.

$ netsplitctl isolate us-east eu-west
$ netsplitctl heal us-east eu-west

3.7.1 How to Run (Copy/Paste)

  • Start two site clusters using the secure formation baseline from consolidated Project 104.
  • Run netsplitctl isolate and apply scripted writes.
  • Run netsplitctl heal and verify convergence.

3.7.2 Golden Path Demo (Deterministic) One user record diverges during partition, then converges with documented merge rule.

3.7.3 If CLI: exact terminal transcript

$ netsplitctl isolate us-east eu-west
partition active

$ reconcilectl status
conflicts=14 merged=14 pending=0

The Core Question You Are Answering

“Can my distributed service prove recovery correctness after a real partition, not just reconnect transport?”

Concepts You Must Understand First

  1. Node monitor semantics
  2. Idempotent merge design
  3. Supervisor restart behavior under flapping conditions

Questions to Guide Your Design

  1. What merge policy is explicit and explainable?
  2. Which recovery steps can safely retry?
  3. How will you prove convergence objectively?

Thinking Exercise

Partition Timeline

Build a timeline for t0 partition start, t1 conflicting writes, t2 reconnect, t3 reconciliation complete.

Questions to answer:

  • Which events are irreversible?
  • Which events can be replayed safely?

The Interview Questions They Will Ask

  1. “What is a netsplit in Erlang clusters?”
  2. “How do you reconcile conflicting updates after partition healing?”
  3. “How do supervisors behave during repeated connect/disconnect cycles?”
  4. “How do you test partition recovery without production risk?”

Hints in Layers

Hint 1: Starting Point Start with deterministic partition scripts and fixed test users.

Hint 2: Next Level Add version metadata to every mutable record.

Hint 3: Technical Details Pseudocode:

on reconnect:
  fetch divergent keys
  apply merge policy
  emit reconciliation audit events

Hint 4: Tools/Debugging Persist reconciliation decisions to an audit log for replay and verification.

Books That Will Help

Topic Book Chapter
Distributed failure models “Designing for Scalability with Erlang/OTP” Fault-tolerance chapters
Process communication “Programming Erlang” Messaging and distributed chapters

Implementation Milestones

Milestone 1 — Contract and fixture: define one representative input, output, invariant, and failure case.

Milestone 2 — Core artifact: Partition nodes, allow only declared operations, heal, and reconcile.

Milestone 3 — Failure behavior: add timeouts, invalid inputs, crashes, retries, or partitions appropriate to the project.

Milestone 4 — Evidence: automate the definition of done and record a reproducible result.

Testing Strategy

  • Unit checks: pure parsing, validation, transition, and formatting decisions.
  • Integration checks: the real process, database, socket, notebook, or framework boundary.
  • Failure checks: malformed input plus at least one crash, timeout, duplicate, overload, or partition scenario.
  • Acceptance check: independently demonstrate that post-heal invariants and promised availability are automatically certified.
  • Avoid arbitrary sleeps; use messages, monitors, deterministic clocks, fixtures, and deadlines where applicable.

Common Pitfalls and Debugging

Problem 1: “State keeps oscillating after reconnect”

  • Why: Merge logic is non-idempotent or order-dependent.
  • Fix: Use monotonic versioning and idempotent merge rules.
  • Quick test: Replay the same reconciliation batch twice and confirm identical final state.

Definition of Done

  • Partition and heal events are reproducible from scripts
  • Reconciliation policy is explicit and documented
  • Final state converges after heal in repeated test runs
  • Recovery metrics/logs expose merge decisions

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • post-heal invariants and promised availability are automatically certified.

Project 126: Partition-Tolerant Horde and CRDT Cluster

Source: PHX-P17. Reconcile split-brain ownership and compare strict versus approximate global limits.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: Level 4: Open Core Infrastructure
  • Curriculum Difficulty: Level 4: Advanced
  • Knowledge Area: Distributed BEAM Engineering
  • Software or Tool: libcluster, Horde, Delta CRDT, Phoenix.PubSub
  • Main Book: “Designing Data-Intensive Applications” by Martin Kleppmann

What you will build: Reconcile split-brain ownership and compare strict versus approximate global limits.

Why it teaches the BEAM ecosystem: It makes you prove that no double ownership remains after convergence.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Reconcile split-brain ownership and compare strict versus approximate global limits.

Build a clustered service that survives netsplits, converges ownership state, and enforces configurable global rate-limit semantics.

deterministic_outcome:

  • scripted netsplit run completed
  • duplicate ownership resolved deterministically
  • rate-limit behavior matches declared policy

The Core Question You Are Answering

What does my system guarantee during partition, and how do I prove convergence after heal?

Concepts You Must Understand First

  • BEAM process model and failure isolation
  • OTP supervision semantics
  • Runtime observability discipline

Questions to Guide Your Design

  1. What is your safety invariant?
  2. What is your bounded recovery target?
  3. What is your fallback behavior under stress?

Thinking Exercise

Describe two truth tables:

  • strict limit under partition,
  • approximate limit under partition.

Include user-visible behavior for each path.

The Interview Questions They Will Ask

  1. What tradeoff did you choose and why?
  2. How do you prove correctness under failure?
  3. Which metric is your leading indicator of incident risk?
  4. “Which measurement would tell you that Partition-Tolerant Horde and CRDT Cluster is approaching its operating limit?”

Hints in Layers

Hint 1: Starting Point Document semantics first, implementation second.

Hint 2: Next Level Build deterministic ownership conflict resolver.

Hint 3: Technical Details Maintain conflict journal with before/after owner snapshots.

Hint 4: Tools/Debugging Run scripted partition/heal tests with fixed timeline.

Books That Will Help

Topic Book Chapter
Partition behavior “Designing Data-Intensive Applications” Replication + partition chapters
Cluster process discovery Horde docs Readme and usage sections

Implementation Milestones

  1. Baseline behavior validated.
  2. Instrumentation and dashboards available.
  3. Fault injection and recovery validated.
  4. Final report with tradeoffs and next steps.

Testing Strategy

6.1 Test Strategy

  • Unit tests for core transitions
  • Integration tests for runtime flows
  • Fault scenario tests for recovery

6.2 Verification Steps

  • Run full test suite.
  • Run deterministic lab script.

Common Pitfalls and Debugging

Problem 1: “Cluster heals but stale owners remain”

  • Why: non-deterministic conflict resolution policy.
  • Fix: enforce stable owner tie-break rule.
  • Quick test: repeat same partition scenario three times and compare final owners.

Problem 2: “Global limit oscillates wildly”

  • Why: sync interval too short or too long for traffic pattern.
  • Fix: tune window and sync cadence, or switch mode by workload.
  • Quick test: replay burst profile and chart accept/deny variance.

Definition of Done

  • Core functionality works on reference scenarios.
  • Failure path behavior matches design policy.
  • SLO metrics are captured and reproducible.
  • Findings are documented with evidence.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • no double ownership remains after convergence.

Project 127: Event-Sourced Multi-Tenant Phoenix Domain

Source: PHX-P21. Build event-sourced aggregates, CQRS projections, optimistic concurrency, tenancy, and replay.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: SQL
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: Level 4: Open Core Infrastructure
  • Curriculum Difficulty: Level 4: Advanced
  • Knowledge Area: Architecture Patterns
  • Software or Tool: Phoenix, Ecto, Oban, tenant routing
  • Main Book: “Domain-Driven Design” by Eric Evans

What you will build: Build event-sourced aggregates, CQRS projections, optimistic concurrency, tenancy, and replay.

Why it teaches the BEAM ecosystem: It makes you prove that projections rebuild and concurrent commands preserve invariants.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Build event-sourced aggregates, CQRS projections, optimistic concurrency, tenancy, and replay.

Build a tenant-scoped command/write path with event stream and asynchronous read projections.

deterministic_outcome:

  • command invariants enforced
  • projection lag visible and controlled
  • cross-tenant access tests blocked

The Core Question You Are Answering

How do I combine strict write correctness with fast reads and hard tenant boundaries?

Concepts You Must Understand First

  • BEAM process model and failure isolation
  • OTP supervision semantics
  • Runtime observability discipline

Questions to Guide Your Design

  1. What is your safety invariant?
  2. What is your bounded recovery target?
  3. What is your fallback behavior under stress?

Thinking Exercise

Map one invoice lifecycle from command to projection and identify where duplicates or replays can occur.

The Interview Questions They Will Ask

  1. What tradeoff did you choose and why?
  2. How do you prove correctness under failure?
  3. Which metric is your leading indicator of incident risk?
  4. “Which measurement would tell you that Event-Sourced Multi-Tenant Phoenix Domain is approaching its operating limit?”

Hints in Layers

Hint 1: Starting Point Define aggregate invariants before endpoint design.

Hint 2: Next Level Use versioned events and projection checkpointing.

Hint 3: Technical Details Use Oban jobs for projection with idempotent upserts.

Hint 4: Tools/Debugging Track projection lag and per-tenant error counters.

Books That Will Help

Topic Book Chapter
Domain boundaries “Domain-Driven Design” Strategic + tactical design
Event/CQRS patterns Fowler articles Event Sourcing + CQRS

Implementation Milestones

  1. Baseline behavior validated.
  2. Instrumentation and dashboards available.
  3. Fault injection and recovery validated.
  4. Final report with tradeoffs and next steps.

Testing Strategy

6.1 Test Strategy

  • Unit tests for core transitions
  • Integration tests for runtime flows
  • Fault scenario tests for recovery

6.2 Verification Steps

  • Run full test suite.
  • Run deterministic lab script.

Common Pitfalls and Debugging

Problem 1: “Read model inconsistent after retries”

  • Why: projection handler not idempotent.
  • Fix: use deterministic event_id checkpoints and upserts.
  • Quick test: replay same event batch twice and compare rows.

Problem 2: “Tenant leak in admin endpoint”

  • Why: missing tenant scope in one query path.
  • Fix: enforce tenant scoping at repository boundary.
  • Quick test: run cross-tenant fuzz query suite.

Definition of Done

  • Core functionality works on reference scenarios.
  • Failure path behavior matches design policy.
  • SLO metrics are captured and reproducible.
  • Findings are documented with evidence.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • projections rebuild and concurrent commands preserve invariants.

Project 128: BEAM Artifact and Bytecode Inspector

Sources: BEAM-P32, ERL-P11. Decode BEAM chunks and bytecode, then compare two builds for reproducibility.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir and Erlang
  • Alternative Programming Languages: Gleam
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: Level 4: Open Core Infrastructure
  • Curriculum Difficulty: Level 4: Advanced
  • Knowledge Area: BEAM Artifacts, Reproducible Builds
  • Software or Tool: :beam_lib, Code, Mix releases
  • Main Book: “The BEAM Book”

What you will build: Decode BEAM chunks and bytecode, then compare two builds for reproducibility.

Why it teaches the BEAM ecosystem: It makes you prove that every artifact difference has an explainable binary and metadata cause.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Integrated Scope

This is one consolidated project, not separate source builds. Implement the following contributions as phases of the same artifact:

  • Decode instructions and BEAM chunks using ERL-P11 foundations.
  • Add BEAM-P32 build metadata, dependency provenance, and reproducibility comparison to the same inspector.

Real World Outcome

Build target: Decode BEAM chunks and bytecode, then compare two builds for reproducibility.

Build beam-audit, a CLI/Mix task that scans a Mix release or arbitrary artifact directory, accounts for every file, safely inspects every .beam, detects duplicate modules, records interface and provenance metadata, enforces artifact policy, and compares two canonical manifests with layered difference explanations.

$ beam-audit scan _build/prod/rel/shop --manifest shop-a.json
release=shop files=418 beam_modules=173 malformed=0
duplicate_modules=0 debug_info_present=0 source_path_leaks=0
manifest_sha256=fd81... result=PASS

$ beam-audit compare shop-a.json shop-b.json --profile same-platform-v1
raw_equal_modules=171 raw_different_modules=2
normalized_equivalent=1 semantic_difference=1
result=FAIL unexplained_difference

3.7.1 How to Run

$ MIX_ENV=prod mix release
$ beam-audit scan _build/prod/rel/example --manifest build-a.json
$ beam-audit compare build-a.json build-b.json --profile strict-v1

3.7.2 Golden Path Demo

Build the same fixture from two different absolute checkout paths. The raw comparison identifies modules containing path-dependent compile metadata. The versioned semantic profile removes only the root prefix and reports normalized equivalence without calling the artifacts byte-identical. A deliberately modified code chunk remains an unexplained failure.

3.7.3 Exact Terminal Transcript

$ beam-audit explain build-a.json build-b.json Elixir.Example.Parser
module=Elixir.Example.Parser
raw_sha256 equal=false
chunk Code equal=true
chunk ExpT equal=true
chunk Attr equal=true
chunk CInf equal=false
CInf.source build_a=/tmp/a/lib/parser.ex build_b=/tmp/b/lib/parser.ex
normalization PATH-ROOT-1 => lib/parser.ex == lib/parser.ex
classification=normalized_equivalent
byte_reproducible=false semantic_profile_match=true

The Core Question You Are Answering

“How can I prove what is inside a BEAM release and explain why two builds differ without trusting or executing either artifact?”

Concepts You Must Understand First

  1. BEAM modules, exports/imports, code loading, and application code paths.
  2. Binary containers, chunks, hashing, and canonical serialization.
  3. Compiler/debug metadata and build input provenance.
  4. Raw identity versus normalized semantic comparison.
  5. Safe traversal, symlinks, and resource-limited parsing.

Questions to Guide Your Design

  1. Which chunks are required, optional, or toolchain-specific?
  2. What is the threat boundary for untrusted artifacts?
  3. Which manifest fields prove exact bytes and which are interpretations?
  4. What may each normalization rule remove without hiding behavior changes?
  5. How does a cross-target profile differ from strict reproducibility?

Thinking Exercise

Imagine two BEAM files with equal code chunks and exports but different compile information and raw hashes. List what you can claim, what you cannot claim, and which evidence would determine whether the difference is expected path variance or undeclared toolchain drift.

The Interview Questions They Will Ask

  1. “What is stored in a BEAM file, and why does chunk presence vary?”
  2. “Why is calling module_info unsafe for an untrusted artifact auditor?”
  3. “What is the difference between byte reproducibility and semantic equivalence?”
  4. “How would you detect duplicate modules in a release?”
  5. “Which build inputs belong in provenance?”
  6. “How do you prevent normalization from hiding a meaningful change?”

Hints in Layers

Hint 1: Account before decode — Produce a raw file entry even if BEAM inspection later fails.

Hint 2: Ask for less — Extract only chunks required by enabled inventory and policy rules.

Hint 3: Preserve three identities — Raw file, per-chunk, and semantic digests answer different questions.

Hint 4: Make normalizers testify — Every normalized difference names a rule and displays before/after evidence.

Books That Will Help

Topic Book Precise reading
VM artifacts The BEAM Book — Erik Stenman “The BEAM File Format” and “Code Loading” chapters/sections
Erlang compilation Programming Erlang, 2nd ed. — Joe Armstrong Chapters on compiling and running programs and code loading
OTP releases Designing for Scalability with Erlang/OTP Release handling and deployment chapters
Supply-chain framing Building Secure and Reliable Systems — Google Chapters on software supply chain and verifiable artifacts

Implementation Milestones

Integrated basic-to-advanced progression

  1. Decode instructions and BEAM chunks using ERL-P11 foundations.
  2. Add BEAM-P32 build metadata, dependency provenance, and reproducibility comparison to the same inspector.

Milestone 1 — Contract and fixture: define one representative input, output, invariant, and failure case.

Milestone 2 — Core artifact: Decode BEAM chunks and bytecode, then compare two builds for reproducibility.

Milestone 3 — Failure behavior: add timeouts, invalid inputs, crashes, retries, or partitions appropriate to the project.

Milestone 4 — Evidence: automate the definition of done and record a reproducible result.

Phase 1: Safe Inventory (5-8 hours)

  • Walk and hash all release files deterministically.
  • Inspect basic BEAM identity and chunk lists without loading.
  • Add malformed-file and module-collision reporting.

Phase 2: Semantic Manifest (5-8 hours)

  • Extract exports, imports, attributes, compile and docs/debug summaries.
  • Add chunk digests, resource limits, and versioned adapters.
  • Canonicalize and hash the manifest.

Phase 3: Policy and Comparison (6-10 hours)

  • Add artifact policy rules and difference hierarchy.
  • Implement narrow visible normalization profiles.
  • Explain raw, chunk, and semantic differences.

Phase 4: Reproducibility Harness (6-8 hours)

  • Build fixtures from distinct roots and toolchain inputs.
  • Add tamper, cross-target, and over-normalization negative tests.
  • Document precise claims and CI exit statuses.

Testing Strategy

6.1 Test Categories

Category Purpose Examples
Container Validate BEAM parsing normal, stripped, corrupt, truncated
Inventory Protect module/interface facts exports, imports, absent optional chunks
Safety Prove no loading and bounded paths on-load fixture, symlink escape, huge chunk
Policy Validate rule evidence debug info, source paths, duplicate module
Reproducibility Compare controlled builds different roots, lock, toolchain, target
Canonicalization Stabilize manifests randomized discovery order
Tamper Protect raw integrity post-build byte modification

6.2 Critical Test Cases

  1. An artifact with load-time behavior is inspected without entering the code server.
  2. A malformed BEAM receives a manifest error entry and nonzero policy result.
  3. Missing optional debug/docs chunks are classified according to policy, not parser failure.
  4. Duplicate module identities across two application paths are reported together.
  5. Random filesystem discovery order yields the same manifest digest.
  6. Builds from two roots expose path variance without hiding raw inequality.
  7. A changed code chunk remains unexplained under the path normalizer.
  8. A native library change fails whole-release raw comparison.
  9. Cross-architecture strict comparison refuses an invalid success claim.
  10. Resource limits stop an oversized decoded chunk while the scan completes accountably.

6.3 Test Data

Compile minimal modules with docs/debug information enabled and stripped, source roots varied, exports altered, and duplicate module names. Mutate copied files for corruption and tamper cases. Include a release with a small sample native asset so whole-tree comparison is tested.

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Problem Why it happens Fix Quick test
Inspector executes candidate Uses code loading for metadata Use :beam_lib; assert module remains unloaded On-load marker fixture
Missing file disappears Parser error drops entry Create raw entry before decode Scan truncated BEAM
False reproducible claim Semantic digest replaces raw hash Report raw identity first Change ignored metadata byte
Meaningful drift hidden Normalizer drops whole compile info Narrow field-specific rule Change compiler option too
Duplicate module missed Index scoped only per app Build release-global module index Two apps define same module
Memory spike Decodes many large chunks concurrently Limit concurrency and decoded size Oversized debug fixture

7.2 Debugging Strategies

  • Use an explain command for one file/module instead of dumping full manifests.
  • Compare chunk sets before decoding semantic values.
  • Print the exact normalization rule and before/after value.
  • Check code server loaded modules before and after safety fixtures.
  • Recreate builds with one controlled input changed at a time.

7.3 Performance Traps

  • Reading every release file fully into memory to hash it
  • Decoding abstract/debug chunks when no enabled rule needs them
  • Unbounded Task concurrency over thousands of modules
  • Retaining full chunk binaries inside the final manifest
  • Recomputing global collision indexes per file

Definition of Done

  • Every selected release file appears in the manifest, including failures.
  • Candidate modules are never loaded or executed.
  • BEAM identity, chunk presence, interfaces, and policy evidence are documented.
  • Duplicate modules and malformed containers are detected.
  • Raw, chunk, and semantic digests remain separate.
  • Manifests are canonical and deterministic under randomized traversal.
  • Every normalizer is versioned, visible, and has a negative test.
  • Comparison output never labels normalized equivalence as byte identity.
  • Provenance states declared source, lock, toolchain, target, and profile.
  • Resource, symlink, and incomplete-scan policies are enforced.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • Every merged source contribution is implemented as a phase of this one artifact, not as a separate project.
  • every artifact difference has an explainable binary and metadata cause.

Project 129: Tracing-Driven Phoenix Performance War Room

Sources: ERL-P12, PHX-P18. Use bounded tracing, Telemetry, profiling, and load models to diagnose latency.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: JavaScript (k6)
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: Level 4: Open Core Infrastructure
  • Curriculum Difficulty: Level 4: Advanced
  • Knowledge Area: Performance Engineering
  • Software or Tool: k6, :observer, telemetry, :fprof, :eprof
  • Main Book: “Systems Performance” by Brendan Gregg

What you will build: Use bounded tracing, Telemetry, profiling, and load models to diagnose latency.

Why it teaches the BEAM ecosystem: It makes you prove that a repeatable before/after experiment attributes the bottleneck safely.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Integrated Scope

This is one consolidated project, not separate source builds. Implement the following contributions as phases of the same artifact:

  • Build ERL-P12 bounded trace collection and safe filtering first.
  • Use those traces inside PHX-P18 load, Telemetry, profiling, and before/after latency experiments.

Real World Outcome

Build target: Use bounded tracing, Telemetry, profiling, and load models to diagnose latency.

Build a reproducible performance pipeline for API + LiveView workloads with load tests, tracing, profiling, and SLO dashboards.

deterministic_outcome:

  • repeatable load profile in CI
  • p99 latency improvement validated
  • hotspot report links change to metric gain

The Core Question You Are Answering

Can I prove performance improvements under identical load with traceable evidence?

Concepts You Must Understand First

  • BEAM process model and failure isolation
  • OTP supervision semantics
  • Runtime observability discipline

Questions to Guide Your Design

  1. What is your safety invariant?
  2. What is your bounded recovery target?
  3. What is your fallback behavior under stress?

Thinking Exercise

Define one “false improvement” scenario (p50 improves, p99 worsens). Explain why this is a regression.

The Interview Questions They Will Ask

  1. What tradeoff did you choose and why?
  2. How do you prove correctness under failure?
  3. Which metric is your leading indicator of incident risk?
  4. “Which measurement would tell you that Tracing-Driven Phoenix Performance War Room is approaching its operating limit?”

Hints in Layers

Hint 1: Starting Point Pick 3 SLOs before writing any script.

Hint 2: Next Level Separate websocket-heavy and API-heavy traffic profiles.

Hint 3: Technical Details Use fixed warmup, steady-state, and cooldown phases.

Hint 4: Tools/Debugging Capture profile snapshots only during steady-state window.

Books That Will Help

Topic Book Chapter
Performance workflow “Systems Performance” Methodology + CPU analysis
Phoenix observability telemetry docs Event handling and measurements

Implementation Milestones

Integrated basic-to-advanced progression

  1. Build ERL-P12 bounded trace collection and safe filtering first.
  2. Use those traces inside PHX-P18 load, Telemetry, profiling, and before/after latency experiments.

Milestone 1 — Contract and fixture: define one representative input, output, invariant, and failure case.

Milestone 2 — Core artifact: Use bounded tracing, Telemetry, profiling, and load models to diagnose latency.

Milestone 3 — Failure behavior: add timeouts, invalid inputs, crashes, retries, or partitions appropriate to the project.

Milestone 4 — Evidence: automate the definition of done and record a reproducible result.

  1. Baseline behavior validated.
  2. Instrumentation and dashboards available.
  3. Fault injection and recovery validated.
  4. Final report with tradeoffs and next steps.

Testing Strategy

6.1 Test Strategy

  • Unit tests for core transitions
  • Integration tests for runtime flows
  • Fault scenario tests for recovery

6.2 Verification Steps

  • Run full test suite.
  • Run deterministic lab script.

Common Pitfalls and Debugging

Problem 1: “Great benchmark, bad production”

  • Why: unrealistic traffic shape and no background jobs in test profile.
  • Fix: include mixed workload and burst patterns.
  • Quick test: compare synthetic and production metric distributions.

Problem 2: “Metrics backend overloaded”

  • Why: high-cardinality labels (user_id, full URL path).
  • Fix: normalize labels to route and cohort.
  • Quick test: track series count before/after label cleanup.

Definition of Done

  • Core functionality works on reference scenarios.
  • Failure path behavior matches design policy.
  • SLO metrics are captured and reproducible.
  • Findings are documented with evidence.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • Every merged source contribution is implemented as a phase of this one artifact, not as a separate project.
  • a repeatable before/after experiment attributes the bottleneck safely.

Project 130: Scheduler, Heap, and Mailbox Pressure Lab

Sources: PHX-P15, ERL-P13, ERL-P14, PUB-P7. First inspect process heaps and GC, then correlate reductions, run queues, and subscriber mailboxes under overload.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: Level 4: Open Core Infrastructure
  • Curriculum Difficulty: Level 4: Advanced
  • Knowledge Area: BEAM Internals
  • Software or Tool: :observer, telemetry, custom probes
  • Main Book: “Elixir in Action” by Sasa Juric

What you will build: First inspect process heaps and GC, then correlate reductions, run queues, and subscriber mailboxes under overload.

Why it teaches the BEAM ecosystem: It makes you prove that admission or shedding keeps queues bounded.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Integrated Scope

This is one consolidated project, not separate source builds. Implement the following contributions as phases of the same artifact:

  • Start with ERL-P13 heap and garbage-collection evidence.
  • Add ERL-P14 scheduler reductions and run-queue measurements.
  • Apply PHX-P15 workload control and PUB-P7 subscriber-mailbox pressure to one overload laboratory.

Real World Outcome

Build target: First inspect process heaps and GC, then correlate reductions, run queues, and subscriber mailboxes under overload.

Build a BEAM runtime diagnostics service that detects scheduler queue pressure, mailbox growth, and binary memory retention, then applies adaptive backpressure.

deterministic_outcome:

  • p99 latency reduced after backpressure
  • mailbox max stabilized under burst load
  • binary memory trend flattened

The Core Question You Are Answering

How can I separate scheduler pressure from mailbox pressure and fix the right bottleneck first?

Concepts You Must Understand First

  • BEAM process model and failure isolation
  • OTP supervision semantics
  • Runtime observability discipline

Questions to Guide Your Design

  1. What is your safety invariant?
  2. What is your bounded recovery target?
  3. What is your fallback behavior under stress?

Thinking Exercise

Create two timelines:

  • Timeline A: no backpressure, write-heavy broadcast.
  • Timeline B: adaptive backpressure at mailbox threshold.

Predict how p99 latency and memory differ before running tests.

The Interview Questions They Will Ask

  1. What tradeoff did you choose and why?
  2. How do you prove correctness under failure?
  3. Which metric is your leading indicator of incident risk?
  4. “Which measurement would tell you that Scheduler, Heap, and Mailbox Pressure Lab is approaching its operating limit?”

Hints in Layers

Hint 1: Starting Point Instrument first, optimize second.

Hint 2: Next Level Track queue length at both scheduler and mailbox levels.

Hint 3: Technical Details Use periodic telemetry samples and threshold-based throttling state machine.

Hint 4: Tools/Debugging Correlate :observer snapshots with custom metrics every 5 seconds.

Books That Will Help

Topic Book Chapter
BEAM process model “Elixir in Action” Concurrency + OTP chapters
Runtime memory behavior Erlang Efficiency Guide Processes + Binary Handling

Implementation Milestones

Integrated basic-to-advanced progression

  1. Start with ERL-P13 heap and garbage-collection evidence.
  2. Add ERL-P14 scheduler reductions and run-queue measurements.
  3. Apply PHX-P15 workload control and PUB-P7 subscriber-mailbox pressure to one overload laboratory.

Milestone 1 — Contract and fixture: define one representative input, output, invariant, and failure case.

Milestone 2 — Core artifact: First inspect process heaps and GC, then correlate reductions, run queues, and subscriber mailboxes under overload.

Milestone 3 — Failure behavior: add timeouts, invalid inputs, crashes, retries, or partitions appropriate to the project.

Milestone 4 — Evidence: automate the definition of done and record a reproducible result.

  1. Baseline behavior validated.
  2. Instrumentation and dashboards available.
  3. Fault injection and recovery validated.
  4. Final report with tradeoffs and next steps.

Testing Strategy

6.1 Test Strategy

  • Unit tests for core transitions
  • Integration tests for runtime flows
  • Fault scenario tests for recovery

6.2 Verification Steps

  • Run full test suite.
  • Run deterministic lab script.

Common Pitfalls and Debugging

Problem 1: “Backpressure never triggers”

  • Why: threshold values too high for observed load.
  • Fix: calibrate thresholds from baseline p95/p99 metrics.
  • Quick test: replay same load profile and confirm action events.

Problem 2: “Latency improves but memory still climbs”

  • Why: retained large binaries in long-lived process state.
  • Fix: copy or re-encode binary at ownership boundary.
  • Quick test: compare vm.memory.binary before/after patch.

Definition of Done

  • Core functionality works on reference scenarios.
  • Failure path behavior matches design policy.
  • SLO metrics are captured and reproducible.
  • Findings are documented with evidence.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • Every merged source contribution is implemented as a phase of this one artifact, not as a separate project.
  • admission or shedding keeps queues bounded.

Project 131: Raw Erlang C NIF for Fast JSON

Source: ERL-P15. Build a C NIF directly against the Erlang NIF API, including resource lifetime, validation, scheduler budget, and crash-risk tests.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Erlang + C
  • Alternative Programming Languages: Erlang + Rust, Erlang + Zig
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: Level 4: Open Core Infrastructure
  • Curriculum Difficulty: Level 4: Advanced
  • Knowledge Area: FFI / Native Code
  • Software or Tool: NIFs (Native Implemented Functions)
  • Main Book: “The BEAM Book” by Erik Stenman

What you will build: Build a C NIF directly against the Erlang NIF API, including resource lifetime, validation, scheduler budget, and crash-risk tests.

Why it teaches the BEAM ecosystem: It makes you prove that speedup is measured without blocking schedulers or leaking native memory.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Build a C NIF directly against the Erlang NIF API, including resource lifetime, validation, scheduler budget, and crash-risk tests.

A NIF (Native Implemented Function) that wraps a fast C JSON parser (like yyjson or simdjson) to provide high-performance JSON parsing for Erlang, learning the NIF API along the way.

Build Raw Erlang C NIF for Fast JSON as one runnable, observable artifact. Build a C NIF directly against the Erlang NIF API, including resource lifetime, validation, scheduler budget, and crash-risk tests.

Produce an evidence bundle containing:

  • one deterministic happy-path run;
  • one rejected or malformed input with an explicit reason;
  • one injected failure or boundary condition;
  • a final verification result proving: speedup is measured without blocking schedulers or leaking native memory.
artifact=raw_erlang_c_nif_for_fast_json
happy_path=PASS
invalid_input=REJECTED explicit_reason=true
failure_boundary=EXERCISED recovery_evidence=true
mastery_check=PASS

The Core Question You Are Answering

“How can Raw Erlang C NIF for Fast JSON deliver its observable outcome while proving that speedup is measured without blocking schedulers or leaking native memory.”

Concepts You Must Understand First

  • NIF boilerplate (module setup, function registration) → maps to NIF API
  • Type conversion (Erlang terms ↔ C types) → maps to enif_ functions*
  • Memory management (who owns what) → maps to resource objects
  • Scheduler safety (don’t block schedulers) → maps to dirty NIFs
  • Error handling (C errors → Erlang exceptions) → maps to enif_raise_exception

Questions to Guide Your Design

  1. Which input and output contracts must remain stable across refactoring?
  2. Where should validation happen, and how will expected failures be represented?
  3. Which component owns mutable state or external effects, and what happens when it dies?
  4. What independent evidence proves this mastery condition: speedup is measured without blocking schedulers or leaking native memory.

Thinking Exercise

Draw Raw Erlang C NIF for Fast JSON as an input → decision/state → effect → evidence pipeline.

Mark every failure boundary, retry boundary, and durable state transition. Then inject one failure at each boundary and predict the observable result before implementing it.

The Interview Questions They Will Ask

  1. “What is the hardest invariant in Raw Erlang C NIF for Fast JSON, and where is it enforced?”
  2. “Which parts should be pure transformations and which require BEAM processes?”
  3. “How does the design behave under malformed input, process failure, or retry?”
  4. “What test or runtime evidence proves: speedup is measured without blocking schedulers or leaking native memory.”

Hints in Layers

NIF skeleton in C: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Note ERL_NIF_DIRTY_JOB_CPU_BOUND - this runs on a dirty scheduler so it doesn’t block regular schedulers.

Hint 1: Starting Point Implement the narrowest happy path for: Build a C NIF directly against the Erlang NIF API, including resource lifetime, validation, scheduler budget, and crash-risk tests.

Hint 2: Next Level Separate parsing, validation, and transition decisions from effects so each can be tested directly.

Hint 3: Technical Details Represent expected failures as tagged outcomes and keep state ownership explicit; write only structural pseudocode before implementation.

Hint 4: Tools and Debugging Inject one failure at a time, correlate it with bounded telemetry, and save a deterministic transcript as evidence.

Books That Will Help

  • Main Book: “The BEAM Book” by Erik Stenman

Implementation Milestones

  1. Basic NIF compiles and loads → NIF infrastructure understood
  2. Simple types convert correctly → Type conversion works
  3. Complex JSON parses correctly → Full implementation works
  4. Benchmarks show significant speedup → NIF was worth it

Testing Strategy

  • Unit checks: pure parsing, validation, transition, and formatting decisions.
  • Integration checks: the real process, database, socket, notebook, or framework boundary.
  • Failure checks: malformed input plus at least one crash, timeout, duplicate, overload, or partition scenario.
  • Acceptance check: independently demonstrate that speedup is measured without blocking schedulers or leaking native memory.
  • Avoid arbitrary sleeps; use messages, monitors, deterministic clocks, fixtures, and deadlines where applicable.

Common Pitfalls and Debugging

Problem 1: Happy-path output looks correct but failures disappear

  • Why: validation, effects, and reporting share one opaque step.
  • Fix: preserve tagged errors and source identity through every stage.
  • Quick test: inject one invalid record or failed dependency and verify an explicit result.

Problem 2: Tests merely repeat the implementation

  • Why: assertions reuse the same transformation or state assumptions.
  • Fix: check external invariants, golden fixtures, and observable failure behavior.
  • Quick test: introduce a deliberate ordering or boundary bug and confirm the test fails.

Definition of Done

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • speedup is measured without blocking schedulers or leaking native memory.

Project 132: Erlang Parse Transform System

Source: ERL-P17. Inspect and rewrite Erlang forms with deterministic expansion and compiler diagnostics.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Erlang
  • Alternative Programming Languages: None (Erlang-specific)
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: Level 4: Open Core Infrastructure
  • Curriculum Difficulty: Level 4: Advanced
  • Knowledge Area: Metaprogramming / Compiler
  • Software or Tool: Parse Transforms
  • Main Book: “Metaprogramming Elixir” by Chris McCord (for concepts, then apply to Erlang)

What you will build: Inspect and rewrite Erlang forms with deterministic expansion and compiler diagnostics.

Why it teaches the BEAM ecosystem: It makes you prove that transformed code preserves semantics, source information, and debuggability.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Inspect and rewrite Erlang forms with deterministic expansion and compiler diagnostics.

A parse transform that adds Elixir-like pipe operator (|>) to Erlang, transforming X |> foo() |> bar(Y) into bar(foo(X), Y) at compile time.

Build Erlang Parse Transform System as one runnable, observable artifact. Inspect and rewrite Erlang forms with deterministic expansion and compiler diagnostics.

Produce an evidence bundle containing:

  • one deterministic happy-path run;
  • one rejected or malformed input with an explicit reason;
  • one injected failure or boundary condition;
  • a final verification result proving: transformed code preserves semantics, source information, and debuggability.
artifact=erlang_parse_transform_system
happy_path=PASS
invalid_input=REJECTED explicit_reason=true
failure_boundary=EXERCISED recovery_evidence=true
mastery_check=PASS

The Core Question You Are Answering

“How can Erlang Parse Transform System deliver its observable outcome while proving that transformed code preserves semantics, source information, and debuggability.”

Concepts You Must Understand First

  • Erlang Abstract Format (the AST) → maps to understanding term structure
  • Parse transform interface → maps to parse_transform/2 function
  • AST walking (find all |> operators) → maps to recursive tree traversal
  • AST rewriting (transform to function calls) → maps to term construction
  • Error reporting (good compile errors) → maps to compiler integration

Questions to Guide Your Design

  1. Which input and output contracts must remain stable across refactoring?
  2. Where should validation happen, and how will expected failures be represented?
  3. Which component owns mutable state or external effects, and what happens when it dies?
  4. What independent evidence proves this mastery condition: transformed code preserves semantics, source information, and debuggability.

Thinking Exercise

Draw Erlang Parse Transform System as an input → decision/state → effect → evidence pipeline.

Mark every failure boundary, retry boundary, and durable state transition. Then inject one failure at each boundary and predict the observable result before implementing it.

The Interview Questions They Will Ask

  1. “What is the hardest invariant in Erlang Parse Transform System, and where is it enforced?”
  2. “Which parts should be pure transformations and which require BEAM processes?”
  3. “How does the design behave under malformed input, process failure, or retry?”
  4. “What test or runtime evidence proves: transformed code preserves semantics, source information, and debuggability.”

Hints in Layers

Parse transform skeleton: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

The tricky part is handling the AST format correctly. Use erl_syntax module for easier manipulation: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Hint 1: Starting Point Implement the narrowest happy path for: Inspect and rewrite Erlang forms with deterministic expansion and compiler diagnostics.

Hint 2: Next Level Separate parsing, validation, and transition decisions from effects so each can be tested directly.

Hint 3: Technical Details Represent expected failures as tagged outcomes and keep state ownership explicit; write only structural pseudocode before implementation.

Hint 4: Tools and Debugging Inject one failure at a time, correlate it with bounded telemetry, and save a deterministic transcript as evidence.

Books That Will Help

  • Main Book: “Metaprogramming Elixir” by Chris McCord (for concepts, then apply to Erlang)

Implementation Milestones

  1. Parse transform compiles → Basic structure works
  2. Simple pipes transform → AST rewriting works
  3. Nested pipes work → Recursive transformation correct
  4. Good error messages on invalid input → Production quality

Testing Strategy

  • Unit checks: pure parsing, validation, transition, and formatting decisions.
  • Integration checks: the real process, database, socket, notebook, or framework boundary.
  • Failure checks: malformed input plus at least one crash, timeout, duplicate, overload, or partition scenario.
  • Acceptance check: independently demonstrate that transformed code preserves semantics, source information, and debuggability.
  • Avoid arbitrary sleeps; use messages, monitors, deterministic clocks, fixtures, and deadlines where applicable.

Common Pitfalls and Debugging

Problem 1: Happy-path output looks correct but failures disappear

  • Why: validation, effects, and reporting share one opaque step.
  • Fix: preserve tagged errors and source identity through every stage.
  • Quick test: inject one invalid record or failed dependency and verify an explicit result.

Problem 2: Tests merely repeat the implementation

  • Why: assertions reuse the same transformation or state assumptions.
  • Fix: check external invariants, golden fixtures, and observable failure behavior.
  • Quick test: introduce a deliberate ordering or boundary bug and confirm the test fails.

Definition of Done

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • transformed code preserves semantics, source information, and debuggability.

Project 133: Hot-Upgrade Release Engineering Drill

Sources: BEAM-P9, ERL-P16, PHX-P19. Transform process state, canary an upgrade, and rehearse rollback after first mastering self-contained releases.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Shell
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: Level 4: Open Core Infrastructure
  • Curriculum Difficulty: Level 4: Advanced
  • Knowledge Area: Release Engineering
  • Software or Tool: Mix releases, release handling scripts
  • Main Book: Erlang Design Principles docs

What you will build: Transform process state, canary an upgrade, and rehearse rollback after first mastering self-contained releases.

Why it teaches the BEAM ecosystem: It makes you prove that compatible upgrades preserve active work and incompatible changes fail safely.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Integrated Scope

This is one consolidated project, not separate source builds. Implement the following contributions as phases of the same artifact:

  • Use BEAM-P9 and ERL-P16 to practice appup/relup state transformation on a small release.
  • Finish with PHX-P19 runtime configuration, canary deployment, rollback, and active-session evidence.

Real World Outcome

Build target: Transform process state, canary an upgrade, and rehearse rollback after first mastering self-contained releases.

Build a release workflow with config preflight, canary deployment, hot-upgrade rehearsal, and automated rollback drill.

deterministic_outcome:

  • canary upgrade completed with health gates
  • rollback rehearsal passes within target window
  • config errors fail before serving traffic

The Core Question You Are Answering

Can I safely upgrade and rollback under active traffic without violating correctness?

Concepts You Must Understand First

  • BEAM process model and failure isolation
  • OTP supervision semantics
  • Runtime observability discipline

Questions to Guide Your Design

  1. What is your safety invariant?
  2. What is your bounded recovery target?
  3. What is your fallback behavior under stress?

Thinking Exercise

Design a failure drill where upgrade succeeds technically but must rollback due to latency regression.

The Interview Questions They Will Ask

  1. What tradeoff did you choose and why?
  2. How do you prove correctness under failure?
  3. Which metric is your leading indicator of incident risk?
  4. “Which measurement would tell you that Hot-Upgrade Release Engineering Drill is approaching its operating limit?”

Hints in Layers

Hint 1: Starting Point Build deterministic preflight checklist first.

Hint 2: Next Level Include state schema version in process state.

Hint 3: Technical Details Implement conversion function for each version bump.

Hint 4: Tools/Debugging Run canary under steady traffic, not idle environment.

Books That Will Help

Topic Book Chapter
Release handling Erlang Design Principles Release handling section
Deploy safety “Release It!” Deployment and stability chapters

Implementation Milestones

Integrated basic-to-advanced progression

  1. Use BEAM-P9 and ERL-P16 to practice appup/relup state transformation on a small release.
  2. Finish with PHX-P19 runtime configuration, canary deployment, rollback, and active-session evidence.

Milestone 1 — Contract and fixture: define one representative input, output, invariant, and failure case.

Milestone 2 — Core artifact: Transform process state, canary an upgrade, and rehearse rollback after first mastering self-contained releases.

Milestone 3 — Failure behavior: add timeouts, invalid inputs, crashes, retries, or partitions appropriate to the project.

Milestone 4 — Evidence: automate the definition of done and record a reproducible result.

  1. Baseline behavior validated.
  2. Instrumentation and dashboards available.
  3. Fault injection and recovery validated.
  4. Final report with tradeoffs and next steps.

Testing Strategy

6.1 Test Strategy

  • Unit tests for core transitions
  • Integration tests for runtime flows
  • Fault scenario tests for recovery

6.2 Verification Steps

  • Run full test suite.
  • Run deterministic lab script.

Common Pitfalls and Debugging

Problem 1: “Node boots but features fail”

  • Why: config defaults masked missing secret values.
  • Fix: fail-fast config schema validation before app start.
  • Quick test: run boot with intentionally missing secret.

Problem 2: “Upgrade succeeds but memory grows”

  • Why: migrated state retains legacy fields and large payloads.
  • Fix: trim migrated state and enforce shape contracts.
  • Quick test: compare memory snapshots pre/post upgrade.

Definition of Done

  • Core functionality works on reference scenarios.
  • Failure path behavior matches design policy.
  • SLO metrics are captured and reproducible.
  • Findings are documented with evidence.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • Every merged source contribution is implemented as a phase of this one artifact, not as a separate project.
  • compatible upgrades preserve active work and incompatible changes fail safely.

Project 134: Distributed Erlang Game Server

Source: ERL-P18. Build a multi-node world with process-owned rooms, player migration, matchmaking, and failure recovery.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Erlang
  • Alternative Programming Languages: Elixir, Go
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: Level 4: Open Core Infrastructure
  • Curriculum Difficulty: Level 4: Advanced
  • Knowledge Area: Distributed Systems / Game Development
  • Software or Tool: Distributed Erlang
  • Main Book: “Designing for Scalability with Erlang/OTP” by Cesarini & Vinoski

What you will build: Build a multi-node world with process-owned rooms, player migration, matchmaking, and failure recovery.

Why it teaches the BEAM ecosystem: It makes you prove that sessions survive churn and partition behavior is documented.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Build a multi-node world with process-owned rooms, player migration, matchmaking, and failure recovery.

# Start 3 game server nodes
$ ./start_node.sh node1 8080
$ ./start_node.sh node2 8081
$ ./start_node.sh node3 8082

# Open browser to http://localhost:8080/game
# See: "Connected to node1. 15 players online."
# Move your character with arrow keys
# See other players moving in real-time

# Kill node1 (Ctrl+C)
# Browser automatically reconnects to node2
# Game continues seamlessly!
# "Reconnected to node2. 15 players online."

# Start node1 again
# Some players automatically migrate back to balance load

The Core Question You Are Answering

“How can Distributed Erlang Game Server deliver its observable outcome while proving that sessions survive churn and partition behavior is documented.”

Concepts You Must Understand First

  • Player process per connection → maps to massive concurrency
  • Game world state (positions, collisions) → maps to shared state patterns
  • Node clustering → maps to distributed Erlang
  • Process migration (when node fails) → maps to process handoff
  • Real-time updates (60 updates/second) → maps to timer:send_interval
  • Client protocol (WebSocket for browser) → maps to cowboy websocket

Questions to Guide Your Design

  1. Which input and output contracts must remain stable across refactoring?
  2. Where should validation happen, and how will expected failures be represented?
  3. Which component owns mutable state or external effects, and what happens when it dies?
  4. What independent evidence proves this mastery condition: sessions survive churn and partition behavior is documented.

Thinking Exercise

Draw Distributed Erlang Game Server as an input → decision/state → effect → evidence pipeline.

Mark every failure boundary, retry boundary, and durable state transition. Then inject one failure at each boundary and predict the observable result before implementing it.

The Interview Questions They Will Ask

  1. “What is the hardest invariant in Distributed Erlang Game Server, and where is it enforced?”
  2. “Which parts should be pure transformations and which require BEAM processes?”
  3. “How does the design behave under malformed input, process failure, or retry?”
  4. “What test or runtime evidence proves: sessions survive churn and partition behavior is documented.”

Hints in Layers

Architecture:

                    ┌─────────────────────────────────────────┐
                    │             Load Balancer               │
                    └──────────────┬──────────────────────────┘
                                   │
         ┌─────────────────────────┼─────────────────────────┐
         │                         │                         │
    ┌────▼────┐              ┌─────▼────┐              ┌─────▼────┐
    │  Node1  │◄────────────►│  Node2   │◄────────────►│  Node3   │
    │(Erlang) │  Distributed │ (Erlang) │  Erlang     │ (Erlang) │
    └────┬────┘   Erlang     └─────┬────┘              └─────┬────┘
         │                         │                         │
   ┌─────┼─────┐             ┌─────┼─────┐             ┌─────┼─────┐
   │Player│Game│             │Player│Game│             │Player│Game│
   │Procs │Loop│             │Procs │Loop│             │Procs │Loop│
   └──────┴────┘             └──────┴────┘             └──────┴────┘

Key pattern - player as process with mailbox: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Using pg for process groups: Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Hint 1: Starting Point Implement the narrowest happy path for: Build a multi-node world with process-owned rooms, player migration, matchmaking, and failure recovery.

Hint 2: Next Level Separate parsing, validation, and transition decisions from effects so each can be tested directly.

Hint 3: Technical Details Represent expected failures as tagged outcomes and keep state ownership explicit; write only structural pseudocode before implementation.

Hint 4: Tools and Debugging Inject one failure at a time, correlate it with bounded telemetry, and save a deterministic transcript as evidence.

Books That Will Help

  • Main Book: “Designing for Scalability with Erlang/OTP” by Cesarini & Vinoski

Implementation Milestones

  1. Single-node game works → Basic architecture correct
  2. Multi-node clustering works → Distribution works
  3. Player survives node failure → Fault tolerance achieved
  4. Smooth gameplay at 60 FPS → Performance tuned

Testing Strategy

  • Unit checks: pure parsing, validation, transition, and formatting decisions.
  • Integration checks: the real process, database, socket, notebook, or framework boundary.
  • Failure checks: malformed input plus at least one crash, timeout, duplicate, overload, or partition scenario.
  • Acceptance check: independently demonstrate that sessions survive churn and partition behavior is documented.
  • Avoid arbitrary sleeps; use messages, monitors, deterministic clocks, fixtures, and deadlines where applicable.

Common Pitfalls and Debugging

Problem 1: Happy-path output looks correct but failures disappear

  • Why: validation, effects, and reporting share one opaque step.
  • Fix: preserve tagged errors and source identity through every stage.
  • Quick test: inject one invalid record or failed dependency and verify an explicit result.

Problem 2: Tests merely repeat the implementation

  • Why: assertions reuse the same transformation or state assumptions.
  • Fix: check external invariants, golden fixtures, and observable failure behavior.
  • Quick test: introduce a deliberate ordering or boundary bug and confirm the test fails.

Definition of Done

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • sessions survive churn and partition behavior is documented.

Project 135: Federated Tenant-Safe Broker Edge Bus

Sources: BEAM-P13, PUB-P11. Bridge selected edge streams through RabbitMQ/Broadway with demand, acknowledgements, tenant validation, idempotency, and DLQ handling.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Java
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: Level 4: Open Core Infrastructure
  • Curriculum Difficulty: Level 4: Advanced
  • Knowledge Area: Durable brokers, acknowledgements, security, chaos observability
  • Software or Tool: RabbitMQ, Broadway, Phoenix.PubSub, Telemetry
  • Main Book: “Enterprise Integration Patterns” by Hohpe & Woolf

What you will build: Bridge selected edge streams through RabbitMQ/Broadway with demand, acknowledgements, tenant validation, idempotency, and DLQ handling.

Why it teaches the BEAM ecosystem: It makes you prove that WAN slowdown and redelivery cause no leak or duplicate effect.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Integrated Scope

This is one consolidated project, not separate source builds. Implement the following contributions as phases of the same artifact:

  • Build BEAM-P13 federated edge routing and bounded WAN behavior.
  • Add PUB-P11 tenant validation, acknowledgements, idempotency, dead-letter handling, and redelivery tests.

Real World Outcome

Build target: Bridge selected edge streams through RabbitMQ/Broadway with demand, acknowledgements, tenant validation, idempotency, and DLQ handling.

Build a disposable RabbitMQ environment, a confirmed test publisher, a Broadway ingestion pipeline, a PostgreSQL projection/inbox store, a dead-letter quarantine, Phoenix.PubSub refreshes, and an operator dashboard.

Tenant 42’s publisher credential can publish only to the intended exchange/vhost scope. Events carry a versioned envelope and routing key. The consumer derives its authorized tenant context from queue binding/configuration, compares it with the routing key and envelope, validates schema and size, and opens a projection transaction.

The projection transaction records {tenant_id, event_id, consumer} uniquely, verifies the payload digest, and applies a monotonic resource revision. Only after commit does the edge emit a compact PubSub refresh and allow successful acknowledgement. A crash switch after projection commit but before acknowledgement proves safe redelivery.

The dashboard shows ready, unacknowledged, confirmed, redelivered, rejected, DLQ, processor latency, projection latency, PubSub refresh, and end-to-end event age. Chaos controls kill a processor, publish an unsupported schema, forge tenant combinations, and pause the broker.

$ mix broker.edge.drill
topology exchange=tenant.events queue=edge.tenant42 type=quorum durable=true PASS
publish event=evt-901 tenant=42 confirm=ack routed=1
consume event=evt-901 redelivered=false schema=1 tenant_check=PASS
projection event=evt-901 revision=71 result=applied
pubsub topic=tenant:42:device:abc refresh_revision=71 sent=1
consumer_ack event=evt-901 result=success

inject fault=crash_after_projection_before_ack event=evt-902
redelivery event=evt-902 redelivered=true projection=already_applied
pubsub refresh=coalesced consumer_ack=success effective_projections=1

publish event=evt-903 schema=99
classification=permanent reason=unsupported_schema requeue=false dlq_count=1

publish event=evt-904 credential_tenant=42 routing_tenant=42 payload_tenant=77
authorization=DENY projection_changes=0 pubsub_deliveries=0

broker paused duration=45s ready=12400 unacked=0
beam_mailbox_max=72 processor_status=waiting alert=UPSTREAM_LAG
broker resumed drained_in=38.4s duplicate_effects=0
drill result=PASS

Open the operator dashboard beside RabbitMQ’s management view. Publish evt-901 with tenant 42 credentials. The publisher panel shows one positive confirm; RabbitMQ briefly shows ready/unacknowledged movement; the projection table advances device abc to revision 71; and the authorized tenant-42 LiveView refreshes. Tenant 77’s board remains unchanged.

Trigger the processor crash after evt-902 commits. The RabbitMQ delivery remains unacknowledged until the connection closes and is then redelivered. The dashboard shows redelivered=true, two processing attempts, one inbox record, one projection effect, and a coalesced or repeated harmless UI refresh.

Publish schema 99. It appears exactly once in the DLQ with unsupported_schema; it does not hot-loop. Publish a payload claiming tenant 77 through tenant 42’s route. The authorization card shows denial, and automated probes confirm no tenant-77 database row, PubSub event, metric label, or sensitive log entry was created.

Pause RabbitMQ or disconnect the application. The ready count grows at the broker while Broadway and BEAM mailbox bounds remain stable. Resume the broker and watch bounded consumers drain backlog. The final report separates upstream backlog, consumer in-flight work, processor latency, PubSub refresh age, and duplicate-effect count.

The Core Question You Are Answering

“How do durable broker guarantees terminate safely at an Elixir application and become transient UI fanout without leaking tenants or duplicating effects?”

Answer by naming the responsibility transfer at confirm, delivery, projection commit, consumer acknowledgement, and PubSub refresh. If your answer says “the event is delivered exactly once,” replace it with the observed delivery and effect semantics.

Concepts You Must Understand First

  1. Publisher confirms
    • When has the broker accepted responsibility?
    • How do mandatory returns and confirms differ for unroutable messages?
    • Reference: RabbitMQ Consumer Acknowledgements and Publisher Confirms.
  2. Manual consumer acknowledgements
    • Why must acknowledgement happen on the delivery’s channel/context?
    • What happens to unacknowledged messages after connection loss?
    • Reference: RabbitMQ reliability and acknowledgements guides.
  3. Broadway demand and acknowledgers
    • Where do successful and failed messages terminate?
    • Which connector/source policy supplies retries?
    • Reference: Broadway and Broadway.Acknowledger documentation.
  4. Idempotent Receiver
    • Which durable unique key turns redelivery into one effect?
    • How will conflicting event-ID reuse be detected?
    • Book Reference: “Enterprise Integration Patterns” — Idempotent Receiver.
  5. Tenant authorization
    • Which context is authenticated, and which tenant fields are merely claims?
    • How are PubSub topics derived server-side?
    • Reference: OWASP authorization guidance and Phoenix LiveView security model.

Questions to Guide Your Design

  1. Topology and responsibility
    • Which queue type and durability settings match the lab’s guarantee?
    • What does a positive publisher confirm actually prove?
  2. Capacity
    • How do prefetch, Broadway demand, processor concurrency, and DB pool size relate?
    • Where should backlog remain during downstream slowdown?
  3. Failure policy
    • Which outcomes requeue, dead-letter, quarantine, or page an operator?
    • What prevents requeue storms?
  4. Tenant isolation
    • Which independent tenant values must agree?
    • Could metrics, logs, or DLQ tooling expose cross-tenant data even if projection is safe?
  5. PubSub handoff
    • Is refresh sent before or after durable projection commit?
    • How does a missed refresh repair on reconnect?

Thinking Exercise

Trace one event through this chain:

publisher intent -> TCP write -> broker confirm -> ready queue -> delivery
-> Broadway demand -> validation -> projection transaction -> PubSub refresh
-> consumer acknowledgement -> broker deletion

Place a crash before and after every arrow. For each point, predict:

  • whether the publisher retransmits;
  • whether RabbitMQ redelivers;
  • whether the projection exists;
  • whether the UI may have refreshed;
  • whether a duplicate effect can occur;
  • which durable evidence resolves uncertainty.

Then repeat with mismatched credential tenant, routing tenant, payload tenant, and database tenant.

The Interview Questions They Will Ask

  1. “What is the difference between publisher confirms and consumer acknowledgements?”
  2. “Why does RabbitMQ at-least-once delivery require idempotency?”
  3. “Does Broadway implement retries, and who decides failed-message behavior?”
  4. “How do prefetch and Broadway demand prevent overload?”
  5. “What belongs in a dead-letter queue, and how is it replayed safely?”
  6. “How do you prevent forged broker tenant data from reaching a Phoenix topic?”

Hints in Layers

Hint 1: Build the failure table before the pipeline

List every outcome with ack, requeue, dead-letter, or security quarantine. Make ambiguous cases explicit.

Hint 2: Acknowledge after the durable boundary

The reference durable boundary is the committed inbox/projection transaction. PubSub refresh is best-effort and does not delay broker acknowledgement indefinitely.

Hint 3: Validate tenant from both directions

Compare authenticated queue/credential context with routing key and envelope. Derive the final PubSub topic from the validated server context.

Hint 4: Make backlog visible where it belongs

Pause processors and confirm ready messages rise at RabbitMQ while BEAM mailbox length stays bounded.

Books That Will Help

Topic Book Chapter / Pattern
Messaging guarantees “Enterprise Integration Patterns” Messaging Channels, Guaranteed Delivery, Idempotent Receiver
Streams and redelivery “Designing Data-Intensive Applications, 2nd Edition” Stream Processing
Service boundaries “Building Microservices, 2nd Edition” Asynchronous Communication
Stability and capacity “Release It!, 2nd Edition” Stability Patterns

Implementation Milestones

Integrated basic-to-advanced progression

  1. Build BEAM-P13 federated edge routing and bounded WAN behavior.
  2. Add PUB-P11 tenant validation, acknowledgements, idempotency, dead-letter handling, and redelivery tests.

Milestone 1 — Contract and fixture: define one representative input, output, invariant, and failure case.

Milestone 2 — Core artifact: Bridge selected edge streams through RabbitMQ/Broadway with demand, acknowledgements, tenant validation, idempotency, and DLQ handling.

Milestone 3 — Failure behavior: add timeouts, invalid inputs, crashes, retries, or partitions appropriate to the project.

Milestone 4 — Evidence: automate the definition of done and record a reproducible result.

Phase 1: Broker Responsibility and Contract Validation (8–12 hours)

Goals

  • Provision durable topology and confirmed publishing.
  • Validate event and tenant contracts before effects.

Tasks

  1. Document exchange, queue, binding, DLX, persistence, and credential scopes.
  2. Implement a confirmed test publisher with correlation evidence.
  3. Define versioned envelope and size limits.
  4. Build tenant-agreement and schema test matrices.
  5. Verify mandatory/unroutable and negative/timeout publication paths.

Checkpoint: Valid events are confirmed and routed; unroutable and forged events have deterministic, distinct outcomes with no projection.

Phase 2: Bounded Processing and Idempotent Projection (10–16 hours)

Goals

  • Process under explicit demand and acknowledgement.
  • Prove redelivery yields one effect.

Tasks

  1. Configure prefetch, demand, concurrency, and database pool budgets.
  2. Add inbox/projection transaction and digest conflict check.
  3. Configure explicit acknowledgement/failure policy.
  4. Inject crash after projection before ack.
  5. Add compact PubSub refresh after commit.

Checkpoint: evt-902 is delivered at least twice, projected once, acknowledged successfully, and never leaks to another tenant.

Phase 3: Quarantine, Outage, and Operational Evidence (10–16 hours)

Goals

  • Make poison handling and backlog operable.
  • Certify the edge under failures.

Tasks

  1. Add DLQ inspection and audited replay/discard workflow.
  2. Instrument confirms, ready/unacked, redelivery, DLQ, stage latency, projection, and PubSub age.
  3. Pause broker and processors under fixed-rate publishing.
  4. Run cross-tenant probes across data, UI, logs, and metrics.
  5. Produce the responsibility-chain and chaos report.

Checkpoint: Broker outage creates bounded upstream lag, recovery drains predictably, poison work is quarantined once, and observed tenant leaks remain zero.

Testing Strategy

6.1 Test Categories

Category Purpose Examples
Contract Validate envelope and versioning Size, required fields, unsupported schema
Broker integration Verify confirms and acknowledgements Ack/nack/return, connection loss, redelivery
Projection integration Verify idempotency and ordering Duplicate event, digest conflict, stale revision
Broadway capacity Verify bounds Prefetch, demand, slow database, processor crash
Tenant isolation Verify fail-closed routing Credential/routing/payload/database matrix
DLQ operations Verify quarantine lifecycle Poison event, inspect, repair, replay, discard
End-to-end Verify broker-to-UI journey Confirm through authorized LiveView reload
Chaos Verify recovery Broker pause, app kill, DB outage, subscriber slowdown

6.2 Critical Test Cases

  1. Confirmed valid publish: Publisher receives positive confirm and exactly one queue receives the event.
  2. Unroutable mandatory publish: Return and confirm semantics are recorded without pretending a consumer exists.
  3. Normal consume: Projection commits before successful acknowledgement.
  4. Crash after projection: Delivery redelivers and inbox returns already_applied.
  5. Duplicate ID/different body: Digest conflict fails closed and alerts.
  6. Unsupported schema: One dead-letter outcome, no requeue loop.
  7. Transient database outage: Delivery remains recoverable and later succeeds with the same ID.
  8. Tenant mismatch matrix: Every mismatch creates zero projection and zero PubSub delivery.
  9. Stale revision: Classified according to documented skip/reconcile policy.
  10. Broker pause: Ready backlog rises while application in-flight/mailbox bounds hold.
  11. Slow subscriber: Broker/projection succeeds; PubSub lag is separately visible and bounded.
  12. DLQ replay: Repaired event preserves original ID and operator audit identity.

6.3 Test Data

authorized_context:
  vhost=/edge-lab
  queue=edge.tenant42
  credential_tenant=42

valid_event:
  event_id=evt-901
  tenant_id=42
  type=device.status_changed
  schema_version=1
  resource=device:abc
  revision=71
  payload={status: degraded}

redelivery_event: evt-902 revision=72 fault=after_projection_before_ack
poison_event: evt-903 schema_version=99 expected=DLQ
forged_event: evt-904 routing_tenant=42 payload_tenant=77 expected=DENY
identity_conflict: evt-901 altered_resource=device:xyz expected=SECURITY_ALERT

load:
  rate=500 events/second
  duration=60 seconds
  max_payload=64 KiB
  prefetch=100
  processor_concurrency=10

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Pitfall Symptom Solution
Treating confirm as end-to-end success Publisher says success while projection is absent Name broker acceptance separately from consumer effect
Ack before commit Crash loses uncommitted projection permanently Ack only after durable effect
Requeue every failure Poison message consumes the queue repeatedly Classify permanent failures and dead-letter
Memory-only dedupe Duplicates reapply after restart Persist inbox key and digest
Unlimited prefetch App memory/mailboxes grow under slow DB Bound prefetch and Broadway demand
Trust routing tenant Forged payload reaches another tenant Cross-check authenticated context and derive topic server-side
High-cardinality metrics Metrics backend cost explodes Keep event IDs in traces/logs, not metric labels
Blind DLQ replay Bad event loops again or changes identity Repair with audit, preserve ID, validate before replay

7.2 Debugging Strategies

  • Follow one event ID across publish intent, confirm, queue delivery, inbox, projection, refresh, and ack.
  • Compare ready vs unacked: ready indicates queued backlog; unacked indicates in-flight consumer responsibility.
  • Inspect redelivered flag and attempt history before blaming the publisher for duplicates.
  • Check connector acknowledgement configuration because Broadway failure alone does not define broker retry.
  • Freeze the database to see whether demand/prefetch boundaries keep application memory stable.
  • Run the tenant matrix whenever routing, envelope, or authorization code changes.
  • Examine DLQ reason codes rather than replaying raw entries until one succeeds.

7.3 Performance Traps

  • Prefetch far above useful concurrency increases redelivery and memory cost during consumer failure.
  • Batching unrelated tenants can create fairness and isolation problems.
  • Large payload decoding before size checks exposes CPU and memory denial of service.
  • Synchronous PubSub/UI work before broker acknowledgement lengthens unacked time unnecessarily.
  • Per-event metric labels overwhelm telemetry backends; use trace correlation instead.
  • Hot retry without backoff amplifies database or broker recovery pressure.

Definition of Done

Minimum Viable Completion

  • One confirmed tenant event is consumed, projected durably, acknowledged, and refreshed through PubSub.
  • A duplicate delivery produces one projection effect.
  • An unsupported schema reaches a DLQ.
  • One forged tenant event produces zero projection and zero UI delivery.
  • Prefetch and Broadway demand are explicitly bounded.

Full Completion

  • All minimum criteria plus confirm-return/timeout handling, digest conflict detection, monotonic revisions, and audited DLQ replay/discard.
  • Processor crash after projection causes safe redelivery.
  • Broker and processor outage drills separate ready, unacked, stage, mailbox, and UI lag.
  • Cross-tenant tests cover credentials, routing, payload, database, PubSub, logs, metrics, and quarantine tooling.
  • A redacted end-to-end report traces immutable event IDs through every responsibility boundary.

Excellence (Going Above & Beyond)

  • Upstream transactional outbox and publisher confirms are connected and failure-tested.
  • Broker-node failure and quorum recovery meet documented RTO/RPO expectations.
  • OpenTelemetry traces span publisher, RabbitMQ, Broadway, PostgreSQL, PubSub, and LiveView.
  • A capacity model predicts safe rate, in-flight limits, drain time, and alert thresholds and matches load evidence.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • Every merged source contribution is implemented as a phase of this one artifact, not as a separate project.
  • WAN slowdown and redelivery cause no leak or duplicate effect.

Project 136: Production-Ready BEAM Message Queue

Source: ERL-P19. Build a Mini-RabbitMQ with framing, exchanges, queues, acknowledgements, persistence, flow control, clustering, and operations tooling.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Erlang
  • Alternative Programming Languages: None (this should be pure Erlang)
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: Level 4: Open Core Infrastructure
  • Curriculum Difficulty: Level 4: Advanced
  • Knowledge Area: Distributed Systems / Message Queues
  • Software or Tool: RabbitMQ (as inspiration)
  • Main Book: “RabbitMQ in Action” by Videla & Williams (for concepts)

What you will build: Build a Mini-RabbitMQ with framing, exchanges, queues, acknowledgements, persistence, flow control, clustering, and operations tooling.

Why it teaches the BEAM ecosystem: It makes you prove that crash and node-failure tests meet declared durability guarantees.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Build a Mini-RabbitMQ with framing, exchanges, queues, acknowledgements, persistence, flow control, clustering, and operations tooling.

# Start a 3-node cluster
$ ./emq start node1 5672
$ ./emq join node2 5673 node1
$ ./emq join node3 5674 node1

# CLI management
$ ./emq-admin status
Cluster: 3 nodes
  node1@localhost: running, 12 queues, 45MB memory
  node2@localhost: running, 8 queues, 32MB memory
  node3@localhost: running, 10 queues, 38MB memory

$ ./emq-admin declare-exchange events topic
$ ./emq-admin declare-queue user-events --durable
$ ./emq-admin bind user-events events "user.*"

# Producer (in Erlang shell)
1> {ok, Conn} = emq_client:connect("localhost", 5672).
2> emq_client:publish(Conn, "events", "user.created", <<"User 123 created">>).
ok

# Consumer (separate shell)
1> {ok, Conn} = emq_client:connect("localhost", 5672).
2> emq_client:subscribe(Conn, "user-events", fun(Msg) ->
     io:format("Got: ~p~n", [Msg]),
     ack
   end).

Got: {message, <<"user.created">>, <<"User 123 created">>}

# Kill node2
$ ./emq stop node2

# Messages automatically route through remaining nodes
# Queues on node2 failover to node1 and node3

The Core Question You Are Answering

“How can Production-Ready BEAM Message Queue deliver its observable outcome while proving that crash and node-failure tests meet declared durability guarantees.”

Concepts You Must Understand First

  • Exchange/Queue/Binding model → maps to domain modeling
  • Message persistence → maps to Mnesia transactions
  • Consumer management → maps to process monitoring
  • Acknowledgment tracking → maps to state machines
  • Clustering → maps to distributed Erlang + Mnesia
  • Backpressure → maps to flow control
  • Admin API → maps to Cowboy REST
  • Metrics → maps to counters + observers

Questions to Guide Your Design

  1. Which input and output contracts must remain stable across refactoring?
  2. Where should validation happen, and how will expected failures be represented?
  3. Which component owns mutable state or external effects, and what happens when it dies?
  4. What independent evidence proves this mastery condition: crash and node-failure tests meet declared durability guarantees.

Thinking Exercise

Draw Production-Ready BEAM Message Queue as an input → decision/state → effect → evidence pipeline.

Mark every failure boundary, retry boundary, and durable state transition. Then inject one failure at each boundary and predict the observable result before implementing it.

The Interview Questions They Will Ask

  1. “What is the hardest invariant in Production-Ready BEAM Message Queue, and where is it enforced?”
  2. “Which parts should be pure transformations and which require BEAM processes?”
  3. “How does the design behave under malformed input, process failure, or retry?”
  4. “What test or runtime evidence proves: crash and node-failure tests meet declared durability guarantees.”

Hints in Layers

This project should use all the patterns you’ve learned:

Supervision tree:

                        ┌──────────────────┐
                        │   emq_sup        │
                        │ (top supervisor) │
                        └────────┬─────────┘
           ┌────────────────────┬┴────────────────────┐
           ▼                    ▼                     ▼
    ┌──────────────┐    ┌──────────────┐     ┌───────────────┐
    │ exchange_sup │    │  queue_sup   │     │ connection_sup│
    │(one_for_one) │    │(simple_1_1)  │     │ (simple_1_1)  │
    └──────────────┘    └──────────────┘     └───────────────┘

Message flow (as gen_statem):

    PUBLISH                   ROUTE                    DELIVER
 ┌───────────┐          ┌──────────────┐          ┌────────────┐
 │ Exchange  │ ────────►│   Queue      │ ────────►│  Consumer  │
 │ (gen_srv) │ bindings │ (gen_statem) │ msgs     │ (gen_srv)  │
 └───────────┘          └──────────────┘          └────────────┘
                              │
                              ▼ persist
                        ┌──────────┐
                        │  Mnesia  │
                        └──────────┘

Queue states (gen_statem): Implementation is intentionally left as pseudocode; use the surrounding contract, milestones, and tests to build it yourself.

Hint 1: Starting Point Implement the narrowest happy path for: Build a Mini-RabbitMQ with framing, exchanges, queues, acknowledgements, persistence, flow control, clustering, and operations tooling.

Hint 2: Next Level Separate parsing, validation, and transition decisions from effects so each can be tested directly.

Hint 3: Technical Details Represent expected failures as tagged outcomes and keep state ownership explicit; write only structural pseudocode before implementation.

Hint 4: Tools and Debugging Inject one failure at a time, correlate it with bounded telemetry, and save a deterministic transcript as evidence.

Books That Will Help

  • Main Book: “RabbitMQ in Action” by Videla & Williams (for concepts)

Implementation Milestones

  1. Single-node pub/sub works → Basic architecture done
  2. Persistence survives restart → Mnesia integration works
  3. Clustering works → Distributed Erlang mastered
  4. Handles 10K messages/second → Performance acceptable
  5. Node failure handled gracefully → Production-ready

Testing Strategy

  • Unit checks: pure parsing, validation, transition, and formatting decisions.
  • Integration checks: the real process, database, socket, notebook, or framework boundary.
  • Failure checks: malformed input plus at least one crash, timeout, duplicate, overload, or partition scenario.
  • Acceptance check: independently demonstrate that crash and node-failure tests meet declared durability guarantees.
  • Avoid arbitrary sleeps; use messages, monitors, deterministic clocks, fixtures, and deadlines where applicable.

Common Pitfalls and Debugging

Problem 1: Happy-path output looks correct but failures disappear

  • Why: validation, effects, and reporting share one opaque step.
  • Fix: preserve tagged errors and source identity through every stage.
  • Quick test: inject one invalid record or failed dependency and verify an explicit result.

Problem 2: Tests merely repeat the implementation

  • Why: assertions reuse the same transformation or state assumptions.
  • Fix: check external invariants, golden fixtures, and observable failure behavior.
  • Quick test: introduce a deliberate ordering or boundary bug and confirm the test fails.

Definition of Done

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • crash and node-failure tests meet declared durability guarantees.

Phase 8 - Advanced Architecture and Capstones

Project 137: Multi-Tenant Dynamic Repo Control Plane

Source: BEAM-P31. Start, limit, observe, and retire tenant-specific Ecto Repos under dynamic supervision.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: Level 5: Industry Disruptor
  • Curriculum Difficulty: Level 5: Expert
  • Knowledge Area: Multi-Tenancy, Resource Control
  • Software or Tool: DynamicSupervisor, Registry, Ecto.Repo
  • Main Book: “Software Architecture in Practice”

What you will build: Start, limit, observe, and retire tenant-specific Ecto Repos under dynamic supervision.

Why it teaches the BEAM ecosystem: It makes you prove that one tenant outage cannot exhaust others.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Start, limit, observe, and retire tenant-specific Ecto Repos under dynamic supervision.

Build a control-plane application that stores tenant connection metadata separately from tenant data, starts Ecto Repo instances on demand, grants generation-bound leases, scopes dynamic repo routing, enforces a global connection budget, drains idle repos, and runs resumable migration campaigns.

$ tenantctl acquire T-204
tenant=T-204 generation=8 state=ready repo_pid=<0.481.0> lease=L-991

$ tenantctl capacity
repos ready=8 starting=1 draining=1 failed=2
connections allocated=45 budget=50 startup_reserved=5 waiters=3
eviction_candidate=T-099 idle=43m leases=0 pinned=false

3.7.1 How to Run

$ mix deps.get
$ mix test
$ mix tenant.demo --tenants 20 --connection-budget 25 --concurrency 100

3.7.2 Golden Path Demo

One hundred concurrent operations target twenty tenants while only five pools of five connections may be allocated. The control plane shares same-tenant starts, leases ready repos, evicts only zero-lease idle candidates, and completes operations without reading any wrong-tenant sentinel.

3.7.3 Exact Terminal Transcript

$ mix tenant.demo --tenants 20 --connection-budget 25 --concurrency 100
operations=100 succeeded=100 tenant_bleed=0
repo_starts=20 shared_start_waiters=37 duplicate_starts=0
max_connections_allocated=25 budget=25 violations=0
evictions=15 active_repo_evictions=0
stale_generation_retries=2
result=PASS

The Core Question You Are Answering

“How can one BEAM application safely operate thousands of isolated tenant databases when only a bounded subset may hold live pools at once?”

Concepts You Must Understand First

  1. Ecto Repo lifecycle, pool behavior, transactions, and migrations.
  2. Process-local dynamic repo selection and cleanup.
  3. DynamicSupervisor, Registry, monitors, and generation identity.
  4. Resource leasing, draining, capacity reservation, and backoff.
  5. Database-per-tenant migration compatibility.

Questions to Guide Your Design

  1. Which process proves tenant authorization before routing?
  2. How are Tasks and durable jobs forced to re-establish context?
  3. What exact resource does the global budget count?
  4. How can eviction race with acquisition without killing active work?
  5. Which application versions can operate each schema version during a campaign?

Thinking Exercise

Trace three simultaneous requests for a stopped tenant while capacity is full. One idle repo is eligible, one repo has a long transaction, and one is migrating. Identify the only legal victim, when the startup reservation is made, and what each waiter sees if startup fails.

The Interview Questions They Will Ask

  1. “How does put_dynamic_repo scope repository selection?”
  2. “Why is process dictionary routing dangerous across Tasks?”
  3. “How do you prevent two first requests from starting two pools?”
  4. “What proves a repo is safe to evict?”
  5. “How would you rotate credentials without interrupting transactions?”
  6. “How do expand/contract migrations apply to database-per-tenant SaaS?”

Hints in Layers

Hint 1: Make missing context fail — Tenant-scoped modules should not quietly use the default repo.

Hint 2: Lease generations — A tenant ID alone cannot prove that a PID is still the current repo.

Hint 3: Drain before stop — Atomically block new leases, then wait for existing leases to reach zero.

Hint 4: Campaigns are data — Persist per-tenant migration state so a control-plane restart can resume safely.

Books That Will Help

Topic Book Precise reading
Ecto repositories Programming Ecto — Darin Wilson and Eric Meadows-Jönsson Chapters on repositories, queries, transactions, and Multi
Multi-tenancy Programming Ecto Chapter/section “Multi-Tenancy with Query Prefixes,” contrasted with database-per-tenant dynamic repos
Process topology Elixir in Action, 3rd ed. — Saša Jurić Chapters 7 “Building a Concurrent System” and 9 “Isolating Error Effects”
Resource thinking Designing for Scalability with Erlang/OTP Chapters on supervision architectures and overload protection

Implementation Milestones

Phase 1: Safe Routing Boundary (5-8 hours)

  • Create catalog, internal tenant identity, and context API.
  • Add exact previous-repo restoration and nesting policy.
  • Prove Tasks require explicit tenant propagation.

Phase 2: Lifecycle and Leases (7-11 hours)

  • Add single-flight repo startup and generation identity.
  • Grant monitored leases and recover leaked owners.
  • Handle repo death and stale-generation retry.

Phase 3: Capacity and Eviction (6-10 hours)

  • Budget pools and startup reservations.
  • Add bounded admission, eligible-idle ordering, draining, and stop.
  • Run saturation and eviction race tests.

Phase 4: Fleet Migrations and Operations (6-11 hours)

  • Add resumable migration campaigns and compatibility checks.
  • Add credential rotation policy and failure backoff.
  • Build operator status and cardinality-safe metrics.

Testing Strategy

6.1 Test Categories

Category Purpose Examples
Isolation Prevent tenant bleed unique sentinels under concurrency
Context Verify routing cleanup exception, nested context, Task boundary
Lifecycle Validate state transitions concurrent start, repo death, retry backoff
Capacity Enforce hard budget saturation, reservation, rotation headroom
Lease/Eviction Protect active work long transaction, leaked owner, drain race
Migration Verify campaign recovery partial success, crash, version compatibility
Security Protect credentials and identity redaction, untrusted tenant reference, atom growth

6.2 Critical Test Cases

  1. Hundreds of mixed-tenant queries always return the correct unique sentinel.
  2. An exception restores the exact previous dynamic repo.
  3. A Task without explicit tenant context fails closed.
  4. Concurrent first requests produce one repo generation.
  5. Repo death invalidates leases and does not route to another tenant.
  6. Capacity never exceeds the budget during concurrent startup.
  7. A leased repo is never selected or stopped by eviction.
  8. New acquisition during draining cannot attach to the draining generation.
  9. Migration crash resumes from observed database version without blind reapplication.
  10. Arbitrary tenant strings do not create atoms or select connection parameters.

6.3 Test Data

Provision tenants with unmistakable sentinel rows and different schema versions. Use fake credential providers, controllable repo starters, monitored long transactions, leaked lease-owner processes, and migration fixtures with one intentional failure. Capture maximum simultaneous pool allocation during load tests.

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Problem Why it happens Fix Quick test
Cross-tenant query Missing context falls back to default Fail closed in tenant data modules Invoke without context
Outer routing lost Cleanup restores default, not previous Save and restore exact prior repo Nested-context fixture
Task uses wrong database Assumed process context inheritance Pass tenant ID and reacquire Spawn Task in tenant scope
Connection budget exceeded Starting repos not reserved Reserve pool cost before start Concurrent cold-start load
Active transaction killed LRU uses timestamp only Lease and drain before stop Hold transaction past idle timer
Startup storm Check-then-start race Serialize lifecycle single flight Launch simultaneous first requests

7.2 Debugging Strategies

  • Include tenant ID, repo generation, lease token hash, and operation correlation in debug traces.
  • Query lifecycle state and capacity ledger before inspecting low-level pool processes.
  • Verify the current dynamic repo at the entry to tenant data modules in test mode.
  • Monitor lease owners and log leaked-lease cleanup separately from normal release.
  • Compare catalog schema version, live database version, and campaign record when migration status disagrees.

7.3 Performance Traps

  • Starting large pools for low-traffic tenants
  • Serializing all tenants through one lifecycle process instead of per-tenant coordination plus a capacity authority
  • High-cardinality tenant labels on every global metric
  • Repeated credential fetch and TLS setup without bounded caching policy
  • Migrating too many databases concurrently

Definition of Done

  • Tenant identity is authenticated before catalog and runtime resolution.
  • Dynamic repo selection is always restored in cleanup.
  • Background processes re-enter context explicitly.
  • No adversarial concurrency test observes tenant bleed.
  • Same-tenant startup is single-flight and bounded.
  • Capacity counts pools/connections and never exceeds declared limits.
  • Eviction requires draining and zero leases for the exact generation.
  • Repo death, startup failure, and saturation have distinct retryable outcomes.
  • Migration campaigns resume and isolate per-tenant failure.
  • Credentials and high-cardinality identifiers are handled safely in observability.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • one tenant outage cannot exhaust others.

Project 138: Advanced BEAM Verification Lab

Source: PHX-P24. Build property, state-machine, concurrency, and distributed invariant tests.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: Level 5: Industry Disruptor
  • Curriculum Difficulty: Level 5: Expert
  • Knowledge Area: Advanced Testing
  • Software or Tool: ExUnit, StreamData, multi-node test harness
  • Main Book: StreamData docs + ExUnit docs

What you will build: Build property, state-machine, concurrency, and distributed invariant tests.

Why it teaches the BEAM ecosystem: It makes you prove that injected ordering, retry, crash, and partition bugs shrink reproducibly.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Build property, state-machine, concurrency, and distributed invariant tests.

Build invariant-focused testing layers using StreamData generators, orchestrated races, and multi-node fault scripts.

deterministic_outcome:

  • property suites pass with persisted seeds
  • race tests repeat deterministically
  • distributed reconciliation assertions stable

The Core Question You Are Answering

Can I prove important invariants survive random input, races, and partitions?

Concepts You Must Understand First

  • BEAM process model and failure isolation
  • OTP supervision semantics
  • Runtime observability discipline

Questions to Guide Your Design

  1. What is your safety invariant?
  2. What is your bounded recovery target?
  3. What is your fallback behavior under stress?

Thinking Exercise

Choose one invariant and describe how it could fail under replay, race, and partition separately.

The Interview Questions They Will Ask

  1. What tradeoff did you choose and why?
  2. How do you prove correctness under failure?
  3. Which metric is your leading indicator of incident risk?
  4. “Which measurement would tell you that Advanced BEAM Verification Lab is approaching its operating limit?”

Hints in Layers

Hint 1: Starting Point Start with one invariant that matters to money or data integrity.

Hint 2: Next Level Build generators for both valid and malformed inputs.

Hint 3: Technical Details Record failing seeds and minimize counterexamples automatically.

Hint 4: Tools/Debugging Use structured logs tagged with test run id and seed.

Books That Will Help

Topic Book Chapter
Property testing StreamData docs Generators and properties
Test harness design ExUnit docs Async, tags, setup/teardown

Implementation Milestones

  1. Baseline behavior validated.
  2. Instrumentation and dashboards available.
  3. Fault injection and recovery validated.
  4. Final report with tradeoffs and next steps.

Testing Strategy

6.1 Test Strategy

  • Unit tests for core transitions
  • Integration tests for runtime flows
  • Fault scenario tests for recovery

6.2 Verification Steps

  • Run full test suite.
  • Run deterministic lab script.

Common Pitfalls and Debugging

Problem 1: “Property tests pass but bug still escaped”

  • Why: generators did not represent critical edge cases.
  • Fix: enrich generators with boundary and adversarial distributions.
  • Quick test: mutation run that intentionally breaks invariant path.

Problem 2: “Distributed tests flaky”

  • Why: timing-dependent assertions without deterministic control.
  • Fix: scripted barriers and explicit convergence windows.
  • Quick test: run suite 20x with fixed seed and compare outcomes.

Definition of Done

  • Core functionality works on reference scenarios.
  • Failure path behavior matches design policy.
  • SLO metrics are captured and reproducible.
  • Findings are documented with evidence.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • injected ordering, retry, crash, and partition bugs shrink reproducibly.

Project 139: BEAM Chaos and Resilience Engineering

Source: PHX-P23. Exercise bulkheads, breakers, supervision, overload, node loss, and recovery SLOs.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Shell
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: Level 5: Industry Disruptor
  • Curriculum Difficulty: Level 5: Expert
  • Knowledge Area: Reliability and Fault Tolerance
  • Software or Tool: chaos scripts, circuit breakers, retry policies
  • Main Book: “Release It!” by Michael Nygard

What you will build: Exercise bulkheads, breakers, supervision, overload, node loss, and recovery SLOs.

Why it teaches the BEAM ecosystem: It makes you prove that every drill has a bounded blast radius and measured recovery.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Exercise bulkheads, breakers, supervision, overload, node loss, and recovery SLOs.

Build a chaos harness to validate breaker, bulkhead, retry, and idempotency behavior under realistic faults.

deterministic_outcome:

  • chaos suite executes with safety stop conditions
  • duplicate replay does not duplicate side effects
  • degraded mode SLOs remain inside policy

The Core Question You Are Answering

What still works and stays correct when multiple failures overlap?

Concepts You Must Understand First

  • BEAM process model and failure isolation
  • OTP supervision semantics
  • Runtime observability discipline

Questions to Guide Your Design

  1. What is your safety invariant?
  2. What is your bounded recovery target?
  3. What is your fallback behavior under stress?

Thinking Exercise

Write a failure budget table for three dependencies: payments, notifications, analytics. Define expected behavior when each fails.

The Interview Questions They Will Ask

  1. What tradeoff did you choose and why?
  2. How do you prove correctness under failure?
  3. Which metric is your leading indicator of incident risk?
  4. “Which measurement would tell you that BEAM Chaos and Resilience Engineering is approaching its operating limit?”

Hints in Layers

Hint 1: Starting Point Define hypothesis and stop conditions for every experiment.

Hint 2: Next Level Tag every command with idempotency key at ingress.

Hint 3: Technical Details Store dedupe outcomes with TTL exceeding max retry horizon.

Hint 4: Tools/Debugging Correlate chaos events with SLO graph annotations.

Books That Will Help

Topic Book Chapter
Resilience patterns “Release It!” Stability patterns
Chaos methodology Principles of Chaos Engineering Entire principles page

Implementation Milestones

  1. Baseline behavior validated.
  2. Instrumentation and dashboards available.
  3. Fault injection and recovery validated.
  4. Final report with tradeoffs and next steps.

Testing Strategy

6.1 Test Strategy

  • Unit tests for core transitions
  • Integration tests for runtime flows
  • Fault scenario tests for recovery

6.2 Verification Steps

  • Run full test suite.
  • Run deterministic lab script.

Common Pitfalls and Debugging

Problem 1: “Chaos tests pass but incidents still bad”

  • Why: experiments did not reflect real failure modes.
  • Fix: derive scenarios from incident history and dependency graphs.
  • Quick test: compare experiment catalog against incident postmortems.

Problem 2: “Idempotency store grew uncontrollably”

  • Why: TTL too long without cleanup strategy.
  • Fix: partition and expire with bounded retention policy.
  • Quick test: run 24h simulation and verify bounded table growth.

Definition of Done

  • Core functionality works on reference scenarios.
  • Failure path behavior matches design policy.
  • SLO metrics are captured and reproducible.
  • Findings are documented with evidence.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • every drill has a bounded blast radius and measured recovery.

Project 140: Elite Runtime Primitives Workshop

Source: PHX-P26. Implement a custom behaviour, queue, CRDT, PubSub adapter, and TCP protocol server.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang, Rust
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: Level 5: Industry Disruptor
  • Curriculum Difficulty: Level 5: Expert
  • Knowledge Area: Elite Mode Topics
  • Software or Tool: custom OTP behaviour, custom adapter implementations
  • Main Book: OTP Design Principles

What you will build: Implement a custom behaviour, queue, CRDT, PubSub adapter, and TCP protocol server.

Why it teaches the BEAM ecosystem: It makes you prove that each primitive has a contract, failure model, compatibility suite, and performance envelope.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Implement a custom behaviour, queue, CRDT, PubSub adapter, and TCP protocol server.

Build custom runtime primitives: OTP behaviour, boot hook, PubSub adapter, queue, CRDT, rate limiter, and TCP protocol server.

deterministic_outcome:

  • adapters pass shared compliance suite
  • queue/CRDT/protocol survive stress and fault tests
  • telemetry remains consistent after adapter swaps

The Core Question You Are Answering

Can I design reusable runtime primitives with explicit contracts and measurable behavior?

Concepts You Must Understand First

  • BEAM process model and failure isolation
  • OTP supervision semantics
  • Runtime observability discipline

Questions to Guide Your Design

  1. What is your safety invariant?
  2. What is your bounded recovery target?
  3. What is your fallback behavior under stress?

Thinking Exercise

Write compatibility checklist for swapping one PubSub adapter implementation with another without code changes at call sites.

The Interview Questions They Will Ask

  1. What tradeoff did you choose and why?
  2. How do you prove correctness under failure?
  3. Which metric is your leading indicator of incident risk?
  4. “Which measurement would tell you that Elite Runtime Primitives Workshop is approaching its operating limit?”

Hints in Layers

Hint 1: Starting Point Define interfaces and invariants in docs before implementation.

Hint 2: Next Level Build one reference adapter and one alternative adapter.

Hint 3: Technical Details Add compliance test suite each adapter must pass.

Hint 4: Tools/Debugging Use protocol fuzzing for frame parser hardening.

Books That Will Help

Topic Book Chapter
Behaviour design OTP design principles Behaviours and applications
Protocol engineering TCP/IP references framing and reliability sections

Implementation Milestones

  1. Baseline behavior validated.
  2. Instrumentation and dashboards available.
  3. Fault injection and recovery validated.
  4. Final report with tradeoffs and next steps.

Testing Strategy

6.1 Test Strategy

  • Unit tests for core transitions
  • Integration tests for runtime flows
  • Fault scenario tests for recovery

6.2 Verification Steps

  • Run full test suite.
  • Run deterministic lab script.

Common Pitfalls and Debugging

Problem 1: “Adapters technically work but metrics mismatch”

  • Why: inconsistent telemetry schema across implementations.
  • Fix: define shared metric contract in behaviour spec.
  • Quick test: swap adapters and compare dashboard continuity.

Problem 2: “TCP parser fails under burst input”

  • Why: frame boundary assumptions invalid under partial reads.
  • Fix: implement buffered incremental parser.
  • Quick test: replay fragmented and concatenated frame streams.

Definition of Done

  • Core functionality works on reference scenarios.
  • Failure path behavior matches design policy.
  • SLO metrics are captured and reproducible.
  • Findings are documented with evidence.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • each primitive has a contract, failure model, compatibility suite, and performance envelope.

Project 141: Multi-Tenant Real-Time Operations Mesh

Sources: PUB-P12, PUB-CAP. Combine durable facts, outbox work, Pub/Sub UI refresh, Presence, bounded telemetry, brokers, and chaos recovery.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang services, TypeScript clients
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: Level 5: Industry Disruptor
  • Curriculum Difficulty: Level 5: Expert
  • Knowledge Area: Distributed architecture, real-time UX, durable integration, security, SRE
  • Software or Tool: Phoenix, LiveView, PubSub, Presence, Ecto, Oban/RabbitMQ, Broadway, Telemetry
  • Main Book: “Software Architecture in Practice, 4th Edition” by Bass et al.

What you will build: Combine durable facts, outbox work, Pub/Sub UI refresh, Presence, bounded telemetry, brokers, and chaos recovery.

Why it teaches the BEAM ecosystem: It makes you prove that certification shows no lost fact, duplicate effect, or tenant leak.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Integrated Scope

This is one consolidated project, not separate source builds. Implement the following contributions as phases of the same artifact:

  • Implement PUB-P12 durable facts, outbox handoff, Pub/Sub refresh, Presence, and broker boundaries.
  • Use PUB-CAP only as the certification phase: multi-node chaos, tenant isolation, and operational handoff.

Real World Outcome

Build target: Combine durable facts, outbox work, Pub/Sub UI refresh, Presence, bounded telemetry, brokers, and chaos recovery.

Build a fleet and incident operations platform for tenants 42 and 77. Each tenant has devices, incidents, responders, roles, integrations, and realtime boards. Three Phoenix application nodes serve users and run PubSub/Presence. PostgreSQL owns domain facts, revisions, tenant policy, outbox/inbox records, and durable projections. Oban or an outbox plus RabbitMQ/Broadway executes durable integrations. A bounded telemetry path updates current device gauges.

The reference journey is “incident severity raised.” An authorized command validates tenant and expected revision, commits revision 18 plus an immutable outbox event, and publishes a compact after-commit refresh. Online boards reload. A pager integration is delivered durably and idempotently. Presence helps show which responders may be available but does not assign ownership.

The platform includes a certification console that runs slow subscriber, application kill, node partition, broker pause, duplicate delivery, unsupported schema, and role-revocation drills. Each drill has predicted degraded status, quantitative SLOs, cross-tenant probes, and automated cleanup.

$ mix platform.certify --profile reference
EVENT PLATFORM — CHAOS CERTIFICATION
run=cert-2026-07-15-01 version=git:4ad2e8a nodes=3 tenants=2

normal_load:
  ui_event_age_p99=182ms target<500ms PASS
  mailbox_p99=44 bound<1000 PASS
  telemetry_received=500000 rendered=3000 coalesced=497000 PASS
  outbox_oldest=1.8s target<30s PASS

duplicate_delivery:
  broker_redeliveries=17 durable_effects=17 duplicate_effects=0 PASS

node_partition:
  components=[[alpha,beta],[gamma]]
  transient_revisions_missed=expected:23
  durable_facts_lost=0 PASS
  membership_convergence=6.2s target<35s PASS
  board_reload_latest_revision=PASS

role_revocation:
  sessions_targeted=6
  sensitive_delivery_after_deadline=0 PASS
  sensitive_actions_after_deadline=0 PASS

tenant_isolation:
  attempted_cross_tenant_paths=240 observed_leaks=0 PASS

sabotage_control disable_revision_reload:
  expected_certification_failure=true observed=true PASS

overall=PASS_WITH_DOCUMENTED_EPHEMERAL_LOSS

Open six browser sessions distributed across three application nodes: two tenant-42 operators, two tenant-77 operators, and two responder sessions. The tenant-42 board shows only its devices, incidents, current gauges, and responders. Tenant 77 has visually identical but independently scoped data. A topology panel identifies the serving node and current component without exposing privileged internals to ordinary users.

Raise incident 913 from severity 2 to 3. Both authorized tenant-42 boards update to revision 18. Tenant-77 boards show no event. The event-journey drawer traces command, transaction, outbox, PubSub refresh, broker integration, idempotent pager result, and audit record using the same event ID. Disconnect one tenant-42 board before the change; on reconnect it loads revision 18 from PostgreSQL and labels the repair source.

Feed high-rate gauges. The ingestion counter rises rapidly, while each board renders at a human-scale cadence. Cards show how many readings were coalesced and whether telemetry is fresh or degraded. Trigger a critical threshold event; it becomes a durable incident fact/work item rather than being lost as an optional gauge sample.

Run the chaos console. During gamma’s partition, boards in different components may miss transient revisions and Presence may diverge, but durable facts remain intact. After heal, topology and Presence converge and every board reloads the latest revision. Pause RabbitMQ; outbox/broker age turns amber while incident commands and local refresh continue according to policy. Resume it and watch backlog drain without duplicate pager effects.

Revoke a tenant-42 operator’s incident-management role while their LiveView remains connected. Within the measured deadline, sensitive subscriptions/actions stop, the UI downgrades or disconnects, and later broadcasts produce zero restricted content. The final certification report shows every SLO, expected degraded state, observed behavior, and sabotage control.

The Core Question You Are Answering

“Can I justify, observe, and recover every event boundary without using Pub/Sub as a universal substitute for state, work queues, authorization, or consensus?”

Answer with one complete event journey. For each arrow, name the plane, source of authority, delivery semantics, ordering scope, duplicate policy, tenant decision, capacity limit, observability signal, and recovery method. Any unnamed arrow is an unreviewed failure boundary.

Concepts You Must Understand First

  1. All prior Pub/Sub concepts
    • Can you distinguish raw process messages, Registry, Phoenix.PubSub, Presence, demand pipelines, outbox, and brokers?
    • Which earlier project provides evidence for each mechanism?
  2. Quality-attribute scenarios
    • What source, stimulus, artifact, environment, response, and measure define the scenario?
    • How will a threshold fail deterministically?
    • Book Reference: “Software Architecture in Practice, 4th Edition” — Quality Attributes.
  3. Multi-tenant authorization
    • Where does identity become trusted context?
    • How do connected sessions react to policy change?
    • Reference: Phoenix LiveView security model and OWASP authorization guidance.
  4. Durable event processing
    • Where are transactional handoff, publisher confirm, consumer ack, and idempotent effect?
    • Book Reference: “Enterprise Integration Patterns” — Guaranteed Delivery and Idempotent Receiver.
  5. Distributed convergence
    • Which views are transient/eventually consistent?
    • Which durable source repairs missed revisions?
    • Book Reference: “Designing Data-Intensive Applications, 2nd Edition” — distributed systems and streams.
  6. Capacity and stability
    • Which queues/buffers are bounded and which work degrades first?
    • Book Reference: “Release It!, 2nd Edition” — Stability Patterns.

Questions to Guide Your Design

  1. Plane ownership
    • If PubSub is disabled for one minute, which facts/work remain correct?
    • If RabbitMQ is paused, which commands and UI paths continue?
  2. Tenant isolation
    • Which helper makes an unscoped query/topic/job impossible or obvious?
    • How are tenant IDs represented in telemetry without leakage or cardinality explosion?
  3. Event semantics
    • Where can duplicates occur, and which durable key neutralizes each one?
    • What revision gaps are repairable from state versus event replay?
  4. Overload
    • Which optional updates are coalesced or sampled?
    • Which critical events must be rejected explicitly rather than silently dropped?
  5. Failure and recovery
    • Which operations continue during a node partition?
    • What evidence proves the user-facing board, not merely a process, recovered?
  6. Evolution
    • Can the work plane move from Oban to RabbitMQ without changing domain event identity?
    • Which automated fitness functions protect boundaries during that change?

Thinking Exercise

Create a full journey for “incident severity raised”:

browser command -> connected authorization -> domain decision -> DB transaction
-> domain event/outbox -> PubSub refresh -> LiveView reload
-> broker publication/confirm -> Broadway delivery -> integration effect/ack
-> Presence hint -> metrics/audit -> reconnect/replay

For every arrow, fill a table with:

  • source and destination plane;
  • tenant authority;
  • event identity and revision;
  • ordering guarantee;
  • loss and duplicate behavior;
  • capacity/buffer limit;
  • observability signal;
  • recovery source;
  • security/privacy classification.

Then remove PubSub, PostgreSQL, RabbitMQ, one application node, policy service, and one subscriber in turn. Predict continue, degrade, or fail closed before running any drill.

The Interview Questions They Will Ask

  1. “How do you choose between Phoenix.PubSub, Oban, GenStage/Broadway, and RabbitMQ?”
  2. “How does the platform recover after missing PubSub messages during a partition?”
  3. “Where can duplicates occur, and how do you prevent duplicate effects?”
  4. “How do you prevent cross-tenant leakage through topics, jobs, metrics, and logs?”
  5. “What happens when one subscriber or integration cannot keep up?”
  6. “Which evidence proves the platform meets its SLOs under chaos?”

Hints in Layers

Hint 1: Draw planes before components

Assign every flow to state, notification, work, or control. Only then select PostgreSQL, PubSub, Oban, RabbitMQ, or Telemetry.

Hint 2: Build one tenant end to end

Complete identity, revision, durability, reconnect, and SLO evidence for tenant 42. Add tenant 77 specifically to attack isolation assumptions.

Hint 3: Add failure before scale

Prove one post-effect duplicate, one missed refresh, and one revocation before increasing rates or node count.

Hint 4: Certification is the deliverable

Every drill needs a hypothesis, threshold, sabotage control, and cleanup assertion. A dashboard screenshot alone is not evidence.

Books That Will Help

Topic Book Chapter / Section
Quality attributes “Software Architecture in Practice, 4th Edition” Quality Attribute Scenarios
Evolution fitness “Building Evolutionary Architectures, 2nd Edition” Fitness Functions
Messaging boundaries “Enterprise Integration Patterns” Ch. 2–4; Guaranteed Delivery; Idempotent Receiver
Data and distribution “Designing Data-Intensive Applications, 2nd Edition” Transactions, Distributed Systems, Streams
Stability “Release It!, 2nd Edition” Stability Patterns and Production
Service architecture “Building Microservices, 2nd Edition” Coupling and Asynchronous Communication

Implementation Milestones

Integrated basic-to-advanced progression

  1. Implement PUB-P12 durable facts, outbox handoff, Pub/Sub refresh, Presence, and broker boundaries.
  2. Use PUB-CAP only as the certification phase: multi-node chaos, tenant isolation, and operational handoff.

Milestone 1 — Contract and fixture: define one representative input, output, invariant, and failure case.

Milestone 2 — Core artifact: Combine durable facts, outbox work, Pub/Sub UI refresh, Presence, bounded telemetry, brokers, and chaos recovery.

Milestone 3 — Failure behavior: add timeouts, invalid inputs, crashes, retries, or partitions appropriate to the project.

Milestone 4 — Evidence: automate the definition of done and record a reproducible result.

Phase 1: One-Tenant Vertical Slice (16–24 hours)

Goals

  • Establish state, identity, revision, and realtime reload boundaries.
  • Produce one complete incident journey.

Tasks

  1. Model tenant, incident, device, responder, membership, and policy constraints.
  2. Implement authenticated/authorized connected board lifecycle.
  3. Add command transaction, domain event, and atomic durable handoff.
  4. Add compact PubSub refresh and reconnect/gap reload.
  5. Trace one event ID through the journey.

Checkpoint: Tenant 42 raises severity, two boards reach revision 18, a disconnected board catches up, and durable integration responsibility remains queryable.

Phase 2: Isolation, Presence, and Bounded Telemetry (16–24 hours)

Goals

  • Add a hostile second tenant and distributed awareness.
  • Protect capacity under high-rate input.

Tasks

  1. Seed tenant 77 with deliberately overlapping resource IDs.
  2. Add cross-tenant query/topic/job/cache/log/metric tests.
  3. Add Presence with freshness and convergence labeling.
  4. Build bounded telemetry coalescing and critical-transition promotion.
  5. Add role revocation and connected-session enforcement.

Checkpoint: 240 cross-tenant probes observe zero leaks; high-rate telemetry remains bounded; critical transitions persist; revocation meets deadline.

Phase 3: Durable Broker Integration and Three Nodes (16–28 hours)

Goals

  • Extend work across a durable broker boundary.
  • Exercise distributed PubSub and Presence behavior.

Tasks

  1. Start three application nodes and prove topology.
  2. Add confirmed broker publication and Broadway consumption.
  3. Add durable inbox/idempotent integration effect and DLQ.
  4. Inject duplicate delivery and processor/app restarts.
  5. Partition one node and verify transient loss plus durable recovery.

Checkpoint: Broker redeliveries create zero duplicate effects; partitioned boards reload latest facts; Presence converges within budget.

Phase 4: SLOs, Chaos, and Certification (12–24 hours)

Goals

  • Turn architectural claims into automated evidence.
  • Produce operations and review artifacts.

Tasks

  1. Define reference load and quality-attribute scenarios.
  2. Instrument latency, mailbox, outbox/broker, Presence, isolation, and revocation measures.
  3. Automate slow subscriber, node kill/partition, broker pause, duplicate, poison, and revocation drills.
  4. Add sabotage controls and idempotent cleanup.
  5. Publish architecture, threat, capacity, runbook, and certification documents.

Checkpoint: The complete certification passes with documented ephemeral loss, and disabling each selected recovery mechanism causes the related scenario to fail.

Testing Strategy

6.1 Test Categories

Category Purpose Examples
Domain Preserve business invariants Revision conflict, policy denial, atomic event handoff
Authorization/isolation Prevent tenant leakage Connected mount, topic, query, job, broker, logs, metrics
Realtime Verify transient semantics Two clients, stale message, revision gap, reconnect
Presence Verify awareness convergence Join/leave, node kill, partition/heal, stale metadata
Capacity Verify bounded behavior High-rate gauges, slow subscriber, DB/broker slowdown
Durable work Verify restart/idempotency Outbox restart, broker redelivery, DLQ, replay
Distributed Verify component behavior Three-node topology, node kill, network partition
Revocation Verify temporal authorization Role removal while sockets/jobs remain active
Chaos/SLO Verify measurable resilience Fault hypothesis, threshold, recovery, sabotage control
Privacy Verify evidence safety Payload/log/trace/DLQ export redaction

6.2 Critical Test Cases

  1. Atomic incident change: Revision and durable handoff commit or roll back together.
  2. Two-client refresh: Authorized boards reach the committed revision under healthy conditions.
  3. Disconnected repair: A board missing PubSub loads the latest revision on reconnect.
  4. Stale/gap handling: Stale revisions are ignored; gaps cause explicit recovery.
  5. Cross-tenant subscription: Tenant-42 session cannot subscribe to tenant-77 topics.
  6. Cross-tenant publication: Forged event cannot create tenant-77 projection or refresh.
  7. Shared resource IDs: Every query still returns only current tenant rows.
  8. Presence partition: Divergent awareness is labeled and converges after heal.
  9. High-rate telemetry: Received volume grows while buffer/mailbox/render bounds hold.
  10. Critical promotion: Threshold transition persists even when optional gauges are coalesced.
  11. Duplicate durable delivery: Multiple attempts create one effect.
  12. Broker pause: Outbox/broker age rises visibly and drains after recovery.
  13. Node partition: Transient loss is documented; durable facts lost remain zero.
  14. Role revocation: Existing session loses restricted delivery/action within deadline.
  15. Sabotage control: Disabling revision reload, idempotency, or revocation propagation fails the expected certification scenario.

6.3 Test Data

tenants:
  42: operators=[alice,bob] responders=[r1..r6]
  77: operators=[carol,dan] responders=[r7..r12]

shared logical IDs across tenants:
  incident=913
  device=abc
  responder=1001

reference event:
  event_id=evt-77
  tenant=42
  incident=913
  revision=18
  type=incident.severity_raised
  severity_before=2
  severity_after=3

reference load:
  devices_per_tenant=100
  gauge_rate_total=5000/second
  board_sessions=60
  critical_transition_rate=5/second
  integration_rate=50/second
  duration=10 minutes

SLO targets:
  ui_event_age_p99<500ms
  mailbox_p99<1000
  outbox_oldest_normal<30s
  presence_convergence_p99<35s
  cross_tenant_leaks=0
  duplicate_effects=0

Use deterministic synthetic generators and print seed, version, config hash, and environment with every result.

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Pitfall Symptom Solution
Generic event bus owns everything No one can state durability or authority Assign every flow to one plane
Topic contains tenant but auth is absent Cross-tenant messages leak Derive topics after authorization and test hostile paths
Presence used as lock Two components make conflicting decisions Store authoritative assignment in state plane
Full telemetry fanout Mailboxes and browser updates grow Coalesce/sample optional gauges; persist critical transitions
PubSub assumed to replay Boards remain stale after partition Detect gaps/reconnect and reload durable state
Ack before effect commit Broker deletes unfinished work Transfer responsibility only after durable effect
“Process restarted” success criterion User board still stale or duplicate effect exists Assert business/user invariants and SLOs
Metrics use raw tenant/event IDs Privacy/cardinality incident Use bounded labels; correlate IDs in protected traces
Chaos without cleanup Later runs inherit network faults Make cleanup idempotent and certify residual state
Green chaos without sabotage Assertions never tested recovery mechanism Disable one mechanism and expect failure

7.2 Debugging Strategies

  • Locate the plane first: Is the symptom wrong state, stale notification, delayed work, or control-plane blindness?
  • Trace one event ID and revision across all durable and transient boundaries.
  • Compare authoritative revision with each board cursor to distinguish loss from stale rendering.
  • Inspect component topology and Presence views per node, not one “global” snapshot.
  • Compare received/rendered/coalesced/dropped counts for telemetry capacity issues.
  • Run cross-tenant canaries continuously during load and chaos, not only in unit tests.
  • Freeze one dependency at a time so backlog location and degraded state remain attributable.
  • Verify recovery from the user’s perspective: correct board, role, integration effect, and deadline.

7.3 Performance Traps

  • One PubSub topic per overly granular object can create excessive subscription churn; one global topic creates excessive filtering and leakage risk. Measure the middle ground.
  • Large LiveView assigns and frequent diffs increase memory and serialization cost.
  • Presence metadata that changes on every telemetry reading creates replication storms.
  • Database pool, Broadway concurrency, Oban queue concurrency, and broker prefetch can multiply beyond downstream capacity.
  • Synchronous external calls in command or notification paths increase lock/ack latency.
  • Unbounded evidence collection can become the largest workload during chaos.
  • Tenant-fairness failure allows one noisy tenant to consume all queue, process, or render capacity.

Definition of Done

Minimum Viable Completion

  • Two tenants have isolated LiveView incident boards and server-derived topics.
  • One incident transition atomically commits state, event identity, and durable handoff.
  • Connected clients refresh through PubSub; disconnected clients recover from durable state.
  • One bounded telemetry path exposes received/rendered/coalesced counts.
  • One durable integration tolerates duplicate delivery with one effect.

Full Completion

  • All minimum criteria deployed across three application nodes with Presence and proven topology.
  • Cross-tenant probes cover subscription, publication, query, job, broker, cache, metrics, logs, traces, and admin tools with zero observed leaks.
  • Node partition documents expected transient loss and recovers all durable facts/revisions.
  • Broker pause, processor kill, slow subscriber, poison event, duplicate delivery, and role revocation meet defined degraded-state and recovery targets.
  • Certification reports UI event age, mailbox bounds, telemetry coalescing, outbox/broker age, duplicate effects, Presence convergence, revocation, and isolation.
  • Sabotage controls prove selected certification assertions can fail.

Excellence (Going Above & Beyond)

  • CI enforces architecture fitness functions for tenant scoping, topic construction, event contracts, and performance budgets.
  • A second region or cell architecture contains blast radius and documents federation semantics.
  • Disaster recovery proves backup restore, outbox/broker reconciliation, and measured RPO/RTO.
  • The complete portfolio includes ADRs, threat model, quality scenarios, capacity model, load results, runbooks, chaos evidence, and an executive architecture summary.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • Every merged source contribution is implemented as a phase of this one artifact, not as a separate project.
  • certification shows no lost fact, duplicate effect, or tenant leak.

Project 142: Multi-Tenant BEAM SaaS Reliability Platform

Sources: BEAM-CAP, PHX-P25. Integrate authenticated ingress, ledgers, workflows, tenant Repos, audit, safe cron, observability, deploy gates, and recovery.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: SQL, Shell
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: Level 5: Industry Disruptor
  • Curriculum Difficulty: Level 5: Expert
  • Knowledge Area: Production-Grade SaaS Patterns
  • Software or Tool: Oban, scheduler/cron coordination, deployment gates
  • Main Book: “Release It!” by Michael Nygard

What you will build: Integrate authenticated ingress, ledgers, workflows, tenant Repos, audit, safe cron, observability, deploy gates, and recovery.

Why it teaches the BEAM ecosystem: It makes you prove that outage and restart preserve business and tenant invariants.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Integrated Scope

This is one consolidated project, not separate source builds. Implement the following contributions as phases of the same artifact:

  • Use BEAM-CAP to define the reliability invariants across ledgers, workflows, audit, and recovery.
  • Deliver those invariants through PHX-P25’s production SaaS surface, tenant repos, deploy gates, and SLO evidence.

Real World Outcome

Build target: Integrate authenticated ingress, ledgers, workflows, tenant Repos, audit, safe cron, observability, deploy gates, and recovery.

Build operational SaaS foundations: soft deletion, audit logging, background orchestration, distributed cron safety, blue/green deploy, and graceful shutdown.

deterministic_outcome:

  • audit and retention checks pass
  • cron executes once per schedule window
  • blue/green + graceful shutdown drills succeed

The Core Question You Are Answering

Can this Phoenix system operate safely as a real SaaS platform under continuous change?

Concepts You Must Understand First

  • BEAM process model and failure isolation
  • OTP supervision semantics
  • Runtime observability discipline

Questions to Guide Your Design

  1. What is your safety invariant?
  2. What is your bounded recovery target?
  3. What is your fallback behavior under stress?

Thinking Exercise

Draft an outage scenario during deploy and define how blue/green plus graceful drain should prevent user-visible errors.

The Interview Questions They Will Ask

  1. What tradeoff did you choose and why?
  2. How do you prove correctness under failure?
  3. Which metric is your leading indicator of incident risk?
  4. “Which measurement would tell you that Multi-Tenant BEAM SaaS Reliability Platform is approaching its operating limit?”

Hints in Layers

Hint 1: Starting Point Define write-path hooks for audit logging first.

Hint 2: Next Level Add tenant-aware job idempotency keys.

Hint 3: Technical Details Implement deploy gate pipeline with rollback trigger conditions.

Hint 4: Tools/Debugging Tag logs with deployment_id and tenant_id for incident slicing.

Books That Will Help

Topic Book Chapter
Production stability “Release It!” Stability and release chapters
Operational design 12factor.net Config, logs, process principles

Implementation Milestones

Integrated basic-to-advanced progression

  1. Use BEAM-CAP to define the reliability invariants across ledgers, workflows, audit, and recovery.
  2. Deliver those invariants through PHX-P25’s production SaaS surface, tenant repos, deploy gates, and SLO evidence.

Milestone 1 — Contract and fixture: define one representative input, output, invariant, and failure case.

Milestone 2 — Core artifact: Integrate authenticated ingress, ledgers, workflows, tenant Repos, audit, safe cron, observability, deploy gates, and recovery.

Milestone 3 — Failure behavior: add timeouts, invalid inputs, crashes, retries, or partitions appropriate to the project.

Milestone 4 — Evidence: automate the definition of done and record a reproducible result.

  1. Baseline behavior validated.
  2. Instrumentation and dashboards available.
  3. Fault injection and recovery validated.
  4. Final report with tradeoffs and next steps.

Testing Strategy

6.1 Test Strategy

  • Unit tests for core transitions
  • Integration tests for runtime flows
  • Fault scenario tests for recovery

6.2 Verification Steps

  • Run full test suite.
  • Run deterministic lab script.

Common Pitfalls and Debugging

Problem 1: “Soft deleted records still appear”

  • Why: one query path bypassed default scope.
  • Fix: centralize scoped query builders.
  • Quick test: run full endpoint list against soft-deleted fixtures.

Problem 2: “Cron ran twice after failover”

  • Why: lock expiration and handover race.
  • Fix: tighten lock semantics and handover jitter.
  • Quick test: force leader restart and inspect execution count.

Definition of Done

  • Core functionality works on reference scenarios.
  • Failure path behavior matches design policy.
  • SLO metrics are captured and reproducible.
  • Findings are documented with evidence.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • Every merged source contribution is implemented as a phase of this one artifact, not as a separate project.
  • outage and restart preserve business and tenant invariants.

Project 143: Eventually Consistent Collaborative Phoenix Platform

Sources: PHX-CAP, PHX-P22, PHX-P27. Build multi-node LiveView collaboration with Presence, CRDT state, partitions, upgrades, chaos, and load evidence.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: JavaScript (k6), Rust (optional native paths)
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: Level 5: Industry Disruptor
  • Curriculum Difficulty: Level 5: Expert
  • Knowledge Area: Full-Stack Distributed Phoenix + BEAM Internals
  • Software or Tool: LiveView, CRDT, ETS, distributed rate limiting, chaos tools, telemetry stack
  • Main Book: Composite reading across all prior references

What you will build: Build multi-node LiveView collaboration with Presence, CRDT state, partitions, upgrades, chaos, and load evidence.

Why it teaches the BEAM ecosystem: It makes you prove that active sessions survive churn and shared state converges.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Integrated Scope

This is one consolidated project, not separate source builds. Implement the following contributions as phases of the same artifact:

  • Use PHX-CAP for the initial collaborative LiveView product and shared-domain contract.
  • Add PHX-P22 Presence internals, CRDT convergence, and reconnect behavior.
  • Complete PHX-P27 multi-node partitions, hot upgrades, chaos, and high-concurrency certification.

Real World Outcome

Build target: Build multi-node LiveView collaboration with Presence, CRDT state, partitions, upgrades, chaos, and load evidence.

Build the full system: LiveView collaboration, CRDT shared state, ETS cache, distributed rate limiting, hot-upgrade simulation, chaos tests, and 50k+ concurrent load campaign.

deterministic_outcome:

  • 50k+ connection scenario executed
  • partition and merge invariants hold
  • hot upgrade + rollback drills pass during active traffic

The Core Question You Are Answering

Can I operate a distributed Phoenix platform that stays correct and responsive when multiple failure modes collide?

Concepts You Must Understand First

  • BEAM process model and failure isolation
  • OTP supervision semantics
  • Runtime observability discipline

Questions to Guide Your Design

  1. What is your safety invariant?
  2. What is your bounded recovery target?
  3. What is your fallback behavior under stress?

Thinking Exercise

Design a “worst 15 minutes” incident timeline combining partition + dependency latency + rolling upgrade, and specify expected system behavior minute by minute.

The Interview Questions They Will Ask

  1. What tradeoff did you choose and why?
  2. How do you prove correctness under failure?
  3. Which metric is your leading indicator of incident risk?
  4. “Which measurement would tell you that Eventually Consistent Collaborative Phoenix Platform is approaching its operating limit?”

Hints in Layers

Hint 1: Starting Point Define explicit SLOs and invariants before implementation.

Hint 2: Next Level Integrate one subsystem at a time with observability gates.

Hint 3: Technical Details Use deterministic replay scenarios for partition and conflict tests.

Hint 4: Tools/Debugging Store incident timeline artifacts for every chaos + load run.

Books That Will Help

Topic Book Chapter
Distributed correctness “Designing Data-Intensive Applications” Replication and consistency
Resilience under load “Release It!” + “Systems Performance” Stability and measurement chapters

Implementation Milestones

Integrated basic-to-advanced progression

  1. Use PHX-CAP for the initial collaborative LiveView product and shared-domain contract.
  2. Add PHX-P22 Presence internals, CRDT convergence, and reconnect behavior.
  3. Complete PHX-P27 multi-node partitions, hot upgrades, chaos, and high-concurrency certification.

Milestone 1 — Contract and fixture: define one representative input, output, invariant, and failure case.

Milestone 2 — Core artifact: Build multi-node LiveView collaboration with Presence, CRDT state, partitions, upgrades, chaos, and load evidence.

Milestone 3 — Failure behavior: add timeouts, invalid inputs, crashes, retries, or partitions appropriate to the project.

Milestone 4 — Evidence: automate the definition of done and record a reproducible result.

  1. Baseline behavior validated.
  2. Instrumentation and dashboards available.
  3. Fault injection and recovery validated.
  4. Final report with tradeoffs and next steps.

Testing Strategy

6.1 Test Strategy

  • Unit tests for core transitions
  • Integration tests for runtime flows
  • Fault scenario tests for recovery

6.2 Verification Steps

  • Run full test suite.
  • Run deterministic lab script.

Common Pitfalls and Debugging

Problem 1: “Convergence eventually, but users saw confusing state jumps”

  • Why: conflict resolution policy not communicated or visualized in UI.
  • Fix: expose merge/conflict indicators and operation timeline.
  • Quick test: run scripted conflicting edits and user-journey review.

Problem 2: “Upgrades succeed in staging but fail under real load”

  • Why: state migration logic untested with high mailbox pressure.
  • Fix: run upgrade drill during active load/chaos scenario.
  • Quick test: compare migration error rate in idle vs stressed conditions.

Definition of Done

  • Core functionality works on reference scenarios.
  • Failure path behavior matches design policy.
  • SLO metrics are captured and reproducible.
  • Findings are documented with evidence.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • Every merged source contribution is implemented as a phase of this one artifact, not as a separate project.
  • active sessions survive churn and shared state converges.

Project 144: Custom Ecto Adapter for an HTTP Document Store

Source: BEAM-P33. Translate Ecto queries and schema operations onto an HTTP document database while honoring adapter contracts.

  • File: BEAM_ECOSYSTEM_MASTERY_PROJECTS.md
  • Main Programming Language: Elixir
  • Alternative Programming Languages: Erlang
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: Level 5: Industry Disruptor
  • Curriculum Difficulty: Level 5: Expert
  • Knowledge Area: Framework Internals, Query Translation
  • Software or Tool: Ecto.Adapter, Ecto query AST, Finch
  • Main Book: “Designing Data-Intensive Applications”

What you will build: Translate Ecto queries and schema operations onto an HTTP document database while honoring adapter contracts.

Why it teaches the BEAM ecosystem: It makes you prove that compatibility tests prove supported semantics, errors, migrations, and documented transaction limits.

Core challenges you will face:

  • Contract and invariants -> define behavior that stays stable across refactoring.
  • Failure semantics -> make crashes, invalid input, retries, or partitions explicit.
  • Independent evidence -> prove the mastery condition with tests, transcripts, metrics, or drills.

Real World Outcome

Build target: Translate Ecto queries and schema operations onto an HTTP document database while honoring adapter contracts.

Build EctoHttpDoc, a Hex-ready adapter plus a deterministic mock document server. The core supports schema insert/update/delete, get by primary key, equality/range boolean filters, stable field ordering, limit, cursor pagination, and full-schema/simple-field selections. It explicitly rejects joins, fragments, aggregates, locks, bulk updates, streams, and transactions.

$ mix ecto_http_doc.conformance --server http://127.0.0.1:4100
backend_api=v1 ecto=3.x adapter=0.1
schema_insert PASS
schema_update_revision PASS
schema_delete_stale PASS
query_filter_boolean PASS
query_order_limit PASS
query_join_rejected PASS no_request_issued=true
transaction_capability UNSUPPORTED expected=true
result=PASS supported=27 rejected_as_designed=11 failed=0

3.7.1 How to Run

$ mix deps.get
$ mix test
$ mix ecto_http_doc.mock_server
$ mix ecto_http_doc.conformance --server http://127.0.0.1:4100

3.7.2 Golden Path Demo

Insert a document, load it through an Ecto schema, update with the correct revision, reject a stale second update, query a stable ordered page, and prove that a join raises a capability error while the mock server records no request.

3.7.3 Exact Terminal Transcript

$ mix ecto_http_doc.demo
insert invoice=INV-42 revision=1 returned_fields=[id,revision,inserted_at]
get invoice=INV-42 total_cents=12500 status=open
update expected_revision=1 new_revision=2 result=ok
stale_update expected_revision=1 observed_revision=2 result=stale
query status=open order=[issued_at:desc,id:asc] rows=10 next_cursor=C2
unsupported join result=Ecto.QueryError requests_sent=0

The Core Question You Are Answering

“How can an Ecto adapter make a non-relational remote service feel coherent without lying about queries, transactions, types, or failure?”

Concepts You Must Understand First

  1. Ecto Repo, Schema, Changeset, Query, and adapter behaviour boundaries.
  2. Ecto types, parameter dumping, result loading, and projections.
  3. HTTP methods, conditional requests, retries, status classification, and JSON limits.
  4. Optimistic concurrency, idempotency, and uncertain outcomes.
  5. Behaviour compatibility, package versioning, and conformance testing.

Questions to Guide Your Design

  1. Which Ecto semantics can the backend satisfy exactly?
  2. Where is unsupported syntax rejected, and what evidence reaches the user?
  3. Which types round-trip without loss?
  4. Which write failures are safe to retry and which are uncertain?
  5. How will applications discover capabilities before production?

Thinking Exercise

Trace a where plus ordered, limited selection through Ecto planning, capability validation, typed parameters, remote request, JSON response, loaders, and final projection. Then insert a join and identify the earliest correct rejection point.

The Interview Questions They Will Ask

  1. “What responsibilities belong to each Ecto adapter behaviour?”
  2. “How do loaders and dumpers protect type semantics?”
  3. “Why is client-side filtering not an acceptable query translation fallback?”
  4. “How do ETags implement optimistic concurrency?”
  5. “When is an HTTP write retry safe?”
  6. “Why should an adapter omit transaction support rather than emulate it?”

Hints in Layers

Hint 1: Publish the matrix first — Decide supported types and query nodes before callbacks.

Hint 2: Plan before transport — Translate into an internal request plan that can be tested without a server.

Hint 3: Negative tests are features — Prove joins and transactions fail clearly with zero requests.

Hint 4: Preserve uncertainty — A timeout after a write is not automatically a safe retry or clean failure.

Books That Will Help

Topic Book Precise reading
Ecto internals Programming Ecto — Darin Wilson and Eric Meadows-Jönsson Repository, schema, query composition, changeset constraint, and transaction/Multi chapters
Data-model mismatch Designing Data-Intensive Applications — Martin Kleppmann Chapter 2 “Data Models and Query Languages”
Distributed failure Designing Data-Intensive Applications Chapter 8 “The Trouble with Distributed Systems”
HTTP contract HTTP: The Definitive Guide — Gourley and Totty Chapters on methods/status, caching, authentication, and conditional requests; verify details against RFC 9110

Implementation Milestones

Phase 1: Contracts and Types (8-12 hours)

  • Publish capability and type matrices.
  • Initialize adapter children/metadata and implement type round trips.
  • Create deterministic mock server protocol.

Phase 2: Schema Operations (8-12 hours)

  • Add insert/get/update/delete request plans.
  • Add generated fields, revision handling, and error classification.
  • Inject ambiguous timeout and stale-write cases.

Phase 3: Queryable Subset (10-16 hours)

  • Validate and translate filters, ordering, limit, cursor, and selections.
  • Add prepared-plan cache versioning.
  • Prove unsupported constructs issue no request.

Phase 4: Hardening and Packaging (9-20 hours)

  • Add bounded retries, telemetry, compatibility checks, and resource limits.
  • Complete conformance and performance fixtures.
  • Build Hex package, documentation, and upgrade policy.

Testing Strategy

6.1 Test Categories

Category Purpose Examples
Behaviour Validate callback contracts init, checkout, loaders/dumpers
Type Property Prove supported round trips UUID, dates, decimal, arrays, null
Query Translation Validate plans without network nested booleans, order, selection
Negative Capability Reject unsupported semantics join, fragment, lock, aggregate, transaction
Protocol Classify remote behavior status, headers, malformed JSON, oversized body
Failure/Retry Preserve write outcomes delayed commit, response loss, rate limit
Compatibility Test Ecto/backend matrix supported and rejected versions

6.2 Critical Test Cases

  1. Every supported primitive round-trips within its precision policy.
  2. Unknown response keys never create atoms.
  3. Unsupported nested query nodes fail before transport.
  4. Insert returns generated ID/revision in the shape Ecto expects.
  5. Stale revision maps to an Ecto stale result without overwrite.
  6. Ambiguous create timeout is classified uncertain unless protected by idempotency.
  7. Cursor cycle and page limits terminate with explicit error.
  8. Malformed 200 response is not treated as empty success.
  9. Repo.transaction capability is absent rather than falsely sequential.
  10. Backend version mismatch fails adapter startup with capability evidence.

6.3 Test Data

Use schemas covering every supported type, deterministic document fixtures, translation fixtures with nested booleans, and mock-server scenarios for all status/error classes. The server records request count and normalized request plans so negative tests prove zero network calls.

Common Pitfalls and Debugging

7.1 Frequent Mistakes

Problem Why it happens Fix Quick test
Query returns wrong rows Unsupported clause was ignored Recursive capability validation before request Add nested fragment fixture
Decimal/time drifts Generic JSON conversion Explicit type matrix and round-trip properties Boundary precision values
Duplicate document Blind retry after ambiguous timeout Stable idempotency/deterministic ID or uncertain result Commit then drop response
Lost update No revision precondition Map ETag/revision and stale result Two concurrent updates
Memory/atom growth Atomizes arbitrary JSON keys Map only known schema fields Random key flood
False transaction confidence Sequential callback called “transaction” Omit transaction behaviour Assert capability unavailable

7.2 Debugging Strategies

  • Inspect the canonical request plan before examining HTTP wire output.
  • Log capability rule ID for every rejection.
  • Correlate adapter operation, remote request ID, revision, and retry attempt without bodies/secrets.
  • Replay recorded bounded responses through the classifier independently.
  • Compare expected Ecto projection shape with loaded row shape field by field.

7.3 Performance Traps

  • N+1 remote requests disguised behind association access
  • Client-side collection of unbounded pages
  • Rebuilding translation plans for identical queries
  • Repeated authentication refresh under concurrency
  • Excessive JSON decode followed by discarding most fields
  • Retrying rate-limited calls without total budgets

Definition of Done

  • Base, Schema, and Queryable callback responsibilities are documented.
  • Capability and type matrices are versioned and tested.
  • Supported values round-trip under explicit precision/null policies.
  • Unsupported query constructs fail early with no remote request.
  • Revision-aware writes prevent stale overwrite.
  • Retry policy distinguishes safe, terminal, and uncertain outcomes.
  • Pagination, response size, attempt count, and total time are bounded.
  • Transaction support is explicitly unavailable.
  • Conformance tests pass against the deterministic mock backend.
  • Package documentation states tested Ecto and backend API versions.

  • The documented happy path works from a clean environment.
  • Invalid input and the principal failure mode produce explicit, testable evidence.
  • Tests cover the core invariant without relying on arbitrary timing.
  • Operational limits, unsupported cases, and recovery behavior are documented.
  • compatibility tests prove supported semantics, errors, migrations, and documented transaction limits.

Project Comparison Table

Project Curriculum difficulty Estimated time Knowledge area Depth Fun factor
1. Reproducible Elixir Workstation Smoke Test Level 1: Foundational 4-8 hours Toolchain / Runtime Setup Focused ★★☆☆☆
2. Elixir Syntax Conformance Playground Level 1: Foundational 4-8 hours Language Grammar / AST Focused ★★☆☆☆
3. Subscription Quote Rules REPL Level 1: Foundational 4-8 hours Core Language / Values Focused ★★☆☆☆
4. Operator Precedence and Readability Auditor Level 1: Foundational 4-8 hours Language Semantics / Readability Focused ★★☆☆☆
5. Batch Delivery Outcome Ledger Level 1: Foundational 4-8 hours Data Structures / Complexity Focused ★★☆☆☆
6. Conference Registration Options Normalizer Level 1: Foundational 4-8 hours Collections / Configuration Shapes Focused ★★☆☆☆
7. Warehouse Scan Correlator Level 1: Foundational 4-8 hours Language Semantics / Destructuring Focused ★★☆☆☆
8. Explainable Event Contract Router Level 1: Foundational 4-8 hours Dispatch / Guards Focused ★★☆☆☆
9. Travel Reimbursement Decision Table Level 1: Foundational 4-8 hours Control Flow / Decision Modeling Focused ★★☆☆☆
10. Dynamic Survey Scoring Pipeline Level 1: Foundational 4-8 hours Functional Composition Focused ★★☆☆☆
11. Unicode Display-Name Audit CLI Level 1: Foundational 4-8 hours Text / Binary Representation Focused ★★☆☆☆
12. Unicode Identifier Confusables CI Scanner Level 1: Foundational 4-8 hours Source Security / Unicode Focused ★★☆☆☆
13. Measurement Conversion Toolkit Level 1: Foundational 4-8 hours Module and API Design Focused ★★☆☆☆
14. Report Formatter Extension Kit Level 1: Foundational 4-8 hours Module Composition / Lexical Scope Focused ★★☆☆☆
15. Convention-Complete Key-Value API Level 1: Foundational 4-8 hours Public API Semantics Focused ★★☆☆☆
16. Compile-Time Compliance Rule Catalog Level 1: Foundational 4-8 hours Compile-Time Metadata Focused ★★☆☆☆
17. Parcel Manifest Domain Model Level 1: Foundational 4-8 hours Domain Modeling / Data Integrity Focused ★★☆☆☆
18. Nested Bill-of-Materials Flattener Level 1: Foundational 4-8 hours Algorithms / Immutable Traversal Focused ★★☆☆☆
19. Erlang Calculator REPL Level 1: Foundational 4-8 hours Language Syntax / REPL Design Focused ★★☆☆☆
20. Memory-Bounded Access-Log Window Processor Level 1: Foundational 4-8 hours Lazy Data Processing Focused ★★☆☆☆
21. Inventory Analytics Command Workbench Level 1: Foundational 4-8 hours Collection Algorithms Focused ★★☆☆☆
22. RGB Binary Thumbnail Transcoder Level 1: Foundational 4-8 hours Binary Transformation / Collectables Focused ★★☆☆☆
23. Multi-Carrier Label Renderer Level 1: Foundational 4-8 hours Open Polymorphism Focused ★★☆☆☆
24. Validated Log-Query Sigil Toolkit Level 1: Foundational 4-8 hours Language Literals / Parsing Focused ★★☆☆☆
25. Partner API Failure Boundary Simulator Level 1: Foundational 4-8 hours Failure Semantics Focused ★★☆☆☆
26. Streaming CSV Export Writer with Iodata Level 1: Foundational 4-8 hours File I/O / Efficient Output Focused ★★☆☆☆
27. Documented Address Validation SDK Level 1: Foundational 4-8 hours Documentation / API Contracts Focused ★★☆☆☆
28. Formatter-Backed Team Syntax Fixture Level 1: Foundational 4-8 hours Syntax / Formatting Focused ★★☆☆☆
29. Offline Incident Bundle Analyzer Level 1: Foundational 4-8 hours Erlang Interoperability Focused ★★☆☆☆
30. Reproducible Order-Pipeline Debugging Casebook Level 1: Foundational 4-8 hours Debugging / Runtime Introspection Focused ★★☆☆☆
31. Team-Ready Mix Project and CI Quality Gate Level 1: Foundational 4-8 hours Build Tooling / Developer Workflow Focused ★★☆☆☆
32. Evidence-Based Elixir Smell Triage Board Level 1: Foundational 4-8 hours Engineering Judgment / Code Health Focused ★★☆☆☆
33. Round-Trip INI Configuration Tool Level 1: Foundational 4-8 hours File I/O / Parsing Focused ★★☆☆☆
34. Markdown-to-HTML Transformation Pipeline Level 1: Foundational 4-8 hours Parsing / Text Processing Focused ★★☆☆☆
35. Bank Statement Reconciliation CLI Level 1: Foundational 4-8 hours Data Transformation, Financial Reconciliation Focused ★★☆☆☆
36. iCalendar Availability and Conflict Detector Level 1: Foundational 4-8 hours Calendars, Interval Algorithms Focused ★★☆☆☆
37. Duplicate File Quarantine Planner Level 1: Foundational 4-8 hours Filesystems, Safety, Integrity Focused ★★☆☆☆
38. Fixed-Width Settlement Parser and Property Lab Level 1: Foundational 4-8 hours Binary Parsing, Verification Focused ★★☆☆☆
39. Executable Interactive Field Report Level 1: Foundational 4-8 hours Literate programming, functional transformations, reproducibility Focused ★★☆☆☆
40. Livebook Data Triage and Mobility Pipeline Level 1: Foundational 4-8 hours DataFrames, lazy queries, data quality, columnar formats Focused ★★☆☆☆
41. Safe SQL Incident Runbook Level 1: Foundational 4-8 hours Databases, operational diagnostics, security, evidence Focused ★★☆☆☆
42. Set-Theoretic Fulfillment API Contract Atlas Level 2: Intermediate 8-16 hours Type Systems / API Contracts Focused ★★★☆☆
43. Process Lifecycle Incident Simulator Level 2: Intermediate 8-16 hours Concurrency / Process Primitives Focused ★★★☆☆
44. TCP Echo Server from Raw Processes Level 2: Intermediate 8-16 hours Concurrency / Networking Focused ★★★☆☆
45. Chat Server Without OTP Level 2: Intermediate 8-16 hours Concurrency / Networking Focused ★★★☆☆
46. Workshop Check-In Counter with Encapsulated Agent State Level 2: Intermediate 8-16 hours State Ownership / Agent Focused ★★★☆☆
47. Mailbox-to-Registry Topic Bus Level 2: Intermediate 8-16 hours Process registry, local routing, supervision Focused ★★★☆☆
48. Monitored Process Pool Manager Level 2: Intermediate 8-16 hours Concurrency / Resource Management Focused ★★★☆☆
49. Raw ETS Token-Bucket Rate Limiter Level 2: Intermediate 8-16 hours Algorithms / Concurrency Focused ★★★☆☆
50. Build Your Own Generic Server Level 2: Intermediate 8-16 hours OTP Internals / Behavior Design Focused ★★★☆☆
51. Monitored Build-Watcher Hub with Automatic Subscriber Cleanup Level 2: Intermediate 8-16 hours OTP / GenServer Lifecycle Focused ★★★☆☆
52. Support Session Directory with Registry and Application Lifecycle Level 2: Intermediate 8-16 hours OTP Applications / Registry Focused ★★★☆☆
53. On-Demand Customer Workspace Supervisor Level 2: Intermediate 8-16 hours OTP / Dynamic Supervision Focused ★★★☆☆
54. Concurrent TCP Health-Check Console with Isolated Client Sessions Level 2: Intermediate 8-16 hours Networking / Supervised Tasks Focused ★★★☆☆
55. Warehouse Scanner Protocol with Executable Documentation Level 2: Intermediate 8-16 hours Executable Documentation / Integration Tests Focused ★★★☆☆
56. Supervised Multi-Room Chat Service Level 2: Intermediate 8-16 hours Concurrency, Fault Tolerance Focused ★★★☆☆
57. Supervision Strategy Fault Lab Level 2: Intermediate 8-16 hours Fault Tolerance Focused ★★★☆☆
58. Supervision Tree Visualizer Level 2: Intermediate 8-16 hours OTP / Introspection Focused ★★★☆☆
59. Process Boundary Cost Clinic Level 2: Intermediate 8-16 hours OTP Architecture / Performance Focused ★★★☆☆
60. ETS Cache and Session Service Level 2: Intermediate 8-16 hours Data Storage Focused ★★★☆☆
61. Crash-Resilient ETS/DETS Session Store Level 2: Intermediate 8-16 hours Stateful Services, Storage Lifecycle, Recovery Focused ★★★☆☆
62. Fault-Tolerant Livebook Telemetry Lab Level 2: Intermediate 8-16 hours BEAM processes, supervision, backpressure, interactive observability Focused ★★★☆☆
63. Concurrent Link and TLS Expiry Auditor Level 2: Intermediate 8-16 hours Bounded Concurrency, HTTP, TLS Focused ★★★☆☆
64. Legacy Billing Refactoring Certification Lab Level 2: Intermediate 8-16 hours Refactoring / Language Safety Focused ★★★☆☆
65. Mix Dependency SBOM and License Auditor Level 2: Intermediate 8-16 hours Build Tooling, Supply Chain Focused ★★★☆☆
66. SBOM Release Attestation and Incident-Response Gate Level 2: Intermediate 8-16 hours Software Supply Chain Focused ★★★☆☆
67. Third-Party Encoder Behaviour SDK Level 2: Intermediate 8-16 hours Library Contracts / Static Analysis Focused ★★★☆☆
68. Stable Invoice SDK Contract Redesign Level 2: Intermediate 8-16 hours API Design / Domain Modeling Focused ★★★☆☆
69. Pluggable Object Storage Library Level 2: Intermediate 8-16 hours Library Design, Packaging Focused ★★★☆☆
70. Hex Package Consumer-Compatibility Factory Level 2: Intermediate 8-16 hours Library Engineering / Packaging Focused ★★★☆☆
71. Contract-Aware Phoenix Event Hub Level 2: Intermediate 8-16 hours Framework Pub/Sub, supervision, API design Focused ★★★☆☆
72. OTP Rate Limiter and Circuit Breaker Level 2: Intermediate 8-16 hours State, Fault Tolerance Focused ★★★☆☆
73. Plug-to-Phoenix Request Stack Level 3: Applied 12-24 hours Web Framework Deep ★★★★☆
74. Ecto Persistence Deep Dive Level 3: Applied 12-24 hours Database / Functional Deep ★★★★☆
75. Multi-Provider Webhook Authenticity Gateway Level 3: Applied 12-24 hours HTTP Security, API Integration Deep ★★★★☆
76. Transactional Inventory Ledger and Reservation API Level 3: Applied 12-24 hours Relational Integrity, Concurrency Deep ★★★★☆
77. Authentication from Scratch Level 3: Applied 12-24 hours Security / Web Deep ★★★★☆
78. Phoenix REST and GraphQL API Level 3: Applied 12-24 hours API Design Deep ★★★★☆
79. Phoenix Channels Chat Level 3: Applied 12-24 hours Real-Time / WebSockets Deep ★★★★☆
80. Correct-by-Reconnect LiveView Operations Board Level 3: Applied 12-24 hours LiveView lifecycle, real-time projections, reconnect recovery Deep ★★★★☆
81. Phoenix Test Pyramid Level 3: Applied 12-24 hours Testing / Quality Deep ★★★★☆
82. Durable Oban Document Workflow Level 3: Applied 12-24 hours Durable Jobs, Workflow Reliability Deep ★★★★☆
83. Phoenix Telemetry and Live Metrics Level 3: Applied 12-24 hours Observability Deep ★★★★☆
84. Production Phoenix Deployment Level 3: Applied 12-24 hours DevOps / Deployment Deep ★★★★☆
85. Transactional Notification Outbox Level 3: Applied 12-24 hours Database transactions, durable jobs, idempotency Deep ★★★★☆
86. First Typed Ash Resource Level 3: Applied 12-24 hours Declarative domain modeling Deep ★★★★☆
87. Related Resources and CRUD Actions Level 3: Applied 12-24 hours Declarative domain modeling Deep ★★★★☆
88. Custom Ash Actions on PostgreSQL Level 3: Applied 12-24 hours Declarative domain modeling Deep ★★★★☆
89. Ash Calculations, Aggregates, and Queries Level 3: Applied 12-24 hours Declarative domain modeling Deep ★★★★☆
90. AshPhoenix Forms Level 3: Applied 12-24 hours Declarative domain modeling Deep ★★★★☆
91. AshAuthentication Application Level 3: Applied 12-24 hours Declarative domain modeling Deep ★★★★☆
92. Ash Authorization Policies Level 3: Applied 12-24 hours Declarative domain modeling Deep ★★★★☆
93. Ash JSON:API and GraphQL Adapters Level 3: Applied 12-24 hours Declarative domain modeling Deep ★★★★☆
94. Ash PubSub and Notifiers Level 3: Applied 12-24 hours Declarative domain modeling Deep ★★★★☆
95. Ash Resource Test Harness Level 3: Applied 12-24 hours Declarative domain modeling Deep ★★★★☆
96. Ash Help Desk Application Level 3: Applied 12-24 hours Declarative domain modeling Deep ★★★★☆
97. Interactive SLA Command Center Level 3: Applied 12-24 hours Operational analytics, event-driven UI, visualization Deep ★★★★☆
98. Portable Cloud Data Lake Lab Level 3: Applied 12-24 hours File systems, object storage, data portability, security Deep ★★★★☆
99. Tested Domain Smart Cell Toolkit Level 3: Applied 12-24 hours Source generation, collaborative UI, packaging, testing Deep ★★★★☆
100. Governed Multi-Session Livebook Operations Studio Level 3: Applied 12-24 hours Internal tools, deployment, identity, operations, data and ML governance Deep ★★★★☆
101. Distributed Presence Workspace Level 4: Advanced 20-40 hours Presence CRDTs, multi-device lifecycle, eventual consistency Systems-level ★★★★★
102. Demand-Aware Fanout Pipeline Level 4: Advanced 20-40 hours Reactive streams, demand, batching, acknowledgements Systems-level ★★★★★
103. Runtime-Configured Cluster-Wide Singleton Job Coordinator Level 4: Advanced 20-40 hours Distribution / Runtime Configuration Systems-level ★★★★★
104. Secure Multi-Network Cluster Formation Lab Level 4: Advanced 20-40 hours Distribution, Cluster Operations Systems-level ★★★★★
105. Three-Node Distributed Phoenix.PubSub Lab Level 4: Advanced 20-40 hours Distributed systems, topology, partitions, rolling deploys Systems-level ★★★★★
106. Set-Theoretic Type Diagnostic Laboratory Level 4: Advanced 20-40 hours Compiler Types / Verification Systems-level ★★★★★
107. Quoted-Expression Transformation Sandbox Level 4: Advanced 20-40 hours Metaprogramming / AST Systems-level ★★★★★
108. Hygienic Macro Expansion Observatory Level 4: Advanced 20-40 hours Metaprogramming / Hygiene Systems-level ★★★★★
109. Data-to-Macro Validation DSL Bake-Off Level 4: Advanced 20-40 hours Language Design / DSL Trade-offs Systems-level ★★★★★
110. Macro Recompilation Budget Gate Level 4: Advanced 20-40 hours Compiler Tooling / Dependency Hygiene Systems-level ★★★★★
111. Compile-Time Pricing Policy DSL Level 4: Advanced 20-40 hours Metaprogramming, Domain Modeling Systems-level ★★★★★
112. Compiler-Aware Migration Linter Level 4: Advanced 20-40 hours Compiler Tooling, Static Analysis Systems-level ★★★★★
113. TCP Device Telemetry Gateway Level 4: Advanced 20-40 hours TCP, Binary Protocols, Connection Lifecycle Systems-level ★★★★★
114. Nerves Cold-Chain Sensor Gateway Level 4: Advanced 20-40 hours Embedded Systems, Fleet Reliability Systems-level ★★★★★
115. Elixir/Rustler Ports-versus-NIF Lab Level 4: Advanced 20-40 hours Native Interop Systems-level ★★★★★
116. Nx Demand Forecasting Engine Level 4: Advanced 20-40 hours Numerical Computing, Forecasting Systems-level ★★★★★
117. Nx and Bumblebee Image Triage Lab Level 4: Advanced 20-40 hours Tensors, pretrained models, inference serving, evaluation Systems-level ★★★★★
118. Durable gen_statem OTP Control Plane Level 4: Advanced 20-40 hours State Machines, Temporal Workflows Systems-level ★★★★★
119. Distributed KV and Mnesia Work-Order Ledger Level 4: Advanced 20-40 hours Distributed State, Transactions, Operational Recovery Systems-level ★★★★★
120. Elixir and OTP Upgrade Readiness Matrix Level 4: Advanced 20-40 hours Compatibility / Release Engineering Systems-level ★★★★★
121. Operator-Ready Two-Node Release Runbook Level 4: Advanced 20-40 hours Release Engineering / Operations Systems-level ★★★★★
122. Self-Contained Air-Gapped Mix Release Level 4: Advanced 20-40 hours Release Engineering, Runtime Configuration, Deployment Systems-level ★★★★★
123. Distributed Service Directory and Fleet Router Level 4: Advanced 20-40 hours Process Registration, Discovery, Distributed Routing Systems-level ★★★★★
124. Safe Attached-Runtime Livebook Console Level 4: Advanced 20-40 hours Distributed Elixir, live diagnostics, trust boundaries Systems-level ★★★★★
125. WAN Netsplit Recovery Drill Level 4: Advanced 20-40 hours Distributed Systems, Failure Recovery Systems-level ★★★★★
126. Partition-Tolerant Horde and CRDT Cluster Level 4: Advanced 20-40 hours Distributed BEAM Engineering Systems-level ★★★★★
127. Event-Sourced Multi-Tenant Phoenix Domain Level 4: Advanced 20-40 hours Architecture Patterns Systems-level ★★★★★
128. BEAM Artifact and Bytecode Inspector Level 4: Advanced 20-40 hours BEAM Artifacts, Reproducible Builds Systems-level ★★★★★
129. Tracing-Driven Phoenix Performance War Room Level 4: Advanced 20-40 hours Performance Engineering Systems-level ★★★★★
130. Scheduler, Heap, and Mailbox Pressure Lab Level 4: Advanced 20-40 hours BEAM Internals Systems-level ★★★★★
131. Raw Erlang C NIF for Fast JSON Level 4: Advanced 20-40 hours FFI / Native Code Systems-level ★★★★★
132. Erlang Parse Transform System Level 4: Advanced 20-40 hours Metaprogramming / Compiler Systems-level ★★★★★
133. Hot-Upgrade Release Engineering Drill Level 4: Advanced 20-40 hours Release Engineering Systems-level ★★★★★
134. Distributed Erlang Game Server Level 4: Advanced 20-40 hours Distributed Systems / Game Development Systems-level ★★★★★
135. Federated Tenant-Safe Broker Edge Bus Level 4: Advanced 20-40 hours Durable brokers, acknowledgements, security, chaos observability Systems-level ★★★★★
136. Production-Ready BEAM Message Queue Level 4: Advanced 20-40 hours Distributed Systems / Message Queues Systems-level ★★★★★
137. Multi-Tenant Dynamic Repo Control Plane Level 5: Expert 30-60 hours Multi-Tenancy, Resource Control Systems-level ★★★★★
138. Advanced BEAM Verification Lab Level 5: Expert 30-60 hours Advanced Testing Systems-level ★★★★★
139. BEAM Chaos and Resilience Engineering Level 5: Expert 30-60 hours Reliability and Fault Tolerance Systems-level ★★★★★
140. Elite Runtime Primitives Workshop Level 5: Expert 30-60 hours Elite Mode Topics Systems-level ★★★★★
141. Multi-Tenant Real-Time Operations Mesh Level 5: Expert 30-60 hours Distributed architecture, real-time UX, durable integration, security, SRE Systems-level ★★★★★
142. Multi-Tenant BEAM SaaS Reliability Platform Level 5: Expert 30-60 hours Production-Grade SaaS Patterns Systems-level ★★★★★
143. Eventually Consistent Collaborative Phoenix Platform Level 5: Expert 30-60 hours Full-Stack Distributed Phoenix + BEAM Internals Systems-level ★★★★★
144. Custom Ecto Adapter for an HTTP Document Store Level 5: Expert 30-60 hours Framework Internals, Query Translation Systems-level ★★★★★

Recommendation

  • New to BEAM: begin at Project 1 and complete the official language foundation through Project 43 before judging raw-process work.
  • Experienced Elixir developer: use the Definition of Done to test out of Projects 1-43, then begin at the first gap you cannot prove.
  • Phoenix-focused engineer: complete Projects 42-72 before the Phoenix phase so process ownership, supervision, and library contracts remain visible beneath the framework.
  • Runtime or distributed-systems engineer: complete Projects 1-72, then emphasize Projects 101-140.
  • Principal-level capstone path: complete Projects 118-136 before attempting Projects 141-144.

Final Overall Project: Eventually Consistent Collaborative Phoenix Platform

Use Project 143 as the final overall project rather than adding a duplicate capstone. It combines a collaborative LiveView product, Presence, CRDT convergence, multi-node partitions, load, chaos, rolling upgrades, and rollback.

  1. Define hard invariants, eventual invariants, tenant boundaries, SLOs, and degraded modes.
  2. Deliver the single-node product and deterministic collaboration model.
  3. Add clustering, partition/heal behavior, bounded fanout, and convergence evidence.
  4. Run active-traffic upgrade, rollback, chaos, and high-concurrency campaigns.

Success criteria: active sessions remain usable, shared state converges within the declared window, tenant isolation holds, telemetry explains failures, and rollback succeeds under load.

From Learning to Production: What Is Next

Your project lane Production equivalent Gap to fill before real use
OTP services Stateful internal service Capacity model, runbooks, alerts, upgrade policy
Phoenix/LiveView Customer-facing web product Threat model, accessibility, browser testing, deployment SLOs
Ash domain Declarative business platform Policy audit, migration discipline, query budgets, API compatibility
Livebook application Internal operational tool Authentication, secrets, data retention, session isolation, rollback
Pub/Sub and brokers Real-time integration layer Delivery contract, backpressure, replay boundary, tenant isolation
Mnesia/distributed state Clustered control plane Partition authority, backup/restore, readiness, operator recovery
NIF/Port work Native performance component Fuzzing, scheduler budgets, ABI/release matrix, crash containment

Summary

This guide now combines 128 source-project entries from the six original guides with all 53 official Elixir v1.20.2 documentation topics, producing 144 prerequisite-aware, self-contained projects. The original twenty-nine conceptual merge groups remain integrated artifacts; every requested official topic contributes one additional distinct project with its own observable outcome and completion contract.

Phase Projects Outcome
Language, Immutable Data, and Reproducible Analysis 1-41 Official Elixir foundations, deterministic data, parsing, validation, and analysis
Processes, Message Passing, OTP, and Local State 42-72 Processes, OTP, API quality, supervision, local messaging, and library discipline
Phoenix, Ecto, Web Security, and Durable Work 73-85 Secure, observable, deployable Phoenix and durable web systems
Ash Framework Resource and Policy Mastery 86-96 Declarative Ash resources, actions, policies, APIs, and tests
Livebook Applications and Data Portability 97-100 Reproducible and governed Livebook applications
Real-Time Flow, Native Boundaries, and Numerical Computing 101-117 Types, metaprogramming, cluster flow, native boundaries, devices, and Nx workloads
State Machines, Distribution, VM Internals, and Releases 118-136 Compatibility, releases, recovery, VM evidence, upgrades, and brokers
Advanced Architecture and Capstones 137-144 Multi-tenant reliability, chaos, convergence, and extension contracts

Additional Resources and References