# Offline scene-preview handoff audit lab

This original Python teaching exercise checks whether a small, custom normalized
handoff record is internally consistent. It is **not a native Topview JSON
parser**, an official Topview integration, an actual renderer, or a product
runtime test. The field names and acceptance policy below belong to this lab.
No upstream product source code is included.

The example artifact is a short literal byte string saying that it is not an
image or video. Even the `image` and `video` scenarios use those same synthetic
bytes. They teach metadata and byte-identity checks; they supply no evidence
that any real scene, image, or video was rendered.

## Run locally

Requires Python 3.10+ and only its standard library. From this directory:

```sh
python3 -B handoff_audit.py
python3 -B -m unittest -v test_handoff_audit.py
python3 -B handoff_audit.py --write-csv
```

The last command deterministically replaces the sibling
`synthetic-handoffs.csv`. No other files are written by the lab. There are no
network calls, subprocesses, package installs, authentication, or timestamps.
The CSV is a report, not an input parser. Tests compare its checked-in content
with regenerated output.

The demonstration intentionally contains blocked examples and exits with code 0
if it runs successfully. That exit code does **not** mean every handoff passed.
A caller using the function as a gate must inspect `AuditResult.ready`, which is
true only for `READY`; `BLOCKED` and `INVALID` both fail closed.

## Custom input contract

Call `audit_handoff(record, artifact_bytes)`. `record` must be a plain Python
dictionary containing exactly the following keys. `artifact_bytes` must be
nonempty Python `bytes`, already read by the caller. It is hashed internally;
a caller-supplied “actual hash” cannot stand in for those bytes.

| Field | Required value |
| --- | --- |
| `schemaVersion` | Exact integer `1`; a boolean is invalid |
| `sceneProjectId`, `sceneId` | Nonempty strings with no surrounding whitespace |
| `sceneSequence` | Exact integer from 0 through 9,007,199,254,740,991 |
| `previewProjectId`, `previewSceneId` | Nonempty strings with no surrounding whitespace |
| `previewSceneSequence` | Same integer type and range as `sceneSequence` |
| `previewKind` | Exact string `image` or `video` |
| `checksComplete` | Exact boolean; must be `True` to pass |
| `renderComplete` | Exact boolean; must be `True` to pass |
| `expectedSha256` | 64 lowercase hexadecimal characters |
| `humanReviewed` | Exact boolean; must be `True` to pass |
| `videoFreshness` | Boolean or `None`; see the special rule below |

All fields are mandatory, including `videoFreshness`. Unknown fields are
rejected to prevent silently accepting misspelled check names. Missing values,
null sequences, strings such as `"true"`, floating-point sequences, negative
sequences, and Python booleans masquerading as integers produce `INVALID`.

For an image, `videoFreshness` must be `None` because that particular assertion
is inapplicable. For a video, only the exact boolean `True` passes. `None`
means unknown and produces `video_freshness_unknown`; `False` means not declared
fresh and produces `video_not_declared_fresh`. The CSV serializes `None` as the
explicit word `null`, never an empty cell. A `True` video assertion is a
hypothetical input allowed by this teaching schema, not an observed native
product field or a claim of verified product video freshness. The demonstration
therefore includes only an unknown-freshness video, which is blocked.

After schema validation, the lab compares both project and scene identity,
requires exact sequence equality, checks the three declared completion/review
booleans, compares the expected hash with the actual bytes' SHA-256 digest, and
applies the video freshness rule. A future sequence also fails equality rather
than being assumed safer than an older one. Reasons are returned in a stable
order; multiple independent blockers can be reported together.

## Exact demonstration output

```text
current-ready: READY
stale-sequence: BLOCKED (preview_sequence_mismatch)
incomplete-render: BLOCKED (render_not_declared_complete)
altered-bytes: BLOCKED (artifact_bytes_mismatch)
unknown-video-freshness: BLOCKED (video_freshness_unknown)
wrong-project-identity: BLOCKED (project_identity_mismatch)
incomplete-checks: BLOCKED (checks_not_declared_complete)
unreviewed: BLOCKED (human_review_not_declared)
Summary: 1 READY, 7 BLOCKED; synthetic assertions only.
```

The included suite has 29 test methods, with additional table-driven subcases.
It checks all demonstration outcomes, project and scene mismatches even with
equal sequences, unknown and false video freshness, malformed types, every
missing required field, sequence boundaries, multiple failures, mutation safety,
and byte-for-byte CSV reproducibility.

## What a passing result cannot prove

- **Byte identity is not visual correctness.** SHA-256 comparison checks whether
  supplied bytes match an expected digest. It does not inspect framing, lighting,
  geometry, color, camera motion, visible content, or even the media file format.
- **Declarations are not execution evidence.** `checksComplete`, `renderComplete`,
  and `videoFreshness` are caller assertions. This lab neither runs checks nor
  observes a render job, browser, video export, console, or renderer completion.
- **Review is not authenticated.** `humanReviewed=True` is self-reported. There is
  no reviewer identity, signature, timestamp, approval history, or proof that a
  person reviewed these exact artifact bytes and this exact scene revision.
- **Sequence numbers are local.** `sceneSequence` is interpreted only in the
  declared project and scene context. The same number in another project is not
  the same revision, which is why both identities must match independently.
  This is a lab policy, not a claim about a product's native revision semantics.
- **The record is not a trust anchor.** There are no signatures, trusted expected
  hashes, verified project identifiers, or independently observed “current”
  revision. An attacker or mistaken caller can supply a consistently wrong
  record, replace bytes and their expected hash together, or assert review.
- **No race protection exists.** A source scene may change after the record is
  assembled. There is no atomic snapshot, revision locking, or later freshness
  recheck. A sequence match alone cannot establish live currentness.
- **No native compatibility or licensing conclusions follow.** The custom fields
  do not document an official Topview export schema or prove any upstream
  behavior. This code is an original educational example, not copied upstream
  code, and makes no claim about upstream licensing.

For an actual handoff, obtain the current source identity and revision from a
trusted source, retain the actual rendered artifact, independently observe job
completion, and bind a real reviewer approval to that exact source-and-artifact
pair. Implementing those integrations is outside this lab.
