"""Reduce each scene to one generic sentence about the SITUATION, not the story. The 2026-09-10 probe found that prose embeddings cluster by story identity -- names, setting, narrator voice -- rather than by what kind of situation a scene is. This strips exactly those signals before embedding. python3 summarise.py --limit 40 # pilot: time it and read the output python3 summarise.py # everything, resuming from summaries.json Model from STP_CHAT_MODEL (default qwen2.5:3b-instruct): the requirement is a small local model, so the prompt is written for one. """ import argparse, json, os, pathlib, re, time import ollama ap = argparse.ArgumentParser() ap.add_argument('--limit', type=int, default=None) args = ap.parse_args() MODEL = os.environ.get('STP_CHAT_MODEL', 'qwen2.5:3b-instruct') # v1 gave examples of roles ("a clerk", "a landlady", "a rich man", "a city # park"). A 3B model copied them into scenes that contain none of those people, # which would make unrelated scenes cluster together and fake the very # recurrence this probe measures. v2 names no example role at all. SYSTEM = """Describe the social situation in a passage of fiction in ONE sentence. Rules: - Exactly one sentence, at most 25 words. - Never use anyone's name. Refer to each person only by the role the passage gives them: their job, their family tie, or their position. - Never name a place, business, street or city. - Say what is happening between the people: who wants what from whom, who holds power, what is at stake. - Do not describe the writing style, the narrator, or the mood. - Output only the sentence.""" # The v2 pilot also tried one retry with a reminder whenever a name slipped # through. It fired 35 times in 40, nearly doubled the run, and 27 summaries # still carried names -- so there is no retry. Names are removed afterwards by # strip_names.py, deterministically. # A full stop after these is not the end of a sentence ("Mr. Peters", "St. Bernard"). END = re.compile(r'(?