Workspace/Lesson workspace
Loading progress
Foundations40 min

Reproducible Python and a clean frontend handoff

Lesson 3 of 3
How to study this lesson

Read one section, trace the worked example, and try the knowledge check. Bookmark saves a shortcut; notes appear in My notebook. Mark lesson complete is your own assessment and does not mark its lab passed.

By the end, you can

  • Describe the evidence needed to reproduce a run.
  • Define a Python-to-frontend JSON interface.
  • Keep secrets and runtime responsibilities on the correct side of an API.

A commit identifies code, not the whole experiment

Git records versions of tracked files. A commit is valuable evidence of which source code was used, but it does not automatically identify dependency versions, interpreter version, environment variables, input data, or a remote model. Two engineers can check out the same commit and obtain different results because one has a newer library or a different feature flag.

A reproducible run therefore needs a small manifest. Record the code revision, Python version, dependency lock or pinned requirements, relevant non-secret configuration, input-data fingerprint, and random seed when applicable. Record a model identifier and prompt revision for later model-backed runs. Never confuse a seed with a universal reproducibility guarantee: remote services and some numerical operations can still behave nondeterministically.

Use environments to isolate decisions

Create a virtual environment for a Python project and install dependencies through that environment's interpreter. Pin direct dependencies and use a lock workflow when transitive resolution matters. Keep generated caches, credentials, and the virtual environment itself out of Git. Commit the instructions needed to rebuild the environment, not a copy of your machine's installed packages folder.

Small commits help explain why behavior changed. If a parser fix, a prompt change, and a dependency upgrade occur in one commit, a regression has three plausible causes. Separate changes when they can be reviewed independently. A useful verification command should work from a fresh checkout with documented setup, instead of relying on a notebook cell or shell variable that only exists on the author's laptop.

Python owns computation; the browser owns interaction

A minimal agent application can expose a Python HTTP endpoint that receives JSON and returns a structured result. The browser renders controls, sends requests, and shows progress. Node.js commonly runs JavaScript tooling or a server-side frontend layer; it is not required to replace Python's model and data code. Both runtimes can communicate through the same documented HTTP contract.

For example, POST /runs can accept {"question":"Which orders are delayed?"} and return {"run_id":"r17","status":"queued"}. A later GET /runs/r17 returns progress and a final answer. The frontend needs field definitions and status semantics, not access to Python's internal classes. This boundary permits a command-line client, a browser, and an integration test to use the same application behavior.

A handoff contract includes the unhappy paths

Specify whether a request completes synchronously or starts a background run. If it starts a run, explain how the client polls, cancels, and distinguishes completed, failed, and cancelled. A run with a partial answer must not look identical to a completed run. An additive optional field is often easier to evolve than changing the meaning of an existing status.

API keys remain in a trusted server environment. A frontend build that embeds a key can expose it to anyone who receives the JavaScript. The browser should authenticate the user to your application, while your server authorizes access to each run and calls model services. Returning a run ID is not sufficient authorization; another user must not be able to fetch a run simply by guessing its identifier.

Fingerprints help compare runs honestly

The example serializes a non-secret configuration with sorted keys and compact separators, hashes those bytes, and builds a JSON response envelope. Rearranging dictionary insertion order does not change the configuration fingerprint. Changing a substantive parameter does. This provides a small reproducibility tool and a sample of what a frontend can safely receive.

A fingerprint detects equality of the exact chosen representation; it does not prove the inputs were correct or complete. Document normalization before hashing and keep the underlying manifest accessible to authorized reviewers. In a portfolio project, include one successful run and one failure fixture, setup instructions, and a short explanation of which facts are deterministic. These artifacts let another engineer inspect your reasoning instead of merely watching a polished demo.

Work through the code

The program fingerprints canonical non-secret configuration and prints a browser-friendly run envelope. The hash is shortened for display only and is not an authorization token. Change max_items to see the fingerprint change. A real run manifest should also record code, input, and dependency identities.

m01_lesson_3.py
python
import hashlib
import json

def canonical_bytes(value):
    return json.dumps(value, sort_keys=True, separators=(",", ":"),
                      allow_nan=False).encode("utf-8")

def fingerprint(value):
    return hashlib.sha256(canonical_bytes(value)).hexdigest()[:12]

config_a = {"schema_version": 1, "max_items": 4}
config_b = {"max_items": 4, "schema_version": 1}
manifest = {"config_fingerprint": fingerprint(config_a),
            "input_rows": 2, "schema_version": 1}
envelope = {"run_id": "demo-001", "status": "completed",
            "result": {"accepted": 2}, "manifest": manifest}
print("order independent:", fingerprint(config_a) == fingerprint(config_b))
print("change detected:", fingerprint(config_a) != fingerprint({**config_a, "max_items": 5}))
print(json.dumps(envelope, sort_keys=True))
EXPECTED / ILLUSTRATIVE OUTPUT
order independent: True
change detected: True
{"manifest": {"config_fingerprint": "2efc7884f1a8", "input_rows": 2, "schema_version": 1}, "result": {"accepted": 2}, "run_id": "demo-001", "status": "completed"}

Run Python snippets locally with the prerequisites named above. The module coding lab runs directly in your browser.

Pause and reason

A teammate reproduces your commit but gets a different answer from a hosted model. Name four missing manifest fields and explain why pinning a Python dependency alone cannot guarantee the same answer.

Check your understanding

A browser frontend needs to call your model-backed Python service. Where should the provider API key be configured?

Your notes

Explain the mechanism in your own words. Add a failure you want to test.

Saved notes appear in your notebook

Go deeper with primary sources

Practice this module