Skip to content
C.W.K.
Lesson 05 of 05 · published

The Frame Knows When It Was Taken

~14 min · timestamps, staleness, capture-time, honesty, metadata

Level 0Closed Lens
0 XP0/45 lessons0/13 achievements
0/100 XP to next level100 XP to go0% complete

"Now" Was Twenty Seconds Ago

Here is a failure that does not look like one. Pippa asks for a look at the game "now". The recorder answers with the newest frame of that input. The picture arrives, the model describes it, Dad hears the description. Everyone is satisfied. But the input's picture had stalled twenty seconds earlier, and the newest frame the recorder held was from before the stall. Pippa described a screen that was no longer on the screen, with confidence, because nothing in the answer said otherwise.

Until Coop 1110-12 that could really happen. The recorder stamped a peek with the time of the ask, and the newest-frame JPEG carried the time its file was written. Both times were "now", and both were true about the wrong thing.

The Rule: Capture Time, Never Ask Time

The fix is a rule about which clock a frame carries, applied everywhere a frame is kept:

  • The newest-frame JPEG that the recorder refreshes for each open input has its file time set to its frame's capture time, so any reader's "how old is this?" is the frame's age, not the encoder's.
  • A peek's JPEG gets a small note beside it: captured_at (when the frame was captured), written_at (when the JPEG was written) and source (one-shot for a device opened just for this peek, gimbal hold, or recording).
  • A gimbal move's before and after frames carry their capture times the same way.

With those two times side by side, staleness stops being a guess. A one-shot peek opened the device for this request, so its frame is fresh by construction. A peek answered from a running recording is as old as written_at - captured_at, and on a stalled input that gap is large.

What a Look Says When It Is Stale

Every deck and camera look puts the frame's capture time in its at field. The play-session look is the one exception: its at is when the answer was built, and the stream frame's age rides in its read line instead. Past five seconds (the same bound as an input's stall), the answer adds a stale line that names the input, the frame's time and its age, for example: "STALE: the game card stalled; newest frame 12:00:03, 20 s ago, not the screen now." That line lives in its own field, so no trimming of the read line can ever drop it, and it takes the place of the echo of the asker's reason, which pays for its tokens and keeps the look inside its budget (the worst-case test prices both versions).

A crop is stricter. A crop exists to read fine detail on the screen as it is, so a stale live frame is refused outright, with its time, and the refusal tells the caller exactly what to do instead: crop that moment from the recording with at= set to the frame's time. The caller is not left guessing whether the text it is reading is current.

Why This Is a Privacy Lesson Too

This track is about price, but this lesson is also about trust, and trust is what the second half of the quest is built on. A system that watches a home must never present an old picture as the present one. Pippa's own decisions (about what to say, about what is happening in the room) rest on the same picture, and so do the later checks on what may leave the house, which judge recorded moments by when they were recorded, not by when somebody asked for them. A frame that knows when it was taken is the smallest unit of honesty the whole design depends on.

Code

A peek's note, a frame's age, and the stale line (trimmed excerpts, backend/recorder_link.py and backend/looks.py)·python
def frame_age(note, now=None):
    """How old a peek's frame was when its JPEG was written, from its note:
    both times are the recorder's own clock. None when the note does not say
    when it was captured."""
    captured = note.get("captured_at")
    if not isinstance(captured, (int, float)):
        return None
    written = note.get("written_at")
    end = float(written) if isinstance(written, (int, float)) else (time.time() if now is None else now)
    return max(0.0, end - float(captured))


# In Eyes._peeked: a frame from a running recording says how old it is
if note.get("source") != "recording":
    return NowFrame(picture, "a one-shot peek (not recording)", at)
age = frame_age(note) or 0.0
if age < STALE_AFTER_S:
    return NowFrame(picture, f"the recording's newest frame, {age:.1f} s old", at)
return NowFrame(picture, f"the recording's newest frame, {_age(age)} old", at,
                f"STALE: {source.row['name'][:STALE_NAME_MAX]} stalled; newest frame {_clock(at)}, "
                f"{_age(age)} ago, not the screen now.")
Stamp the capture time on the file itself, and read it back (runnable)·python
import json
import os
import tempfile
import time
from pathlib import Path

folder = Path(tempfile.mkdtemp())


def save_frame(jpeg_bytes, captured_at, source):
    path = folder / "latest.jpg"
    path.write_bytes(jpeg_bytes)
    os.utime(path, (captured_at, captured_at))          # file time = capture time
    note = {"captured_at": captured_at, "written_at": time.time(), "source": source}
    path.with_suffix(".json").write_text(json.dumps(note))
    return path


def describe(path, stale_after=5.0):
    note = json.loads(path.with_suffix(".json").read_text())
    age = note["written_at"] - note["captured_at"]
    if note["source"] == "recording" and age >= stale_after:
        return f"STALE: newest frame {age:.0f} s old, not the screen now"
    return f"fresh ({age:.1f} s old, {note['source']})"


print(describe(save_frame(b"...", time.time() - 0.4, "recording")))
print(describe(save_frame(b"...", time.time() - 20, "recording")))     # a stalled input
print("file mtime age:", round(time.time() - (folder / "latest.jpg").stat().st_mtime), "s")

External links

Exercise

Find one place in a system you know where a cached value or image is served as "current" (a dashboard tile, a thumbnail, a status badge). Write down which timestamp it carries: the time it was produced, the time it was cached, or the time it was asked for. Then change it, or sketch the change, so the reader sees the production time and an explicit stale marker past a threshold.
Hint
The stale marker belongs in its own field, not appended to a description that might be truncated. Oriel learned that its stale line had to survive any trim of the read line, so it gave it a field of its own.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign in — Please sign in to comment.

No comments yet — be the first.