#!/usr/bin/env python3 """exp15 — BLIND reading packets for the owner (§D3 human endpoint: metrics NOMINATE, blind read RATIFIES, planка = <=2 claims/chapter). Presents the SAME opening source passage translated 3 ways — flat-A0-30 (blind-greedy baseline), oracle-30 (seam-aligned), q3a-src (source-carryover arm) — under SHUFFLED neutral labels (V1/V2/V3), with a separate key. The owner reads without knowing which is which and counts claims. Deterministic shuffle (fixed seed). Outputs to exp15/monitor/ (blind packet + key, key kept separate). Run: python blind_packets.py """ from __future__ import annotations import json import random import sqlite3 import sys from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parent)) from chunker import greedy_chunks SD = Path("/home/ubuntu/books/gu-zhenren/exp15") AH = SD / "anchors" MON = SD / "monitor" N_CHUNKS = 6 # ~first 3-4 节 of the opening (readable passage) def db_finals(db): con = sqlite3.connect(db) out = {} for ck, txt in con.execute("SELECT chunk_idx, response_text FROM checkpoints WHERE stage='edit' ORDER BY chunk_idx, attempt"): out[ck] = txt con.close() return out def main(): MON.mkdir(parents=True, exist_ok=True) flat_src = greedy_chunks((SD / "S2prime_big_flat.txt").read_text(encoding="utf-8")) oracle_src = greedy_chunks((SD / "S2prime_big_blanklines.txt").read_text(encoding="utf-8")) flat_fin = db_finals(AH / "flat_a0_30.db") oracle_fin = db_finals(AH / "oracle_30.db") # source span covered by the first N flat chunks (used for oracle coverage matching AND now shown as # the fidelity reference — the reader compares each version against this original for omissions/errors) src_span = "".join(flat_src[:N_CHUNKS]) src_display = "\n\n".join(flat_src[:N_CHUNKS]) # paragraph-joined for readability # flat + q3a-src share flat chunking; oracle differs -> take oracle chunks until it covers ~the same source len flat_text = "\n\n".join(flat_fin[i] for i in range(N_CHUNKS) if i in flat_fin) arm_dir = SD / "arms" / "q3a-src" src_arm = "\n\n".join((arm_dir / f"{i:02d}.final.txt").read_text(encoding="utf-8") for i in range(N_CHUNKS) if (arm_dir / f"{i:02d}.final.txt").exists()) # oracle: chunks whose cumulative source length ~covers src_span cov, oi, otexts = 0, 0, [] target = len(src_span) while oi < len(oracle_src) and cov < target: if oi in oracle_fin: otexts.append(oracle_fin[oi]) cov += len(oracle_src[oi]); oi += 1 oracle_text = "\n\n".join(otexts) arms = {"flat-A0-30 (blind greedy baseline)": flat_text, "oracle-30 (seam-aligned)": oracle_text, "q3a-src (source-carryover)": src_arm} labels = ["V1", "V2", "V3"] keys = list(arms.keys()) rnd = random.Random("exp15-blind-2026-07-18") rnd.shuffle(keys) mapping = dict(zip(labels, keys)) # V1->arm, ... # blind packet (no arm names) — original source at top for FIDELITY comparison, then the 3 versions pkt = [f"# exp15 — СЛЕПОЙ ПАКЕТ для чтения (открывающий фрагмент 蛊真人, ~{N_CHUNKS} чанков)", "", "Три версии перевода ОДНОГО фрагмента под нейтральными метками (V1/V2/V3, перемешаны; ключ отдельно).", "Оцени: (а) художественность/связность и (б) ВЕРНОСТЬ — сверяя каждую версию с китайским ОРИГИНАЛОМ", "ниже (ничего не потеряно; смысл/род/референт/порядок событий переданы). Планка: ≤2 претензии на главу.", "Примечание: V1/V2/V3 переводились с разной нарезкой на чанки, поэтому у одной из версий хвост", "фрагмента может слегка отличаться по границе — это часть эксперимента, не ошибка перевода.", "", "---", "", "## ОРИГИНАЛ — китайский исходник (эталон для сверки верности)", "", src_display, "", "---", ""] for lab in labels: pkt += [f"## {lab}", "", arms[mapping[lab]], "", "---", ""] (MON / "blind_read_packet.md").write_text("\n".join(pkt), encoding="utf-8") (MON / "blind_read_KEY.json").write_text(json.dumps( {"_warning": "KEY — не показывать читающему до вынесения вердикта", "mapping_label_to_arm": mapping, "n_chunks": N_CHUNKS, "source_span_runes": len(src_span)}, ensure_ascii=False, indent=2), encoding="utf-8") print(f"blind packet -> {MON}/blind_read_packet.md (key -> blind_read_KEY.json)") print(f" labels: {mapping}") print(f" lengths: flat {len(flat_text)}c, oracle {len(oracle_text)}c, q3a-src {len(src_arm)}c") if __name__ == "__main__": main()