Project 1: Executable Energy Field Report
Build a replayable Livebook report that turns household appliance readings into auditable energy-cost and efficiency scenarios.
Quick Reference
| Attribute | Value |
|---|---|
| Difficulty | Level 1 — Beginner |
| Time Estimate | 5–8 hours |
| Language | Elixir (alternatives for comparison: Erlang, Python) |
| Prerequisites | Basic expressions, lists and maps; command-line navigation; Git fundamentals |
| Key Topics | Livebook evaluation, immutable data, pattern matching, deterministic replay, invariants, provenance |
1. Learning Objectives
By completing this project, you will:
- Explain how Livebook evaluates sections and cells, including why a descendant cell becomes stale when an ancestor changes.
- Model appliance readings as immutable domain values and transform them without relying on hidden mutable state.
- Separate input normalization, domain calculation, presentation, and verification into reviewable stages.
- Represent invalid readings with explicit tagged outcomes instead of crashes or silent coercion.
- Reproduce the same report after reconnecting to a clean runtime using only committed inputs and declared dependencies.
- Produce a manifest that identifies the input snapshot, formula revision, runtime, package versions, assumptions, and output checks.
- Use independent invariants to detect stale, partial, or internally inconsistent results.
2. Theoretical Foundation
2.1 Core Concepts
Executable documents and evaluation ancestry. A Livebook notebook is both prose and executable Elixir. A code cell receives bindings and module definitions from the cells that precede it in its evaluation branch. The notebook tracks that ancestry: if a tariff cell changes, downstream calculations become stale because their result was derived from an older binding. A displayed value is therefore not trustworthy merely because it is visible. Its evaluation lineage must still match the current source.
Immutable values and rebinding. Elixir does not mutate a value in place. A name may be rebound to a new value, but earlier values are unchanged. The report should make each transformation explicit: raw readings become normalized readings, normalized readings become appliance totals, and totals become scenarios. Distinct stage names make the reasoning visible and prevent rebinding from disguising which representation is being used.
Boundary and domain representations. Text entered by a person or read from a file is untrusted boundary data. Domain data has already satisfied a contract. A raw value such as "1200" is not yet a wattage; it becomes one only after parsing, range validation, and unit assignment. Keeping boundary and domain shapes distinct prevents plausible but meaningless arithmetic.
Determinism and reproducibility. A deterministic calculation returns the same result for the same explicit inputs. Reproducibility adds the ability for another runtime to obtain those inputs, dependency versions, assumptions, and execution order. A notebook that depends on an author’s shell variable, home-directory file, current clock, or unexplained cell history is not reproducible even if its pure calculation is deterministic.
Invariants. An invariant is a relationship that must remain true independent of presentation. Useful report invariants include: no reading has negative watts or hours; total usage equals the sum of appliance usage; reported currency equals rounded energy multiplied by tariff; and baseline cost minus efficient cost equals reported savings under one declared rounding policy. Invariants are stronger than checking a single expected number because they cover whole classes of inputs.
Provenance. Provenance answers where a result came from. The report manifest should record the input snapshot checksum, report period, tariff source, formula revision, rounding policy, Elixir/OTP/Livebook versions, and verification status. Provenance does not make a result correct, but it makes it inspectable and repeatable.
2.2 Why This Matters
Real engineering reports often outlive the interactive session that created them. Energy audits, pricing calculators, experiment summaries, financial models, and incident analyses all become dangerous when conclusions survive but assumptions disappear. Livebook gives the narrative and computation one home, while Elixir encourages explicit data flow and failure values. Together they make a small report behave like a reviewable software artifact.
This project also establishes habits used throughout the series. The capacity planner adds events to the same pure-calculation core. The CSV clinic applies boundary validation and reconciliation at bulk scale. The telemetry lab adds processes whose lifetimes cannot be reconstructed from bindings alone. Clean replay is the control experiment that exposes hidden dependencies in all of them.
2.3 Historical Context / Background
Literate programming proposed that programs should be written in an order optimized for human understanding rather than only compiler consumption. Modern computational notebooks made this idea interactive, but also introduced a familiar reproducibility problem: a visible output may reflect an execution order different from the document order. Livebook addresses this with an Elixir-aware evaluator, dependency tracking, stale-cell indicators, and explicit runtimes.
Elixir adds a second lineage. Its functional core descends from immutable functional programming, while the BEAM runtime comes from Erlang’s concurrent, fault-tolerant systems tradition. In this first project, the functional side is primary: values are transformed, failures are data, and calculations remain independent of UI or process state.
2.4 Common Misconceptions
- “A notebook is reproducible because it was saved.” Saving preserves source and selected metadata, not every external file, environment value, secret, clock reading, or process that influenced the output.
- “Rebinding is mutation.” Rebinding associates a name with a new immutable value; it does not change the prior value held by another binding or data structure.
- “Top-to-bottom source means top-to-bottom execution happened.” The current outputs may have been produced in another order. A fresh runtime replay is the proof.
- “One golden total is enough testing.” A hard-coded total can pass while units, rounding, validation, or scenario formulas are wrong. Independent invariants provide broader evidence.
- “A module defined in a cell is automatically permanent.” It exists in the current runtime. Reconnect or runtime termination removes it until the defining cell is evaluated again.
- “Floats are always wrong for a learning report.” Floating-point arithmetic can be acceptable for physical estimates when tolerances are declared. Currency rounding must still occur at one explicit boundary, not opportunistically after every intermediate value.
3. Project Specification
3.1 What You Will Build
Create one .livemd notebook named energy-field-report.livemd. It will contain:
- A title, purpose, report period, assumptions, units, and declared scope.
- A setup section that declares dependencies and displays the runtime baseline.
- A committed six-row appliance fixture with watts, daily hours, days used, and efficiency factor.
- A boundary-validation section that reports every invalid row with stable row identity.
- Named Elixir modules or clearly named pure functions for normalization, usage calculation, cost calculation, scenario comparison, and verification.
- A baseline scenario and an efficient scenario using the same validated readings.
- A human-readable report with totals, cost, savings, and independent PASS/FAIL checks.
- A provenance manifest suitable for review in Git.
- 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.
3.2 Functional Requirements
- Declare inputs: Record the six appliance readings, report period, tariff in
R$/kWh, scenario policy, and units in source-controlled cells. - Validate boundaries: Reject missing appliance names, non-numeric watts/hours/days, negative values, daily hours above 24, days outside the report period, and efficiency factors outside the declared interval.
- Preserve row identity: Every validation message must identify the source row or appliance key.
- Compute consumption: Convert watt-hours to kilowatt-hours exactly once using an explicit unit conversion.
- Compute cost: Apply one tariff and one documented currency rounding boundary.
- Compare scenarios: Produce baseline and efficient usage/cost plus absolute and percentage savings.
- Verify invariants: Display PASS/FAIL for row validity, aggregation, cost arithmetic, and scenario reconciliation.
- Expose stale behavior: Change the tariff, observe downstream stale state, and document the cells that require re-evaluation.
- Emit a manifest: Show input checksum, formula revision, runtime/package versions, assumptions, row counts, and verification status.
- Replay cleanly: Reconnect to a fresh runtime, evaluate in document order, and reproduce the expected report.
3.3 Non-Functional Requirements
- Correctness: All displayed totals must be derived from validated domain values; no invalid row may silently contribute.
- Reproducibility: No absolute local path, implicit environment variable, current-time dependency, or manual pre-run action may be required.
- Readability: Narrative cells explain why a stage exists; names include units where ambiguity is possible.
- Reviewability: The
.livemdfile has stable formatting and useful Git diffs; generated noise and secrets are absent. - Reliability: Validation returns structured errors and the report renders a controlled failure state instead of raising.
- Performance: The six-row report should replay in under two seconds after dependency setup on an ordinary development machine.
- Portability: A second user with a supported Livebook runtime can reproduce the fixture result from the repository.
3.4 Example Usage / 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
3.5 Real World Outcome
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.
4. Solution Architecture
4.1 High-Level Design
┌──────────────────────────────────────────────────────────────┐
│ Livebook document │
│ purpose • assumptions • setup • supported runtime baseline │
└──────────────────────────────┬───────────────────────────────┘
│
v
┌──────────────────────┐ tagged results ┌────────────────────┐
│ Boundary fixture │─────────────────▶│ Validation layer │
│ rows + tariff + date │ │ parse • units • │
└──────────────────────┘ │ ranges • all errors│
└─────────┬──────────┘
│ trusted values
v
┌──────────────────────┐ ┌────────────────────┐
│ Scenario policy │─────────────────▶│ Pure domain core │
│ baseline / efficient │ │ usage • cost • │
└──────────────────────┘ │ comparison │
└─────────┬──────────┘
│ result
┌────────────────────────────┼────────────────────┐
v v v
┌──────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Report renderer │ │ Invariant checks │ │ Manifest builder │
│ tables + summary │ │ independent math │ │ versions + hash │
└────────┬─────────┘ └────────┬─────────┘ └────────┬────────┘
└──────────────────────────┴─────────────────────┘
│
v
┌────────────────────┐
│ Clean replay proof │
└────────────────────┘
4.2 Key Components
| Component | Responsibility | Key Decisions |
|---|---|---|
| Notebook setup | Declare dependencies and display runtime facts | Keep setup deterministic and first in evaluation ancestry |
| Boundary fixture | Hold raw readings and tariff | Commit a small, inspectable snapshot rather than depend on a local file |
| Validator | Parse fields, check ranges, accumulate row errors | Return tagged data; never raise for expected bad input |
| Domain model | Represent validated appliance readings and scenarios | Encode units in field names or types; keep raw strings out |
| Calculator | Derive kWh, costs, and savings | Pure inputs/outputs; one unit conversion and one rounding policy |
| Verifier | Recalculate independent relationships | Avoid reusing presentation strings as test inputs |
| Renderer | Present valid, invalid, and blocked states | Never display stale partial totals as a valid report |
| Manifest builder | Record provenance and replay evidence | Stable fields and checksums; exclude secrets and incidental timestamps |
4.3 Data Structures
Use conceptual schemas rather than copying a complete solution:
RawReading = {
source_row: positive_integer,
appliance_name: text,
watts_text: text,
daily_hours_text: text,
days_used_text: text,
efficiency_factor_text: text
}
ValidatedReading = {
source_row: positive_integer,
appliance_id: stable_atom_or_text,
watts: non_negative_number,
daily_hours: number_in_0_to_24,
days_used: integer_in_report_period,
efficiency_factor: number_in_declared_interval
}
ValidationResult =
OK(list_of_ValidatedReading)
OR ERROR(list_of_{row, field, rejected_value, reason})
ScenarioResult = {
name: text,
appliance_kwh: list_of_{appliance_id, kwh},
total_kwh: non_negative_number,
tariff_r_per_kwh: non_negative_number,
cost_r: currency_value
}
ReportManifest = {
input_sha256,
report_period,
formula_revision,
rounding_policy,
elixir_version,
otp_version,
livebook_version,
verification_results
}
4.4 Algorithm Overview
Key Algorithm: Validate, Calculate, Reconcile
- Canonicalize the raw fixture into a stable order for hashing and review.
- Parse every field while preserving source-row identity.
- Accumulate independent validation failures for each row.
- If any row is invalid, return a blocked report with all actionable errors.
- For each validated row, calculate
watts × daily hours × days ÷ 1000. - Apply the scenario efficiency factor without changing the baseline data.
- Sum appliance values for each scenario.
- Multiply each total by tariff; round currency once at the declared boundary.
- Calculate absolute and percentage savings, handling a zero baseline explicitly.
- Independently recompute invariants and assemble report plus manifest.
Complexity Analysis:
- Time:
O(n)fornappliance rows; validation, calculation, and reconciliation each scan a bounded number of times. - Space:
O(n + e)for normalized rows andevalidation errors. - Replay cost: dominated by dependency startup, not the six-row domain calculation.
5. Implementation Guide
5.1 Development Environment Setup
Use a currently supported environment. Livebook 0.19.8 requires Elixir ~> 1.18 and OTP 25 or later; the current Elixir learning baseline is Elixir 1.20.2 with OTP 29.0.3.
$ elixir --version
$ livebook --version
$ git --version
$ livebook server
Record the actual versions shown on your machine in the manifest. Do not fabricate a match with the reference baseline. Create a dedicated Git branch or small repository for the notebook so a clean clone can be used for replay.
5.2 Project Structure
livebook-energy-report/
├── energy-field-report.livemd
├── fixtures/
│ ├── appliances-july-2026.fixture
│ └── invalid-readings.fixture
├── evidence/
│ └── clean-replay-transcript.txt
├── README.md
└── .gitignore
Keep fixtures human-readable. If the values are embedded directly in the notebook, retain the fixture directory for invalid and alternate scenario cases rather than duplicating full solution logic.
5.3 The Core Question You’re 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.
5.4 Concepts You Must Understand First
Stop and research these before building the report:
- 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.
- Pattern matching and tagged outcomes
- What information belongs in
OK(value)versusERROR(reasons)? - Which invalid inputs are expected domain outcomes rather than exceptional crashes?
- Book Reference: Programming Elixir 1.6, Chapters 4–7.
- What information belongs in
- 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.
- Units and rounding
- At which exact step do watt-hours become kilowatt-hours?
- Why should currency be rounded at one boundary?
- Reproducibility and provenance
- Which inputs must be snapshotted rather than fetched live?
- How will a checksum and formula revision help later review?
5.5 Questions to Guide Your Design
- Which cells are narrative, setup, input, domain logic, verification, and presentation?
- Which values have physical units, and are those units visible in names and output?
- Does validation report all actionable row errors or stop after the first?
- Is the efficient scenario derived from immutable baseline readings or from already rounded output?
- Can the invariant calculations detect a stale cost after the tariff changes?
- What exact information must be in the manifest for a reviewer six months later?
- What happens when baseline usage is zero and percentage savings would divide by zero?
- Does a reconnect reconstruct modules, bindings, results, and verification without manual memory?
5.6 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:
- Change only the report title. Which cells should become stale?
- Change tariff from
0.91to0.95. Which outputs and invariants must change? - Change one appliance’s efficiency factor. Should the baseline move?
- Remove the cell defining the calculator module and reconnect. Where should evaluation fail?
- 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.
5.7 The Interview Questions They’ll Ask
- “How does rebinding in Elixir differ from mutation?”
- “Why can a notebook show a plausible but stale result?”
- “What makes a computational report reproducible?”
- “Why put core logic in named functions or modules instead of a long cell?”
- “How do invariants differ from golden-output tests?”
- “Where should rounding occur in a calculation involving physical estimates and currency?”
- “What disappears when a Livebook runtime reconnects?”
5.8 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.
5.9 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 |
5.10 Implementation Phases
Phase 1: Foundation (1.5–2 hours)
Goals: Define the contract and obtain one transparent baseline calculation.
Tasks:
- Create the notebook outline and record versions, period, tariff, units, and assumptions.
- Add the six-row fixture and a separate invalid fixture.
- Write the validation-result and domain-record schemas in prose or pseudocode.
- 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:
- Build parsing and accumulated validation around stable row identity.
- Implement baseline and efficient calculations as pure transformations.
- Add the valid report, blocked report, and zero-baseline state.
- 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:
- Add the manifest and stable fixture checksum.
- Exercise tariff edits and document stale descendants.
- Reconnect to a clean runtime and evaluate in document order.
- 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.
5.11 Key Implementation Decisions
| Decision | Options | Recommendation | Rationale |
|---|---|---|---|
| Fixture source | Embedded table, committed file, live API | Embedded or committed snapshot | Small, inspectable, and replayable without network drift |
| Failure style | Raise, skip invalid rows, tagged result | Tagged result that blocks the report | Expected data defects remain visible and cannot silently change totals |
| Stage naming | Rebind one generic name, preserve distinct names | Preserve distinct names | Makes notebook lineage and review easier to follow |
| Currency arithmetic | Round each row, round at report boundary | Declare one boundary and reconcile | Avoids unexplained cent drift |
| Verification | One golden total, independent invariants | Both | Golden fixture proves example; invariants prove relationships |
| Current time | Read wall clock, explicit report period | Explicit report period | Prevents reruns from changing meaning |
6. 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
- 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.
- Multiple invalid fields: One row with negative watts and 27 daily hours reports both defects and blocks calculation.
- Tariff edit: Changing tariff marks cost/report descendants stale while usage remains conceptually unchanged.
- Zero baseline: Savings percentage renders as not applicable or a documented zero case; it never divides by zero.
- Rounding edge: Values near a half-cent follow one named rounding rule and reconcile.
- Clean runtime: Reconnect removes current modules and bindings; document-order replay restores all results.
- 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
7. Common Pitfalls & 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.
8. Extensions & Challenges
8.1 Beginner Extensions
- Add a third “behavior change” scenario while leaving baseline data untouched.
- Render a per-appliance contribution table sorted by kWh with stable tie-breaking.
- Add Portuguese and English labels without changing calculation values.
8.2 Intermediate Extensions
- Generate valid random fixtures and test aggregation/range properties.
- Add a committed CSV adapter that produces the same validated domain representation.
- Compare float-based physical estimates with decimal currency handling and document the boundary.
8.3 Advanced Extensions
- Add a CI replay check that opens the notebook’s core calculations in a testable Mix project.
- Sign the manifest or store an immutable artifact checksum for audit comparison.
- Model tariff bands and prove that band ordering, gaps, and overlaps are validated.
9. Real-World Connections
9.1 Industry Applications
- Engineering calculation sheets: Replace opaque spreadsheets with reviewed assumptions, executable formulas, and invariant checks.
- Experiment reports: Bind data snapshot, analysis revision, environment, and conclusions in one artifact.
- Financial scenario tools: Make rounding, units, and comparison baselines explicit.
- Operational runbooks: Preserve evidence and procedure while keeping actions bounded and reproducible.
9.2 Related Open Source Projects
- Livebook: The executable notebook and runtime platform used by the project.
- Elixir: The functional language and tooling foundation.
- ExUnit: Elixir’s built-in testing framework for extracting and testing pure domain logic.
9.3 Interview Relevance
- Functional design: Explain immutability, pure functions, explicit failures, and stage-oriented data flow.
- Reproducibility: Distinguish deterministic logic from a reproducible environment and artifact.
- Testing strategy: Show why golden examples and invariants complement one another.
- Debugging: Describe how stale ancestry and clean runtime replay expose hidden dependencies.
10. Resources
10.1 Essential Reading
- Elixir in Action, 3rd ed., by Saša Jurić — Chapters 2–4 for functional data modeling and failures.
- Programming Elixir 1.6 by Dave Thomas — Chapters 4–7 for pattern matching, functions, and modules.
- The Pragmatic Programmer, 20th Anniversary ed., by David Thomas and Andrew Hunt — orthogonality and automation topics.
10.2 Video Resources
- Livebook official homepage and introductory material — current product overview and learning entry points.
- Elixir official learning resources — talks and courses maintained from the language site.
10.3 Tools & Documentation
- Livebook 0.19.8 release: official release notes — current release baseline used by this guide.
- Livebook introduction notebook: official source — cells, sections, evaluation, and collaboration.
- Livebook runtimes: official runtime documentation — runtime lifecycle and alternatives.
- Elixir Getting Started: official guide — language foundations.
- Mix and OTP: official guide — extracting reusable modules and tests.
10.4 Related Projects in This Series
- Project 2: Interactive Capacity Planning Workbench — places a Kino event boundary around a pure scenario core.
- Project 3: Messy CSV Triage Clinic — expands validation, reconciliation, and provenance to bulk data.
- Project 4: Fault-Tolerant Telemetry Lab — adds process state and explicit lifecycle cleanup.
11. Self-Assessment Checklist
Before considering this project complete, verify:
11.1 Understanding
- I can explain why a visible notebook output may be stale.
- I can distinguish rebinding from mutation with a concrete example.
- I can distinguish deterministic calculation from reproducible execution.
- I can explain each invariant without reading the implementation.
- I know which state disappears on runtime reconnect.
11.2 Implementation
- All functional requirements are met.
- Invalid rows produce accumulated, traceable errors and no valid-looking report.
- Baseline and efficient scenarios use the same validated source data.
- Units, tariff, period, formula revision, and rounding policy are visible.
- Reference, edge-case, stale-cell, and replay tests pass.
- The
.livemddiff contains no secrets, local paths, or unexplained noise.
11.3 Growth
- I recorded one hidden dependency that clean replay helped me find.
- I documented what I would extract into a Mix project as the report grows.
- I can explain the project, architecture, and testing evidence in a technical interview.
12. Submission / Completion Criteria
Minimum Viable Completion:
- One
.livemdreport 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.
This guide was generated from LEARN_LIVEBOOK_ELIXIR_DEEP_DIVE.md. For the complete learning path, see the parent directory.