Add story-to-pack research and a structured situation review
Research toward building a content pack from a story corpus, kept on its own branch and independent of the game. Records the selection experiments against blind labels, and settles selection as gate G2 followed by a human review: review.py writes REVIEW.md and a review.json form, apply_review.py checks the filled form and writes situations.json for the next stage. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01C6UDQ9o6L6Ey173U7XVou6
This commit is contained in:
co-authored by
Claude Opus 5
parent
d84ae495f4
commit
fa3769d0fe
@@ -0,0 +1,38 @@
|
||||
"""Near-duplicate situations among accepted clusters (SELECTION.md protocol step 6).
|
||||
|
||||
python3 merge_dupes.py dev # list every accepted pair's centroid cosine, with label names
|
||||
python3 merge_dupes.py test 0.93 # merge pairs at or above a threshold chosen on dev
|
||||
|
||||
Centroids are the mean unit summary vector of each cluster. On dev the threshold is chosen by
|
||||
reading: the lowest cosine that still separates pairs whose names say "same situation" from pairs
|
||||
that do not. On test it is applied as given, and each merge is reported with both names so it can
|
||||
be checked.
|
||||
"""
|
||||
import json, pathlib, sys
|
||||
|
||||
set_name = sys.argv[1]
|
||||
threshold = float(sys.argv[2]) if len(sys.argv) > 2 else None
|
||||
|
||||
sys.argv = ['measure.py', 'summary_embeddings.json']
|
||||
exec(pathlib.Path('measure.py').read_text(encoding='utf-8').split("print(f'{path.name}")[0])
|
||||
sys.argv = ['select_rule.py']
|
||||
exec(pathlib.Path('select_rule.py').read_text(encoding='utf-8').split("mode = sys.argv")[0])
|
||||
|
||||
candidates = json.loads(pathlib.Path(f'candidates-{set_name}.json').read_text())
|
||||
frozen = json.loads(pathlib.Path('rule-frozen.json').read_text())
|
||||
terms = [tuple(t) for t in frozen['terms']]
|
||||
rows = {r['id']: r for r in load(set_name)}
|
||||
accepted = [cid for cid, r in rows.items() if all(passes(r, t) for t in terms)]
|
||||
|
||||
cent = {cid: norm([sum(V[i][d] for i in candidates[cid]) / len(candidates[cid]) for d in range(dim)])
|
||||
for cid in accepted}
|
||||
pairs = sorted(((dot(cent[a], cent[b]), a, b) for x, a in enumerate(accepted) for b in accepted[x + 1:]),
|
||||
reverse=True)
|
||||
|
||||
print(f'{set_name}: {len(accepted)} accepted clusters, {len(pairs)} pairs\n')
|
||||
for cos, a, b in pairs[:25]:
|
||||
mark = ' MERGE' if threshold is not None and cos >= threshold else ''
|
||||
print(f"{cos:.4f} {a}({rows[a]['label']}) {rows[a]['name'] or '-'}\n {b}({rows[b]['label']}) {rows[b]['name'] or '-'}{mark}")
|
||||
if threshold is not None:
|
||||
merged = [(a, b) for cos, a, b in pairs if cos >= threshold]
|
||||
print(f'\nthreshold {threshold}: {len(merged)} merges')
|
||||
Reference in New Issue
Block a user