plan: a place the film never left is not a new place
Browse filescheck_place_handoff's arrival half compared each beat against shot N-1 only,
so a location established in shot 1 and not re-named in shot 2 read as newly
arrived in shot 3. Live: platform / (unnamed) / platform on a chain that
spends every hop on one platform, warning that shot 2 "never goes there" when
shot 2 is standing on it.
The film's current place carries forward across beats that name none. What the
check is actually about is whether this beat names somewhere other than where
the previous hop ENDED, because that is what the live frame at its first frame
shows. Leaving and coming back -- kitchen / hallway / kitchen -- is still a
move and still warns.
Third lint this session with the same defect: tested against the wrong
baseline, and every one of them was telling the author to change work that was
already right.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014VB4Dw6F79643vySkf19KV
- plan.py +23 -15
- tools/check_templates.py +32 -0
|
@@ -246,21 +246,29 @@ def check_place_handoff(shots, ref_plan=None):
|
|
| 246 |
"makes her way", "makes his way", "makes their way",
|
| 247 |
)
|
| 248 |
|
| 249 |
-
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
|
| 253 |
-
|
| 254 |
-
|
| 255 |
-
|
| 256 |
-
|
| 257 |
-
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 264 |
|
| 265 |
# The same defect seen from the other side. Both LM Studio models plated
|
| 266 |
# the opening location, moved the story somewhere else, and gave the new
|
|
|
|
| 246 |
"makes her way", "makes his way", "makes their way",
|
| 247 |
)
|
| 248 |
|
| 249 |
+
# Where the film currently IS, carried forward across beats that name no
|
| 250 |
+
# place at all. Comparing only against shot N-1 made a place the film never
|
| 251 |
+
# left read as newly arrived the moment one beat in the middle did not
|
| 252 |
+
# happen to name it: platform / (unnamed) / platform warned on shot 3, for
|
| 253 |
+
# a chain that spends every hop on one platform. What matters is whether
|
| 254 |
+
# this beat names somewhere OTHER than where the previous hop ended, which
|
| 255 |
+
# is what the live frame at its first frame actually shows.
|
| 256 |
+
current = set()
|
| 257 |
+
for i, s in enumerate(shots):
|
| 258 |
+
low = (s.get("beat") or "").lower()
|
| 259 |
+
named = {t for t in places if ("@" + t).lower() in low}
|
| 260 |
+
if i and current:
|
| 261 |
+
for tag in sorted(named - current):
|
| 262 |
+
if any(v in low for v in _ARRIVES):
|
| 263 |
+
continue
|
| 264 |
+
warnings.append(
|
| 265 |
+
f"shot {i + 1}: @{tag} is a new place and shot {i} is "
|
| 266 |
+
f"somewhere else. The hop opens on a live frame of the old "
|
| 267 |
+
f"location, so the only way to obey is a cut. End shot {i} "
|
| 268 |
+
f"with the arrival, or have shot {i + 1} do the travelling."
|
| 269 |
+
)
|
| 270 |
+
if named:
|
| 271 |
+
current = named
|
| 272 |
|
| 273 |
# The same defect seen from the other side. Both LM Studio models plated
|
| 274 |
# the opening location, moved the story somewhere else, and gave the new
|
|
@@ -141,6 +141,38 @@ def main():
|
|
| 141 |
print(" FAIL %s: warned=%s wanted=%s" % (label, got, want))
|
| 142 |
fails.append(label)
|
| 143 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 144 |
# The last shot of any pattern that ends a chain must not be left `ongoing`.
|
| 145 |
closers = [s for s in all_shots
|
| 146 |
if (s["directives"].get("tail") in ("settle", "hold"))]
|
|
|
|
| 141 |
print(" FAIL %s: warned=%s wanted=%s" % (label, got, want))
|
| 142 |
fails.append(label)
|
| 143 |
|
| 144 |
+
# ...and the arrival half has to carry the current place forward across a
|
| 145 |
+
# beat that names none. Comparing only against shot N-1 made a place the
|
| 146 |
+
# film never left read as newly arrived: platform / (unnamed) / platform
|
| 147 |
+
# warned on shot 3, live, for a chain that spends every hop on one
|
| 148 |
+
# platform.
|
| 149 |
+
def _b(*beats):
|
| 150 |
+
return [{"beat": b} for b in beats]
|
| 151 |
+
|
| 152 |
+
for label, sh, plan, want in (
|
| 153 |
+
("one place, a beat that does not name it",
|
| 154 |
+
_b("walks along the @platform", "moves past the yellow lines",
|
| 155 |
+
"slows her pace on the @platform"),
|
| 156 |
+
_pl({"tag": "platform"}, {"tag": "her", "subject": 1}), False),
|
| 157 |
+
("leaving and coming back is still a move",
|
| 158 |
+
_b("in the @kitchen", "down the @hallway", "back in the @kitchen"),
|
| 159 |
+
_pl({"tag": "kitchen"}, {"tag": "hallway"},
|
| 160 |
+
{"tag": "her", "subject": 1}), True),
|
| 161 |
+
("a new place with no arrival still warns",
|
| 162 |
+
_b("in the @kitchen", "across the @lamp_room floor"),
|
| 163 |
+
_pl({"tag": "kitchen"}, {"tag": "lamp_room"},
|
| 164 |
+
{"tag": "her", "subject": 1}), True),
|
| 165 |
+
("a beat that does the travelling does not",
|
| 166 |
+
_b("in the @kitchen", "she reaches the @lamp_room and stops"),
|
| 167 |
+
_pl({"tag": "kitchen"}, {"tag": "lamp_room"},
|
| 168 |
+
{"tag": "her", "subject": 1}), False)):
|
| 169 |
+
got = any("is a new place" in w for w in PL.check_place_handoff(sh, plan))
|
| 170 |
+
if got == want:
|
| 171 |
+
print(" ok %s" % label)
|
| 172 |
+
else:
|
| 173 |
+
print(" FAIL %s: warned=%s wanted=%s" % (label, got, want))
|
| 174 |
+
fails.append(label)
|
| 175 |
+
|
| 176 |
# The last shot of any pattern that ends a chain must not be left `ongoing`.
|
| 177 |
closers = [s for s in all_shots
|
| 178 |
if (s["directives"].get("tail") in ("settle", "hold"))]
|