Asset index and evidence-integrity record
Captured: 2026-07-26. Codelab "Deploy a website with Cloud Run", last updated 2026-03-20.
This file leads with what went wrong, because an entire capture set was discarded during this study and a reader is entitled to know exactly which images survived scrutiny and which did not.
1. The capture failure, stated plainly
10 of Persona A's 11 screenshots were invalid and are not published.
screencapture photographs the frontmost window and, within it, whichever tab is visually selected. Browser automation drives a tab without selecting it. Persona A drove the Cloud Shell tab programmatically while the visually-selected tab remained the codelab page — so every capture returned the same stale frame of the codelab.
Six files were byte-identical. This was found by hashing, not by looking:
baa0bb6d… s2-cloudrun-api-enabled · s2-cloudshell-active · s2-compute-api-prompt · s2-end-state
672b9d13… s3-npm-start-listening · s3-setup-complete
The remaining four had distinct hashes and were still wrong — different scroll positions of the same codelab page. Critically, s4-permission-denied-error.png, which purported to show the study's central error, showed "1. Before you begin".
A correction inside the correction. The first quarantine sweep was too broad. s3-fancy-store-preview.png was swept in without individual inspection and is in fact genuine — Persona A challenged the claim, the file was re-examined, and it was restored. One of the two published Persona A captures exists because a subagent pushed back on its coordinator.
Root cause, and why the first fix failed
The initial mitigation — open -a "Google Chrome" before each capture — addressed window focus and did nothing about tab selection. A later attempt to drive tab selection through Chrome's AppleScript interface worked for tab control but still failed to capture, because Chrome sits on a different macOS Space that cannot be switched to without Accessibility permission. The final capture attempt returned the desktop wallpaper.
save_to_disk on the browser screenshot tool writes no file, reproducing a finding already documented in the earlier study in this repository.
What replaced it
Headless Chrome, which bypasses the window system entirely:
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --headless --disable-gpu \
--hide-scrollbars --virtual-time-budget=6000 --screenshot=out.png \
--window-size=2400,1800 "<url>"
This is strictly better for documentation capture: no notifications, no browser chrome, no debugging banner, deterministic 2400×1800. Its limitation is that it carries no authenticated session, so console screenshots could not be produced this way.
assets/capture.sh retains a hash-based self-check that prints !! DUPLICATE CAPTURE on a repeated frame, so this class of failure fails loudly rather than silently in future.
2. Published images
| File | Source | Shows | Used |
|---|---|---|---|
doc-real-step2.png … doc-real-step10.png |
headless Chrome, 2400×1800 | codelab steps 2–10 as published | reference |
ann-step5-deploy.png |
annotated from doc-real-step5 |
5 defects on one page: the Cloud Shell variable, the 5-region prompt, Pod status, 2019 output, unrendered **Note:** |
slide 14 |
ann-step9-cleanup.png |
annotated from doc-real-step9 |
cleanup commands: what works (green), what is conceded (yellow), what fails (red) | slide 10 |
s1-before-you-begin.png |
Persona A, screencapture |
codelab step 1 — genuine, because step 1 is the codelab page | slide 5 |
s3-fancy-store-preview.png |
Persona A, screencapture |
Fancy Store live on a cloudshell.dev Web Preview URL — verified genuine after being wrongly quarantined |
slide 15 |
Annotation method
assets/make_annotations.py, built on the existing assets/annotate.py (Pillow). Coordinates in display space, scaled to pixels. Annotations are burned into the pixel data, so they survive base64 embedding and cannot be detached from the evidence they mark.
Colour is semantic and matches the deck: blue Persona A · green Persona B or "this works" · red the defect · yellow the hidden cost. No annotation covers UI copy; all explanation lives in the caption.
3. What could not be captured, and why
| Wanted | Why not | Substitute |
|---|---|---|
| Screen recordings of either persona | Requires photographing a Chrome window on a macOS Space unreachable without Accessibility permission | Deck uses animated transcript replays built from real captured output and real measured timings, labelled "transcript replay — not a screen recording" |
| Console views: Artifact Registry leftovers, Cloud Build history, orphaned bucket object | Headless Chrome carries no authenticated session; windowed capture blocked as above | Verbatim gcloud transcripts in assets/transcripts/ and the persona logs. Every console claim in the report is backed by CLI output, not by an image |
| Cloud Shell terminal states for steps 5–9 | Persona A stopped saving files once cap.sh was confirmed unreliable |
Described in persona-a-log.md, verified at the time via the browser tool's own screenshots |
No fabricated, reconstructed, or vendor-supplied screenshot appears anywhere in this deliverable. Where an image does not exist, the deck renders verbatim text explicitly labelled as a transcript.
4. Transcripts and logs
| File | Contents |
|---|---|
logs/persona-a-log.md |
9 steps + 2 interventions, per-step timestamps, ambiguities logged before resolution, verbatim errors |
logs/persona-b-log.md |
9 steps, same schema, plus the post-cleanup audit |
logs/probe-propagation.md |
The controlled experiment that overturned this study's own first conclusion |
logs/concept-inventory.md |
56 concepts, per-step, with definition status — built before either run |
logs/scoring.md |
Two-axis dataset, time adjustment stated, quadrant thresholds stated, metric blind spots stated |
transcripts/b-step3-recovery.txt |
Raw npm/build output from Persona B's step-3 recovery |
5. Redaction
The account demeketester@gmail.com is a dedicated test account, not a personal address, and appears in verbatim error text where it is part of the evidence (the PERMISSION_DENIED messages name it). Project numbers and the default compute service-account address are retained for the same reason — they are what the errors say.
One privacy incident occurred and was handled. An early test capture caught a macOS notification containing a phone number and a personal event name. That file was deleted immediately and never entered the asset set. macOS notifications render into any windowed capture; a Focus mode should be enabled before any future windowed capture run.
6. Reproduction
# documentation captures (no auth needed)
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --headless --disable-gpu \
--hide-scrollbars --virtual-time-budget=6000 --screenshot=doc.png \
--window-size=2400,1800 "https://codelabs.developers.google.com/codelabs/cloud-run-deploy#4"
./.venv/bin/python codelab-study/assets/make_annotations.py # burn callouts
./.venv/bin/python codelab-study/assets/build_deck.py # rebuild deck
./.venv/bin/python codelab-study/assets/md_to_pdf.py # rebuild PDFs
Note the codelab's step fragments are 0-indexed: #4 renders step 5. Files were renamed to match actual content.