experiment journal · 2026-07-09 · 실행 근거 기반
각 노드는 세 칸으로 읽는다: 이상 기대치(설계가 요구하는 것) ·
코드 위치(실제 구현 file:line) · 실측(오늘 런의 진짜 숫자 —
runs/stageB_v3/logs/*.ledger.jsonl와 런 final에서 그대로 가져옴).
이 페이지의 모든 수치는 실제 아티팩트에서 검증된 것만 적었다.
WAKE — 4블록 프롬프트 → 메커니즘 가설 → 행동
에이전트는 (A) 환경 (B) 액션 API (C) 플레이 방법 (D) 세계모델+스킬 사용법, 딱 네 블록만 안다.
매 턴 “무엇이 무엇과 관계 맺는가”로 2-3개 메커니즘 가설(HYPOTHESIS:)을 세우고
가장 판별력 있는 하나에만 행동한다. 절대좌표 목표 금지.
ttso/auto/thin_run.py:56 (PROMPT 상수, 4블록) ·
가설 규율은 블록 C(thin_run.py:90-99) ·
한 라운드 = python 블록 1개, 지속 샌드박스에서 exec.
on_s1: 79액션으로 3레벨, on_s0: 35액션으로 1레벨
(runs/stageB_v3/logs/B1_on_*.log final). 시뮬레이션 상한 SIM_CAP=3/라운드,
클릭 상한은 턴마다 피드백에 명시.
LEAK BOUNDARY — 프롬프트는 환경+API만 노출 (오늘 3개 표면 소거 완료)
에이전트-대면 텍스트 어디에도 이 게임의 메카닉/승리조건 어휘가 없어야 한다. 프롬프트 주석 원문: “It exposes the ARC environment and the action API but NEVER this game's mechanics/win-condition — the agent DISCOVERS what an action does.”
ttso/auto/thin_run.py:52-55 (PROMPT 경계 주석) ·
ttso/eval/g2_run.py:60 (_MINER_CTX: 마이너에게도 인터페이스+“(hidden) win condition”만) ·
sleep 프롬프트 ttso/prompts/miner.txt·refine.txt.
표면 3개를 순차 제거: ① scaffold PROMPT/PROMPT_ACI 삭제 + miner/refine에서 coupled·distant·neighbours·toggle-family 어휘 제거(83ab400, 19:05) → ② WAKE_MODES/BOARD DRIFT 문구 중립화(같은 커밋) → ③ store 시드 렌즈의 COUPLED/orthogonal-neighbours/distant 어휘(a921b9c, 19:25). 이후 전 표면 프로그램 스윕 CLEAN(커밋 메시지 원문).
OBSERVED full-diff — 클릭이 바꾼 모든 셀을 에코
클릭 셀만이 아니라 그 클릭이 실제로 바꾼 모든 셀(결합 이웃, 원거리 토글 포함)을 관측 라인으로 돌려준다 — 승리조건 읽기 없음, fork 없음. 결합/간접 동역학은 이 라인 없이는 학습 불가능했다.
ttso/auto/thin_run.py:188 (_diff_entry: 클릭셀 before→after 선두 + 나머지 변화셀을
맨해튼 거리순, DIFF_CAP=20) · 피드백 부착 thin_run.py:557
(“OBSERVED: …”, 라운드당 OBS_CAP=12 클릭).
sleep 리포트의 observed 트랜지션: B1_on_s0 sleep#1에서 14개, B1_on_s1 sleep#4에서 21개.
predict-verify 행 누계: B1_on_s0 16, B1_on_s1 22 (final의
2_eval_predict_verify_rows).
TRIGGER — surprise(예측 빗나감) 또는 stuck(레벨 무진행)
둘 중 하나면 sleep: (a) 최고-credence 메커닉의 부분점수 예측 정확도가 실제 전이에서 τ=0.8 미만(surprise — 세계가 모델과 다르다) → 즉시, (b) 레벨 무진행 3턴 연속(stuck) + 새 증거 8개 이상 축적(ripe) → 발화. 그리드 novelty가 아니라 레벨 진행만이 stuck의 기준.
ttso/core/control.py:69 (control; stuck_k=3은 :42) ·
control.py:119 (force_sleep_on_mismatch, tau=0.8) ·
평가 지점 ttso/eval/g2_run.py:282 (_check_transition; 임계 0.8은 :296) ·
런 파라미터 g2_run.py:215 (cooldown 4, min_evidence 8).
30라운드 B1: on_s0 3회, on_s1 5회. 진행 중 B3(60라운드 상한, 라운드 50 시점): s0 9회, s1 6회 (각 ledger의 고유 sleep_index 수).
MINE — 잔차(residual)를 겨냥한 후보 k=4 제안
마이너는 현재 룰셋이 커버하지 못한 잔차 셀(관측됐지만 예측 안 되는 변화)을 명시적으로 겨냥해 mechanic 후보를 쓴다. 스텝 크기 ∝ 잔차: 잔차가 크면 구조적으로 다른 룰, 작으면 국소 수정.
ttso/sleep/mine.py:320 (mine) · 잔차 프롬프트 ttso/sleep/sleep.py:796
(_residual_prompt) · 스텝 크기 sleep.py:842 (_step_size) ·
오케스트레이션 sleep.py:865 (sleep).
sleep당 proposed=4 (k=4). 잔차 하강의 실례: B3_on_s0 L0 잔차 306셀 → 0셀 (sleep#0의 residual_before 306 → sleep#1의 residual_before 0); B1_on_s0은 residual 1.0 → 0.403 (ledger/sleep 리포트).
GATE — advantage_on_union > 0 (fail-closed)
후보가 라이브 룰셋 union의 predict-accuracy를 올릴 때만(ΔIG > 0) 통과. 잔차를 덮되 기존을 후퇴시키지 않으면 >0, 허위 셀만 발명하면 <0. fork도 oracle도 ground-truth 손실도 없다.
ttso/sleep/judge.py:384 (advantage_on_union =
predict_accuracy(ruleset+[cand]) − predict_accuracy(ruleset)).
mechanic 후보 판정: rejected 43 / parked 13; diff-검증 불가한 strategy 레코드는 별도로 accepted 24 (4개 ledger 집계, B3는 라운드 50 시점).
PARK — mine ≠ commit: 라이브러리 바깥에 주차
mine 시점 buffer로 뽑힌 후보는 그 buffer에 과적합일 수 있다. 즉시 커밋하지 않고, 마이너가 본 트랜지션 키(mine_keys)를 스탬프해서 주차한다. 주차 스펙은 확정 전까지 세계모델에 보이지 않는다.
ttso/sleep/store.py:249 (park) · 주차 결정 지점
ttso/sleep/sleep.py:1014-1025.
B3_on_s0 sleep#0, fp a882f2ec6f: advantage 0.6216>0 →
“PARKED for post-park confirm (not yet committed)”. v3 전 런 parked 13.
CONFIRM — 생성기가 못 본(post-park unseen) 트랜지션으로 재채점
주차 이후 게임이 쌓은 트랜지션 중 mine_keys에 없는 것(strictly held-out)으로 advantage_on_union을 다시 잰다. >0이면 승격, ≤0이면 과적합으로 드롭 — 일반화한 룰만 라이브러리에 들어간다.
ttso/sleep/commit.py:49 (confirm) · CONFIRM-first 순서
ttso/sleep/sleep.py:904 · 승격/격리 store.py:271 (resolve).
B3_on_s0 sleep#1: adv 0.9086 > 0 on 4 post-park transition(s) the generator never saw → promote. v3 합산 confirmed 7 / dropped 3 (드롭 사유 원문: “overfit the mine-time buffer, does not generalize”).
BETA CREDENCE — 신념 = Beta 사후평균, 재적용은 idempotent
credence = α/(α+β). 로깅된 실제 전이 하나당 부분점수(F1)로 α+=hit, β+=1−hit — 반쯤 맞으면 반만 인정. 같은 트랜지션 키는 두 번 세지 않는다(replay가 사후분포를 더블카운트하지 않음).
ttso/sleep/store.py:105-111 (alpha/beta 필드, credence 프로퍼티) ·
갱신 store.py:289 (observe_transition; α+=credit은 :307).
Stage-A A2 게이트(결정적 하네스): α 1.0 → 2.33, 동일 트랜지션 replay 후에도 2.33 (idempotent). 라이브 예: M1이 브리핑에 쓴 B3 mechanic의 credence 0.798 (/tmp/m1_summary.json).
PACKAGE — 브리핑 렌더 → 매 라운드 피드백에 재주입
확정 스킬을 credence 순으로, 지금 보드에서 when이 성립하는 것만 골라 브리핑으로 렌더(cap 8000자). 판별 probe는 VoI 게이트(EIG×가치 > RHAE 한계비용)를 통과할 때만 노출; 못 넘으면 “합의된 것에 커밋하라”로 바뀐다. wake가 이 브리핑을 실제로 읽고 써야 루프가 닫힌다.
ttso/sleep/package.py:107 (render) · 라운드마다 재렌더
ttso/eval/g2_run.py:202 (_package; 라이브 보드로 when-검색) ·
thin_run이 피드백 메시지에 부착.
동일 보드·동일 프롬프트 쌍대 비교: 브리핑 arm 인용률 6/6 vs 무브리핑 0/6 vs 브리핑 전 라운드 0/12 — 재주입된 브리핑을 wake가 진짜로 사용한다 (/tmp/m1_summary.json; 상세는 experiments 페이지).
FORK-BAN — Game.fork는 raise하도록 몽키패치, 종료 시 assert
파이프라인 어느 경로도 진짜 엔진을 복제해 미리 돌려볼 수 없다. 스킬 검증은 전부 자기 세계모델 위의 predict-verify. 과거의 “WIN”이 fork-브루트포스 아티팩트였던 전력이 있으므로, 소프트 규약이 아니라 하드 펜스로 강제한다.
ttso/eval/g2_run.py:226-234 (_banned_fork: 호출 즉시 RuntimeError + 카운트) ·
g2_run.py:430 (assert fork_dep["n"] == 0) ·
결과 필드 fork_dependence.
완주한 모든 final에서 fork_dependence = 0: B1 on/off × seed 0/1 네 런 전부
(runs/stageB_v3/logs/B1_*.log 마지막 줄). 시도 자체가 0회 — raise가 아니라
카운터가 0.
경계 요약: 에이전트가 아는 것 = 4블록 프롬프트(환경+API) + 자기 관측 + 자기 브리핑. 에이전트가 못 하는 것 = 엔진 fork, 승리조건 읽기, 게임별 어휘가 실린 힌트 수신. 이 페이지의 각 실측 칸이 그 경계 안에서 나온 숫자다.