DVPApplied Creative AI Engineering

Search this course

Search lesson and reference material.

↑ ↓ to choose · Enter to open · Esc to close

Milestone 2 of 12

Developer workbench

Build reproducible command-line habits for media tooling.

Reproducibility envelope
terminal inputCLIJSON report
A controlled workbench links a terminal, dependency graph, and reviewable Git branches.
7 hoursPhase 1 · Engineering independenceRelease 3 · available
Learning objectives
Entry diagnostic

Explain how a CLI finds an input file and why its environment is reproducible.

A trustworthy media tool begins before its first function: you must know which directory, interpreter, dependencies, input file, and Git state produced the result. This milestone builds a workbench you can explain and recreate.

Required route: diagnostic and visual model (45 min), terminal and path practice (70 min), environment and dependency practice (75 min), file/JSON/CLI lesson (90 min), Git and failure clinic (55 min), transfer and evidence gate (65 min), resources and summary (20 min). Total: 7 hours.

Entry diagnostic

You receive a folder containing shot 014.json, metadata_qc.py, and an unknown .venv. Without editing anything, explain how you would prove your current folder, inspect the files, identify the Python interpreter, inspect Git changes, and reproduce the environment. State which commands only observe and which create project-local state.

Your answer passes the fast route only if it distinguishes a working directory from a file path, an environment from a lock file, and an unstaged diff from a commit.

Self-check

  1. Which observation proves where the terminal is operating?
  2. Why is an existing .venv not sufficient evidence of reproducibility?
  3. What should you inspect before staging a file?

Why this matters in CineQC

A QC score without provenance is a rumour. A clip may be read from the wrong export folder, a global package may change decoder behaviour, or a broad Git command may mix unrelated work into a fix. The workbench makes the chain inspectable: location → environment → inputs → command → output → diff → commit.

For CineQC-adjacent work, metadata often includes clip names, codecs, frame counts, frame rates, and measured QC scores. Safe paths and structured JSON preserve that context across Windows, Linux, CI, and later GPU work.

Visual model — the reproducibility envelope

Picture the CLI inside five nested boundaries:

  1. The terminal chooses the project directory.
  2. The environment chooses the interpreter and installed packages.
  3. the lock file chooses dependency versions.
  4. The CLI arguments choose input and output paths.
  5. Git records the reviewed source and configuration.

The output report is reproducible only when you can name all five boundaries. Media bytes and private production assets remain outside Git; a small lawful metadata fixture is enough for this milestone.

Sandbox lab

Use a new local practice folder and the isolated environment from this lesson for the required pathlib, JSON, CLI, terminal, and Git work. The shared browser Python lab is a live M01 exercise runner; you may replace its editor content for an optional standard-library scratch run, but it does not contain guided M02 exercises. Never rehearse file operations inside a production export directory. Every command below either observes state or creates a new named practice artifact; none deletes or overwrites an existing artifact.

Navigate safely in PowerShell

PowerShell commands operate on objects and support -LiteralPath, which treats brackets and wildcard characters as ordinary path text. Quote any path that may contain spaces. This sequence proves the current directory and enters a dedicated practice folder.

Runtime: Local Windows PowerShell 7 · creates only a new media qc practice directory when absent · 10 min.

Get-Location
Get-ChildItem -LiteralPath .
$practice = Join-Path (Get-Location) 'media qc practice'
if (-not (Test-Path -LiteralPath $practice)) {
    New-Item -ItemType Directory -Path $practice
}
Set-Location -LiteralPath $practice
Get-Location

Get-Location and Get-ChildItem observe. New-Item creates only the named folder after Test-Path proves it is absent. Set-Location changes terminal context, not file content.

Make the cross-platform distinction

POSIX shells use / separators, environment expansion such as $PWD, and -- to stop option parsing. PowerShell uses cmdlets, provider paths, and parameters such as -LiteralPath. Do not paste a shell command into another shell and hope its quoting semantics match.

Runtime: Local bash or zsh on Linux/macOS · creates only a named practice directory · 10 min.

pwd
ls -la
mkdir -p -- "media qc practice"
cd -- "media qc practice"
pwd

Portable Python code should use pathlib rather than manually joining \ or /. Shell activation commands remain platform-specific.

Self-check

  1. Why is -LiteralPath safer for an unfamiliar Windows filename?
  2. Which POSIX token prevents a filename beginning with - from becoming an option?
  3. Which layer should solve path separators: shell strings or pathlib?

Create an isolated environment with uv or venv

Choose one route for the lab. uv records project dependencies and a cross-platform lock in one workflow. Standard-library venv is the fallback when uv is unavailable. A virtual environment is project-local and disposable; source code and media never belong inside .venv.

Runtime: Local PowerShell · Python 3.12 and uv installed · creates .venv, pyproject.toml, and uv.lock in the practice folder · 20 min.

uv init --bare
uv venv
uv add --group dev pytest
uv lock
uv sync --frozen
uv run python --version

Runtime: Local PowerShell · Python 3.12 installed · standard-library fallback creates .venv · 15 min.

py -3.12 -m venv .venv
& .\.venv\Scripts\Activate.ps1
python -m pip install pytest
python -c "import sys; print(sys.executable)"
python -m pip freeze

Runtime: Local bash or zsh · Python 3.12 installed · standard-library fallback creates .venv · 15 min.

python3.12 -m venv .venv
source .venv/bin/activate
python -m pip install pytest
python -c 'import sys; print(sys.executable)'
python -m pip freeze

For the venv route, save reviewed direct dependencies in project configuration rather than treating an ad hoc pip freeze dump as a design. For the uv route, commit both pyproject.toml and uv.lock; never commit .venv. Recreate with uv sync --frozen and prove the interpreter again.

Runtime: Read-only configuration example · no command to run · 5 min.

[project]
name = "metadata-qc"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = []

[dependency-groups]
dev = ["pytest>=8,<10"]

Reproducibility means a fresh environment can be created from declared inputs. It does not mean copying .venv, relying on activation, or assuming the word python points to the same executable on every machine.

Keep disposable environments, generated reports, caches, and private media out of Git. Review the ignore file like source; a broad ignore pattern can hide something important.

Runtime: Read-only ignore-file example · save as .gitignore in the dedicated practice repository · 5 min.

.venv/
outputs/
__pycache__/
.pytest_cache/
*.mov

File I/O with pathlib and JSON

Start with a lawful metadata fixture rather than a real private clip. JSON carries values between tools, while pathlib.Path carries the location. Read with an explicit UTF-8 encoding. Refuse to overwrite an output so a repeated experiment cannot erase prior evidence.

Runtime: Local Python 3.12 or browser lab · save as shot_014.json when local · 10 min.

{
  "clip": "shot_014.mov",
  "codec": "prores",
  "frame_count": 240,
  "fps": 24.0,
  "qc_scores": {"flicker": 0.31, "stutter": 0.08}
}

Runtime: Local Python 3.12 · reads one JSON file and creates a new report path only · 20 min.

import json
from pathlib import Path

def load_metadata(path: Path) -> dict:
    with path.open("r", encoding="utf-8") as handle:
        return json.load(handle)

def build_report(metadata: dict, threshold: float) -> dict:
    scores = metadata["qc_scores"]
    worst_name, worst_score = max(scores.items(), key=lambda item: item[1])
    return {
        "clip": metadata["clip"],
        "worst_metric": worst_name,
        "worst_score": worst_score,
        "flagged": worst_score >= threshold,
    }

def write_new_json(path: Path, payload: dict) -> None:
    if path.exists():
        raise FileExistsError(f"Refusing to overwrite {path}")
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(json.dumps(payload, indent=2) + "\n", encoding="utf-8")

The functions expose three contracts: input JSON must contain named fields, the score mapping must be non-empty, and the output path must be new. Those assumptions become tests in M03.

CLI arguments make choices explicit

Hard-coded paths are invisible configuration. argparse turns them into named inputs, validates types, and produces --help without another dependency.

Runtime: Local Python 3.12 · append to metadata_qc.py; imports the functions above · 20 min.

import argparse

def parse_args():
    parser = argparse.ArgumentParser(description="Score a media metadata fixture")
    parser.add_argument("input", type=Path, help="Input metadata JSON")
    parser.add_argument("--output", type=Path, required=True, help="New report JSON")
    parser.add_argument("--threshold", type=float, default=0.25)
    return parser.parse_args()

def main():
    args = parse_args()
    metadata = load_metadata(args.input)
    report = build_report(metadata, args.threshold)
    write_new_json(args.output, report)
    print(json.dumps(report, sort_keys=True))

if __name__ == "__main__":
    main()

Run help first, then one bounded invocation. -- before the positional path is useful when a filename might begin with a hyphen.

Runtime: Local PowerShell · creates only outputs/shot_014-report.json when absent · 10 min.

uv run python .\metadata_qc.py --help
uv run python .\metadata_qc.py --output .\outputs\shot_014-report.json --threshold 0.25 -- .\shot_014.json

Runtime: Local bash or zsh · creates only outputs/shot_014-report.json when absent · 10 min.

uv run python ./metadata_qc.py --help
uv run python ./metadata_qc.py --output ./outputs/shot_014-report.json --threshold 0.25 -- ./shot_014.json

Git as a review boundary

Git does not make a change correct; it makes the reviewed change recoverable and comparable. Use a dedicated branch, stage explicit paths, inspect both unstaged and staged diffs, then commit one coherent result.

Runtime: Local PowerShell, bash, or zsh · inside the dedicated practice folder · creates a local Git history · 25 min.

git init
git status --short
git switch -c phase1/metadata-qc
git branch --show-current
git diff -- metadata_qc.py shot_014.json
git add -- metadata_qc.py shot_014.json pyproject.toml uv.lock .gitignore
git diff --cached
git commit -m "feat: add metadata QC report CLI"
git status --short
git log -1 --oneline

Recovery-safe habits are procedural: stop when a command targets an unexpected path; preserve unrelated work; inspect status and diff; make a branch before an experiment; stage named paths; keep generated media and secrets out of Git; and ask before using a command that discards working-tree changes. A commit is a checkpoint, not proof that the output is correct.

Self-check

  1. Which diff shows what will enter the next commit?
  2. Why stage named paths rather than every changed file?
  3. What two artifacts prove the CLI run is reproducible and reviewable?

Failure clinic

Three common workbench failures are wrong context, hidden environment state, and accidental overwrite.

Runtime: Local Python 3.12 or browser lab · deliberately raises FileNotFoundError until the base path is corrected · 15 min.

from pathlib import Path

project = Path.cwd()
input_path = project / "fixtures" / "shot_014.json"
print("cwd:", project)
print("input:", input_path)
print("exists:", input_path.exists())
print(input_path.read_text(encoding="utf-8"))

Do not “fix” this by scattering absolute paths through the code. Form the hypothesis “the terminal is in the wrong project directory,” print the resolved context, then either change the terminal directory or pass an explicit project/input argument.

If an import works only outside the environment, prove sys.executable and recreate from the declaration. If an output already exists, choose a new evidence filename after inspection; do not add an overwrite flag during this milestone.

CineQC transfer

Create a fresh practice repository containing the metadata fixture and CLI. Run it from a recreated environment at thresholds 0.25 and 0.40, using two distinct output filenames. Compare the JSON reports: the worst score remains 0.31, while flagged changes from true to false. Explain why the threshold is configuration but the measured score is evidence.

Then inspect the Git diff and commit only source, fixture, pyproject.toml, and lock data. Leave .venv, outputs, private clips, tokens, and machine-specific paths untracked.

Evidence gate

Submit a small repository snapshot or narrated screen recording with:

  1. A location/interpreter proof: current directory, sys.executable, and the exact fresh-environment command.
  2. A working artifact: CLI source, lawful metadata input, two new JSON outputs, and captured commands.
  3. Reproducibility evidence: dependency declaration plus lock or a clearly versioned standard-venv install procedure.
  4. Review evidence: branch name, clean or explained git status, staged diff, focused commit, and no private media or secrets.
  5. A changed-input explanation: predict and then show how threshold 0.40 changes only flagged.

The gate passes when another learner can recreate the environment, run the command, obtain the same structured fields, inspect the history, and hear you explain the path and dependency boundaries. State that metadata fixtures do not prove real decoder behaviour; that is a later experiment.

One-page summary

Required resource
docs
Python venv documentation
Use the creation, activation, and reproducibility passages from Python's standard reference. · 20 min
Go deeper
docs
Python pathlib documentation
Look up only the path composition and file-reading methods used by the lab. · 15 min
docs
Git status documentation
Decode working-tree and staging-area output without taking a separate Git course. · 10 min
Evidence gate

A reproducible CLI that reads media metadata and emits structured JSON.

Diagnostic route

Check the statements you can demonstrate in the challenge. Selections route your learning; they are not proof of mastery.

What can you demonstrate?

Start the full milestone.

Evidence gate

Submit an inspectable artifact for independent review. Only a verified diagnostic challenge or reviewed evidence can mark this milestone proven. Proof is local self-tracking, not tamper-resistant against edits to this browser storage.

Local mastery progress

Current state: not-started. Advance through learning, practice, and submitted evidence; proof requires a later passed review.

Notes

Your local study notes mount here when JavaScript is available.

Protected AI Tutor

Teaching modes mount here when JavaScript is available. The readable course remains available without them.