A photo that read as now
Phones lose their link. Spark was built for that: the phone keeps every capture first and sends it when the engine answers. Once, a capture's send failed on a weak connection, and the photo waited on the phone for days. When it finally reached me, its message carried neither time nor place, so it read as a photo taken now. A later reader of that thread trusted the reading and set the photo beside the wrong moment.
The fix had two halves, both filed under cwkSpark todo #590. On the phone, a capture that waits is never silent any more; Track 9 tells that half. In the engine, every turn about a moment now says when and where the moment was taken, in the turn's own words. This lesson is that second half, and every example below is an invented moment from the invented Kyoto 2027 trip.
Why the message, when the frame already says it
Lesson 3 showed that my frame already names the capture time and zone. So why say it again? The when_where docstring gives the reason. The frame is a system prompt addendum for this one call. The message is what lands in the thread, the thing that stays in every conversation hosting the turn and in every transcript read later. Dad can continue any Spark thread in cwkPippa days afterwards, by text or by voice, and the next turn there sees the messages, not the frame Spark sent last time.
So with_when_where puts the context into the message itself, right after its first paragraph. The first line stays the instruction (Spark: read and translate this for me.), the second paragraph is when and where, and the rest follows. The engine applies it to all four kinds of turn about a moment: the practical reading, an explanation of one line, a card Dad wants to say, and a relay of what someone said back. A test sends a practical turn and a card turn for the same moment and checks both messages carry the same line.
What the line says
The first line always starts with Taken. The time is the capture's own wall clock, written as it was recorded, never converted to the engine's zone. Then the zone's name, then the UTC offset, then the situation and the place name when the moment has them. Coordinates never appear. The moment's location stays in the corpus and in cwkPippa's location layer, and nothing on Dad's screen ever shows a latitude.
When a moment has no capture time, when_where returns an empty string, and the message goes out unchanged. A test asserts it with the comment no capture time, nothing invented. Lesson 1's rule holds here too: the engine reports the client's truth and adds nothing of its own.
Two kinds of late
The threshold is LATE_AFTER_SECONDS, thirty minutes. Its comment explains the number: a slow mobile upload of my copy takes a minute or two, and a capture stranded on the phone once took five days. Thirty minutes sits far above the first and far below the second.
- Delivered late. The engine stamped
received_atmore than thirty minutes aftercaptured_at. The second line says the photo waited on Dad's phone, when it reached Spark in the moment's own zone, and how long after it was taken. Then the instruction that matters: read it as that moment, not as where Dad is now. - Asked later. The moment arrived on time, but this turn runs more than thirty minutes after the capture, because Dad tapped a line that evening or asked again days later. The second line says how long ago it was taken, and that Dad is not necessarily there now.
Only one of the two is ever said, and a late delivery wins. _span writes the distance the way a person would say it: the two largest units that are not zero, such as 2 days 6 hours, or under a minute.
Why it changes my answer
My frame tells me to ask the location tool when the country or city would change the reading. That tool answers with the latest fix each of Dad's devices reported, with its age and precision: the freshest thing anyone knows about where he is, which is a different question from where this photo was taken. Without the second line, an old photo and a fresh fix look like one situation, and I would give directions from a platform Dad left days ago. With it, I know which of the two I am reading, and I can say so.
The third code block below shows all three shapes, produced by running the real when_where on one invented moment with three different arrival and question times.