---
title: "Chapter 10: Prove Cloud Parity"
description: "Run the same locked commit on Mac and Linux, then classify differences instead of hiding them."
type: "lesson"
order: 10
chapter: "04-cloud-and-system-tests"
duration: "45–90 minutes"
---

# Chapter 10: Prove Cloud Parity

## Objective

Run the same locked commit on Mac and Linux, then classify differences instead of hiding them.

Your tutor should stop at each gate and wait for your evidence before continuing.

## Concept

A successful Mac run is one data point. A successful Linux run is another. The goal is one reviewed dependency declaration and equivalent application behavior across supported systems. Nix cannot make Darwin into Linux, turn ARM instructions into x86, or make a package available on an unsupported platform.

Use an explicit platform matrix. An Apple Silicon Mac usually evaluates `aarch64-darwin`; an ARM Linux VM uses `aarch64-linux`; a typical x86 cloud runner uses `x86_64-linux`. These are three different package outputs. A Mac binary cache entry does not satisfy a Linux dependency.

Other differences survive toolchain pinning: case-sensitive paths, locale, filesystem permissions, kernel interfaces, ports, clocks, and external APIs. Tests should expose these differences. Avoid “fixes” that silently skip a failing supported platform.

## Concept check

**Q1.** Can a cached Darwin Python closure run on x86 Linux?

**Q2.** Does a Linux-only failure prove every part of Nix reproducibility failed?

<details>
<summary>Concept answer key — attempt first</summary>

## Answer key (concept)

**Q1.** No, outputs are platform-specific. **Pass criteria:** mention both OS and architecture.

**Q2.** No. Classify it as dependency, system, data, or application behavior first. **Pass criteria:** investigate evidence rather than treating parity as magic.

</details>

## Gate: Establish a green source commit

Use the reviewed completion implementation, not the intentionally failing exercise commit. Record:

```bash
git rev-parse HEAD
git status --porcelain
nix --version
devenv version
uname -sm
```

**Pass:** a clean working tree and a known commit. Confirm the lockfiles are tracked. Do not run `devenv update` in the cloud just because startup is slow.

## Gate: Reproduce on Linux

On the restricted Linux worker, install Nix and devenv using Chapter 01/02 or the pinned CLI bootstrap in Chapter 11. Clone the learning repository and check out the exact full commit from the Mac:

```bash
git clone YOUR_LEARNING_REPOSITORY_URL agent-lab
cd agent-lab
git checkout YOUR_RECORDED_COMMIT
devenv test
git diff --exit-code -- devenv.lock
```

Replace the two uppercase placeholders before running. This is a human-selected repository, not an endpoint invented by an agent. The first cloud test needs no model key. Keep agent execution separate from basic portability verification.

## Gate: Compare evidence

Fill this table with actual results:

| System | Source commit | Lock hash | Nix / devenv | Unit result | DB result |
|---|---|---|---|---|---|
| Your Mac | | | | | |
| Your Linux VM | | | | | |

Inside the development shell, compute a portable lock digest:

```bash
python -c 'import hashlib; print(hashlib.sha256(open("devenv.lock", "rb").read()).hexdigest())'
```

**Pass:** identical source and lock, both behavior suites green, with host and CLI differences recorded. Expected test counts must match. A “skipped integration test” is not cloud parity.

## Gate: Diagnose a deliberate mismatch

On a disposable branch, change the case of the `taskboard.py` import in a test. Observe behavior on each filesystem. Restore the correct import. Then remove a declared command such as `ruff` and check whether your host installation masks the omission. Explain why a clean CI runner is valuable even when a development shell succeeds.

If a real package is platform-specific, use an explicit conditional such as `lib.optionals pkgs.stdenv.isLinux [ pkgs.inotify-tools ]`. Preserve the same user-visible behavior where possible, and document Linux-only checks separately.

## Known failure modes

- A clean shell is not automatically a clean filesystem or empty environment.
- A lock update while debugging changes the experiment; keep it separate.
- Long socket paths, already running services, and host-installed tools can look like package problems.
- A remote Linux builder builds Linux outputs; it does not execute Linux binaries natively on macOS.

## Check your understanding

**Q3.** Which two identities must match before comparing results?

**Q4.** Where should Linux kernel/systemd checks run?

<details>
<summary>Answer key — attempt every question first</summary>

## Answer key

**Q3.** The source commit and dependency lock. **Pass criteria:** both, not only a branch name.

**Q4.** On an appropriate Linux environment or remote builder. **Pass criteria:** separate system tests from Mac application checks.

</details>

## References

- [Cross-platform devenv recipes](https://devenv.sh/recipes/cross-platform/)
- [Nix remote builds](https://nix.dev/manual/nix/stable/advanced-topics/distributed-builds.html)

---

[← Chapter 09](/nix-agent-lab/03-controlled-agents/09-isolation-before-autonomy/) · [Next: Chapter 11 →](/nix-agent-lab/04-cloud-and-system-tests/11-ci-and-caches/)
