irregular6612 Claude Fable 5 commited on
Commit
fee03b4
·
2 Parent(s): 79da9f1ffcff52

Merge feat/y22-ship-promotion: y8 spawn-nudge 승격 반증 기록을 main에 안착

Browse files

315-combo 스윕에서 통과 조합 0 — awards는 spawn 위치에 취약해 재배치가 아니라 삭제된다.
promotion은 hold, 재설계(강제 중립 진입 corridor)가 선행 조건.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

docs/superpowers/plans/2026-07-18-y8-log-ship-redesign.md ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # y8 (log) 승격 재설계 Implementation Plan
2
+
3
+ > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans. Steps use checkbox (`- [ ]`) syntax.
4
+
5
+ **Goal:** y8(log)의 결정적 C-N award를 캘리브레이션 스팬(turn 1-2) 뒤로 밀어 faithful 6/6 @ PARK_CAL_TURNS를 만들고, `PARK_LOG_SHIPPABLE`을 재측정 파생시켜 정식 shipped로 승격한다.
6
+
7
+ **Architecture:** 실패는 순수 캘리브레이션 타이밍(신호가 폐기되는 warm-up 턴에만 존재; skip=0이면 6/6, skip=2면 0/6). 메커니즘(body-block C-N poser)은 정상이므로 **board 기하만** 재조형한다: 걷는 이 스폰을 뒤로 + 동행 건널목을 함께 재위상(S 대수 커플링). 핵심은 **경험적 탐색** — (spawn offset, companion phase, log off)의 조합을 스파이크로 쓸어 게이트를 동시에 만족하는 지점을 찾는다.
8
+
9
+ **Tech Stack:** 순수 JS(engine.js 모듈 `_parkLogBuild`), `node`로 측정. 빌드 없음.
10
+
11
+ ## Setup — 워크트리에서 실행 (필수)
12
+
13
+ 이 계획은 **격리된 git 워크트리**에서 실행한다(메인 워크스페이스·main 브랜치 미오염). Task 1 시작 전:
14
+
15
+ - REQUIRED SUB-SKILL: `superpowers:using-git-worktrees`로 워크트리 생성 (브랜치 예: `feat/y8-log-ship`).
16
+ - 모든 태스크·커밋은 그 워크트리 안에서. engine.js를 실제 수정하므로(y22의 배관과 달리 board 기하 변경) 격리가 특히 중요 — 측정 스파이크가 엔진을 반복 편집한다.
17
+ - scratchpad 측정 스크립트의 `<ABS_ROOT>`는 **워크트리 경로**로 치환(메인 체크아웃 아님).
18
+ - 완료 후 `superpowers:finishing-a-development-branch`로 통합 방식(merge/PR) 결정.
19
+
20
+ ## Global Constraints
21
+
22
+ - **파생, 절대 주장 금지:** `PARK_LOG_SHIPPABLE`은 재측정에서 파생(bomb/fire/trolley 선례). `PARK-SHIP-BAR-CALIBRATED`(engine.test.js:8083)가 slot.ship == 캘리브레이션 6/6을 강제.
23
+ - **calibration:** 게이트는 skip=`PARK_CAL_TURNS`에서 잰다. skip=0에서도 6/6 유지(신호 파괴 아님) 확인.
24
+ - **불변식 유지:** incongruence(parkCrossings에서 filtered, sweep≥0)와 surface-mimic(recovered 0)은 재조형 후에도 유지돼야 한다 — 셋을 동시에 만족.
25
+ - **무수정 영역:** y8의 mechanism/read stack(`_parkLogCtx`/facet gates/honesty)과 다른 모듈·슬롯은 건드리지 않는다. board 기하(`_parkLogBuild`의 spawn/companionSpawn/off/필요 시 board 크기)만.
26
+ - **커플링:** engine.js:11893-11901의 `S = 8 - rr + xl`, race는 S=도착시각. 스폰을 밀면 동행 위상도 함께.
27
+ - **느린 스위트:** 전체 스위트 ~28분 — 개발 중엔 측정 스크립트/개별 게이트만, 최종만 전체 완주(background).
28
+
29
+ ---
30
+
31
+ ## File Structure
32
+
33
+ - `engine.js` — `_parkLogBuild`(11819-11918) board 기하 재조형; `PARK_LOG_SHIPPABLE`(12210) 파생 전환; 필요 시 `_parkLogRecovers` 신설(bomb `_parkBombRecovers` 미러).
34
+ - `campaign.js` — y8 슬롯 리터럴 flip(측정 통과 후).
35
+ - `engine.test.js` — 파급 게이트(CAMP-SHIP-UNMOVED, PARK-SHIP-BAR-CALIBRATED) 갱신; y8 승격 스윕 게이트 신설; CROSS-SURFACE-MIMIC에 y8 검토.
36
+ - `<scratchpad>/y8-spike.js` — 경험적 탐색용(리포 미커밋).
37
+
38
+ ---
39
+
40
+ ## Task 1: 스파이크 — 6/6을 내는 (spawn, companion phase) 조합 탐색
41
+
42
+ **Files:** Create `<scratchpad>/y8-spike.js` (리포 미커밋). Read engine.js:11819-11918.
43
+
44
+ **Interfaces:** Produces — 검증된 파라미터 조합 `{ spawnDelta, companionRr, logOffDelta }`가 skip=PARK_CAL_TURNS에서 6/6 + incongruence + mimic 0을 만족. 없으면 폴백(Task 1b, y3 기하).
45
+
46
+ - [ ] **Step 1: 현 상태 재현** — 스파이크가 in-memory로 `_parkLogBuild`를 감싸 스폰/동행/off를 파라미터화하고, skip=0과 skip=PARK_CAL_TURNS 양쪽에서 faithful N/6, 그리고 첫 award 착지 턴(per persona)을 출력. 먼저 파라미터 0(현행)으로 돌려 `skip0=6/6, skip2=0/6, award@t1`을 재현(진단 재확인).
47
+
48
+ ```javascript
49
+ // <scratchpad>/y8-spike.js — monkeypatch _parkLogBuild's spawn/companion/off, measure both skips.
50
+ const E = require('<ABS_ROOT>/engine.js');
51
+ // (approach: require, then re-invoke E._parkLogBuild through a wrapper cell that shifts spawn.y,
52
+ // companionSpawn.y, and log.off; measure parkRecoverOrder at skip 0 and PARK_CAL_TURNS, and log the
53
+ // award-turn histogram per persona via the module's award hooks. Exact wrapper derived from reading
54
+ // 11819-11918. Print: for each candidate, skip0 fOK/6, skip2 fOK/6, earliest-award-turn, filtered, mimic.)
55
+ ```
56
+
57
+ - [ ] **Step 2: 탐색** — `spawnDelta ∈ {1,2,3}` (걷는 이를 chain-0에서 더 멀리), 각각에 대해 `companionRr`을 S 대수로 재계산(`S = 도착시각`), `logOffDelta`로 롤 위상 정렬. 각 조합에서 측정. **수용 기준**: skip=PARK_CAL_TURNS에서 6/6(전 페르소나), 첫 결정 award 착지 turn ≥3, incongruence filtered, mimic recovered 0. 24 base 시드 중 최소 6시드 서브샘플로 먼저, 후보 확정 시 24시드 확인.
58
+ - [ ] **Step 3: 기록** — 통과 조합을 스파이크 로그에 남긴다(시드범위·수치·단위). 통과 조합 없으면 → Task 1b(폴백).
59
+ - [ ] **Step 4: 커밋 없음** (스파이크는 scratchpad). 결과를 다음 태스크로 전달.
60
+
61
+ ### Task 1b (조건부): 폴백 — y3 기하 차용
62
+
63
+ - [ ] Task 1이 6/6 조합을 못 찾으면: y3 board 형태(earliest award turn 3, 144/144 캘리브레이션-무손실)를 참조해 `_parkLogBuild`의 스폰/레인 레이아웃을 y3 shape로 이식하는 조합을 스파이크. 동일 수용 기준.
64
+
65
+ ---
66
+
67
+ ## Task 2: `_parkLogBuild` 재조형 적용 + 플래그 파생
68
+
69
+ **Files:** Modify engine.js:11889(spawn), 11902(companionSpawn), 11909(off); 12210(PARK_LOG_SHIPPABLE); 필요 시 `_parkLogRecovers` 신설.
70
+
71
+ **Interfaces:** Consumes — Task 1의 검증 조합. Produces — `PARK_LOG_SHIPPABLE === true` (재측정 파생).
72
+
73
+ - [ ] **Step 1: 실패 테스트(파생 확인)** — engine.test.js에 `Y8-LOG-SHIP-GATE` 신설(Y20-BOMB-SHIP-GATE 미러): `assert.strictEqual(E.PARK_LOG_SHIPPABLE, true, ...)`. 지금은 false라 FAIL 확인.
74
+ - [ ] **Step 2: board 기하 적용** — Task 1 조합을 `_parkLogBuild`에 적용(spawn.y/companionSpawn.y/off). 11893-11901 주석의 S 대수를 새 값으로 갱신(대수가 여전히 성립하도록). 레인/hedge/chain/mechanism/read stack 무수정.
75
+ - [ ] **Step 3: 파생 전환** — `PARK_LOG_SHIPPABLE = _parkLogRecovers(_parkLogCell(PARK_LOG_SHIP_SEED))`로 교체(`_parkBombRecovers` 미러 — playCell을 페르소나별로 재생, skip=PARK_CAL_TURNS에서 6/6). `_parkLogRecovers`가 없으면 신설, export.
76
+ - [ ] **Step 4: 통과 확인** — `node -e "console.log(require('./engine.js').PARK_LOG_SHIPPABLE)"` → `true`. `Y8-LOG-SHIP-GATE` PASS.
77
+ - [ ] **Step 5: 커밋** — `feat(park): retime y8 log spawn/companion so C-N award lands past calibration`.
78
+
79
+ ---
80
+
81
+ ## Task 3: 24시드 스윕 게이트 (faithful + incongruence + mimic)
82
+
83
+ **Files:** engine.test.js 신규 `Y8-LOG-SHIP-SWEEP` (Y22-SHIP-SWEEP / CROSS-REPAIR-P1-SWEEP 미러).
84
+
85
+ - [ ] **Step 1: 스윕 테스트** — 24 base 시드에서 y8 play cell에 대해 skip=PARK_CAL_TURNS faithful 6/6, incongruence filtered(parkCrossings), surface-mimic recovered 0, 비공허(mimic moved 6/6, posed>0)를 독립 재도출로 단언. 통과 로그 출력.
86
+ - [ ] **Step 2: 통과 확인** — `node engine.test.js 2>&1 | grep -iE "Y8-LOG-SHIP-SWEEP|AssertionError"`.
87
+ - [ ] **Step 3: 커밋** — `test(park): Y8-LOG-SHIP-SWEEP — 24 seeds faithful 6/6 calibrated + incong + mimic clean`.
88
+
89
+ ---
90
+
91
+ ## Task 4: 슬롯 flip + 파급 게이트 갱신 (y22 승격과 동형)
92
+
93
+ **Files:** campaign.js(y8 슬롯), engine.test.js(CAMP-SHIP-UNMOVED, PARK-SHIP-BAR-CALIBRATED).
94
+
95
+ - [ ] **Step 1: red 확인** — 아직 slot ship=false라 파생과 불일치할 지점, 그리고 PARK-SHIP-BAR-CALIBRATED의 y8 관련 비공허 절이 어떻게 반응하는지 먼저 확인(red-first).
96
+ - [ ] **Step 2: 슬롯 flip** — campaign.js y8 `ship: false, open: true` → `ship: true`(open 제거). 헤더 주석 승격 반영.
97
+ - [ ] **Step 3: CAMP-SHIP-UNMOVED 갱신** — engine.test.js:8020 PIN 맵에서 `y8: E.PARK_LOG_SHIPPABLE` 제거(더는 preview 아님), 8024 루프 목록에서 y8 제거, `checked` 5→4; 8040 shipped.length +1; 8050 shippedFields에 y8 추가(순서 주의 — PARK_CROSSINGS 순).
98
+ - [ ] **Step 4: PARK-SHIP-BAR-CALIBRATED 비공허 재료 갱신** — 8079-8081은 "캘리브레이션이 적어도 한 모듈 verdict를 바꾼다"를 y8로 확인했다. y8이 이제 6/6이면 이 예시가 소멸 → 여전히 skip0≠skip2인 다른 미달 모듈로 비공허 예시 이전(측정으로 확인 후 지정). red를 먼저 보고 갱신.
99
+ - [ ] **Step 5: 통과 확인** — 관련 게이트 grep PASS.
100
+ - [ ] **Step 6: 커밋** — `feat(park): promote y8 to shipped (first shipped disjoint C-N poser)`.
101
+
102
+ ---
103
+
104
+ ## Task 5: CROSS-SURFACE-MIMIC에 y8 편입 (선택, 표면 방어 pin)
105
+
106
+ **Files:** engine.test.js CROSS-SURFACE-MIMIC.
107
+
108
+ - [ ] **Step 1:** y8이 shipped field 슬롯이 됐으니, 슬롯 목록에 'y8' 추가 + 분기(recovered===[], mimMoved===6) 검토. 단 y8 demo가 walk이라 y20식 분기가 맞는지 측정으로 확인 후 pin.
109
+ - [ ] **Step 2: 통과 확인 + 커밋** — `test(park): CROSS-SURFACE-MIMIC covers y8`.
110
+
111
+ ---
112
+
113
+ ## Task 6: 전체 스위트 + 육안 검증
114
+
115
+ - [ ] **Step 1:** `node engine.test.js` 전체 완주(~28분, background), 전 게이트 PASS.
116
+ - [ ] **Step 2:** 로컬 서버(`python3 -m http.server 8765`)에서 y8 타일 preview→정식 전환 + 리포트가 순서 판정 표시 육안 확인.
117
+ - [ ] **Step 3:** 플랜 체크박스 갱신 커밋.
118
+
119
+ ---
120
+
121
+ ## Self-Review 결과
122
+
123
+ - **Spec coverage:** §5.1 board 재조형→Task 1/2; §5.2 파생→Task 2; §5.3 게이트 4종→Task 2/3/5; §5.4 flip+파급→Task 4; §6 리스크(iterative loop, 폴백, 8079-8081)→Task 1b/Task 4 Step 4.
124
+ - **경험적 태스크 정직성:** Task 1은 값이 TBD가 아���라 **수용 기준이 명확한 탐색**(6/6 @ calibration + turn≥3 + incong + mimic 0). placeholder 아님.
125
+ - **Type consistency:** `_parkLogRecovers`/`PARK_LOG_SHIPPABLE`/`PARK_LOG_SHIP_SEED`(engine.js:12209 존재) 이름 일치. `_parkBombRecovers` 패턴 미러.
126
+ - **리스크:** 커플링 때문에 Task 1이 여러 조합을 시도해야 할 수 있음 — 폴백(Task 1b) 명시. 8079-8081 비공허 이전은 red-first로 안전.
docs/superpowers/specs/2026-07-18-y8-log-ship-FINDING.md ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # y8 (log) 승격 재설계 — 실측 결과: 스폰-넛지 전제 반증, 승격 보류
2
+
3
+ - 날짜: 2026-07-18
4
+ - 대상: `y8` (mechanic: log), engine.js `_parkLogBuild` / `_parkLogRecovers` / `PARK_LOG_SHIPPABLE`
5
+ - 선행: 설계 `2026-07-18-y8-log-ship-redesign-design.md`, 계획 `2026-07-18-y8-log-ship-redesign.md`
6
+ - 결정: **y8 승격 보류, honest preview 유지** (`PARK_LOG_SHIPPABLE = false` 그대로). 사용자 확인.
7
+ - 상태: engine.js·campaign.js·게이트 **무변경** (스파이크 훅은 측정 후 되돌림). 이 문서만 기록.
8
+
9
+ ## 1. 한 줄
10
+
11
+ 설계(§5.1)와 engine.js 헤더(12192-12200)가 처방한 "스폰을 레인에서 뒤로 밀어 결정적 award를
12
+ calibration span 밖으로 옮긴다"는 수리 모델은 **실측으로 반증됐다**. award는 스폰 위치에 취약하며,
13
+ 스폰을 밀면 그 award가 늦게 재배치되는 게 아니라 **그냥 사라진다**. 3-파라미터 넛지로는 불가능하다.
14
+
15
+ ## 2. 무엇을 측정했나
16
+
17
+ 격리 워크트리(`worktree-feat+y8-log-ship`, base f2fe5b2)에서 `_parkLogBuild`에 임시 전역 훅
18
+ (`globalThis.__PARK_LOG_SPIKE__ = {sdx, sdy, rrOff, offOff}`; 전역 부재 시 no-op — baseline
19
+ byte-동일 확인)을 달아 다음을 파라미터화하고 쓸었다:
20
+
21
+ - `sdx/sdy` — 걷는 이 spawn 오프셋(unmirrored `M(wx + sdx)`, `2 + sdy`)
22
+ - `rrOff` — companion spawn 행(`xl - 1 + rrOff`), §4 S 대수의 위상
23
+ - `offOff` — 로그 롤 위상 `off`
24
+
25
+ 측정 지표(per seed): faithful `parkRecoverOrder` @skip=0 및 @skip=`PARK_CAL_TURNS`(=2), 첫
26
+ award 착지 턴, `reason==='complete'`.
27
+
28
+ ## 3. 결과 (수치·단위·시드범위 명시)
29
+
30
+ - **와이드 스윕**: `sdx ∈ {-3..1}` × `sdy ∈ {0..2}` × `rrOff ∈ {-3..3}` × `offOff ∈ {0..2}`
31
+ = **315 조합**, 6-시드 서브샘플(seeds 1,2,3,4,7,13). **통과 조합 0개.** 근접-통과(pass2 평균 ≥5/6)
32
+ 조차 0. baseline(무훅) = pass 0, skip0 6/6, skip2 0/6, earliestAward turn 1 (진단 재현).
33
+ - **초점 진단** (seed 1) — 왜 불가능한지 설명. skip=2 잔여 tally(각 페르소나 award를 span 제거 후 집계):
34
+
35
+ | persona (att order) | 스폰 이동 후 결정된 쌍 | 미결정(0-0) 쌍 |
36
+ |---|---|---|
37
+ | goal,* | GN | **GC, CN** |
38
+ | safety,* | GC, CN | **GN** |
39
+ | care,* | GN, CN (약) | **GC** |
40
+
41
+ - `sdx=-1`(visual spawn (8,2)): 걷는 이 opener는 turn 6-8로 밀렸다(성공). 그러나 굶은 쌍의
42
+ award는 늦게 나타나지 **않고** 미결정(0-0)으로 남는다. 즉 이른 award를 **삭제**할 뿐 늦은
43
+ 대체 award를 **생성하지 못한다**.
44
+ - 페르소나마다 **서로 다른 쌍**이 굶는다. `skip0=6/6`은 오직 turn-1/2 award를 포함할 때만 성립.
45
+
46
+ ## 4. 반증된 전제
47
+
48
+ - 설계 §5.1-1 및 engine.js 헤더 12192-12200: *"MOVE THE SPAWN AWAY FROM THE LANE so the decisive
49
+ move lands AFTER the calibration span ... his first real choice about the log happens at turn 3+."*
50
+ - 이 모델은 "결정적 move(그리고 그 award)는 하나이고, 접근 수를 앞에 끼우면 그 move가 통째로 turn
51
+ 3+로 밀린다"를 가정한다. **실측은 반대다**: award는 특정 board 상태에서 특정 move가
52
+ discriminate할 때만 발생하며, 스폰을 밀면 걷는 이의 경로·도착 시각·companion/log 상대위상이 모두
53
+ 바뀌어 원래의 discriminating 상태가 **재현되지 않는다**. 굶은 쌍은 다시 posed되지 않는다.
54
+
55
+ ## 5. 진짜 수리에 필요한 것 (승격을 재개한다면)
56
+
57
+ 3-파라미터 넛지가 아니라, **굶은 쌍을 span 뒤에서 다시 pose**하도록 board를 재설계해야 한다:
58
+
59
+ 1. **강제 중립 진입 corridor** (길이 k): 여섯 페르소나가 동일하게 걷는 1-폭 통로 — 그동안 어떤 쌍도
60
+ pose/starve 되지 않아야 한다. board 레이아웃(벽/워크웨이) 변경 필요.
61
+ 2. **companion·log 동시 지연** (정확히 k): corridor 종료 시점의 board 상대상태가 원래 turn 1의
62
+ 상태와 같도록 companion spawn 행과 log `off`를 함께 밀어, 원래의 C-N body-block 결정이 turn 1+k
63
+ 에서 그대로 재현되게 한다.
64
+ 3. **리스크**: y8의 전략적 가치는 공원 유일의 disjoint C-N(body-block) poser라는 점이다(§3 설계).
65
+ naive한 "y3 기하 차용"(계획 Task 1b)은 y3가 C-N을 disjoint하게 pose하지 않으므로 그 body-block을
66
+ **버릴** 위험이 있다. 재설계는 body-block을 **보존**하면서 corridor+지연을 얹어야 하며, 수렴이
67
+ 보장되지 않는다.
68
+
69
+ ## 6. 조치
70
+
71
+ - 승격 보류. `PARK_LOG_SHIPPABLE = false`, y8 슬롯 `ship: false, open: true` (marked preview) 유지.
72
+ - engine.js 헤더(12192-12200)의 "MOVE THE SPAWN AWAY" 처방에 이 문서를 가리키는 정정 주석 1건 추가
73
+ (동작 무변경 — 다음 세션이 죽은 접근을 재유도하지 않도록). 그 외 무변경.
74
+ - 스파이크 스크립트(scratchpad `y8-probe.js`/`y8-scan.js`/`y8-spike.js`/`y8-diag.js`)는 리포 미커밋.
docs/superpowers/specs/2026-07-18-y8-log-ship-redesign-design.md ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # y8 (log) 승격 재설계 설계 — preview → shipped (캘리브레이션 타이밍 수리)
2
+
3
+ - 날짜: 2026-07-18
4
+ - 대상: `y8` (mechanic: log), campaign.js `PARK_CROSSINGS` + engine.js log 모듈
5
+ - 입력: 진단 리포트 `2026-07-18-preview-diag-y8.md`, 합성 `2026-07-18-preview-promotion-feasibility.md`
6
+ - 상태: 설계 승인됨, 구현 계획 대기
7
+
8
+ ## 1. 목표 한 줄
9
+
10
+ y8을 정직한 preview에서 정식 shipped로 승격한다. 실패는 순수 **캘리브레이션 타이밍**이다 — 순서 신호(body-block의 disjoint C-N poser)가 매 판정 에피소드가 버리는 첫 `PARK_CAL_TURNS`(=2) 턴 안에서만 발현된다. board 기하만 재조형해 결정적 수를 스팬 뒤(turn ≥3)로 밀고, `ship`은 재측정에서 파생시킨다.
11
+
12
+ ## 2. 배경 — 무엇이 고장났나 (진단 근거)
13
+
14
+ - 측정: 12시드×6페르소나, faithful **0/72 @ skip=PARK_CAL_TURNS**, 그러나 **6/6 @ skip=0**(전 시드). incongruence filtered 12/12, mimic recovered 0. 실패는 오로지 캘리브레이션 폭만큼(진단 리포트).
15
+ - 근본 원인(engine.js:12169-12200 헤더가 자기 문서화): 걷는 이가 자기 chain-0/body-block 셀 바로 옆에 스폰(`spawn = { x: M(wx), y: 2 }`, engine.js:11889)해 "커밋이 곧 첫 수"다. award 히스토그램 {t1:12, ...} — 여섯 페르소나 **각자 최소 한 쌍의 유일한 award가 스팬 안**에 들어가고, 미결정 쌍이 하나라도 있으면 `parkRecoverOrder`가 null을 반환한다.
16
+ - **메커니즘·read stack은 정상**: 헤더가 "this is a BOARD task, and the read stack is not the problem"이라 못 박음. body-block은 144/144로 C-N을 disjoint하게 pose한다. 딱 한 수 너무 일찍 pose할 뿐.
17
+
18
+ ## 3. 전략적 가치
19
+
20
+ y8의 body-block은 **공원에서 유일하게 C-N(care–biggest) 쌍을 disjoint하게 pose하는 셀**이다(x2 은퇴·y12 preview·y14/y21이 못 하는 그것 — 합성 §교차관찰). 승격 = **공원 최초의 shipped disjoint C-N poser** 확보로, 아레나 전역 C-N gap을 실측으로 닫는 첫 사례.
21
+
22
+ ## 4. 핵심 커플링 (설계 제약)
23
+
24
+ 스폰은 단독이 아니라 **동행의 건널목 타이밍과 커플링**돼 있다. engine.js:11893-11901의 대수:
25
+
26
+ ```
27
+ S = (9 - rr) + (xl - 2) + 1 = 8 - rr + xl // 동행이 gap까지 가는 걸음 (rr = companionSpawn 행)
28
+ "the race" 요구: S = 9 → rr = xl - 1 // body-block 창이 걷는 이 도착과 정렬
29
+ ```
30
+
31
+ 즉 body-block(유일 C-N poser)은 걷는 이의 도착 시각에 정확히 맞춰 발동한다. **스폰을 뒤로 밀면 동행 위상도 함께 밀어야** poser가 안 깨지고 창이 turn ≥3으로 이동한다.
32
+
33
+ ## 5. 설계 — 스폰 뒤로 (최소 변경)
34
+
35
+ ### 5.1 board 기하 (engine.js `_parkLogBuild`, 11819-11918)
36
+
37
+ 1. **걷는 이에게 강제 접근 수 부여** — `spawn`(11889)을 자기 chain-0/body-block 셀에서 `k(≥2)` 칸 더 떨어뜨려 통나무에 대한 첫 실질 선택이 turn ≥3에 착지하게 한다. 접근 경로는 어느 쌍도 pose/starve 하지 않는 순수 이동이어야 한다(중립 corridor).
38
+ 2. **동행 건널목 재위상** — `companionSpawn`(11902)의 행과 로그 롤 위상 `off`(11909, `_parkSchedule`)를 걷는 이의 새 도착 시각 `T`에 맞춰, §4의 S 대수를 `S = T`로 다시 풀어 이동한다. body-block 창이 스팬 뒤에 열리도록.
39
+ 3. 레인/hedge/chain/token/mechanism/read stack은 **그대로**. `PARK_LOG_N`·`_PARK_LOG_YH`가 접근 수를 수용하는지 확인(부족하면 board를 최소 확장, 단 y3처럼).
40
+
41
+ ### 5.2 플래그 파생 (engine.js)
42
+
43
+ - `PARK_LOG_SHIPPABLE`(12210)을 하드핀 `false`에서 **재측정 파생**으로: `_parkLogRecovers(_parkLogCell(PARK_LOG_SHIP_SEED))` 형태(bomb/fire/trolley 모듈 선례). 재측정이 skip=PARK_CAL_TURNS에서 6/6이면 true.
44
+ - slot 리터럴 `ship`은 손으로 주장하지 않는다 — `PARK-SHIP-BAR-CALIBRATED`(engine.test.js:8083)가 이미 모든 모듈 핀을 캘리브레이션 6/6과 대조한다. y8이 통과하면 그 게이트가 자동으로 방어.
45
+
46
+ ### 5.3 게이트 (4종, 측정에서 파생)
47
+
48
+ - **faithful 6/6 @ skip=PARK_CAL_TURNS** (핵심; 현재 0/6 → 목표 6/6). skip=0에서도 6/6 유지 확인.
49
+ - **incongruence 유지** — parkCrossings에서 y8이 filtered, sweep≥0 (현재 12/12).
50
+ - **mimic 0 유지** — surface-mimic recovered 0 (현재 0). `CROSS-SURFACE-MIMIC`에 y8 추가 검토.
51
+ - **비공허** — mimic moved 6/6, posed >0.
52
+
53
+ ### 5.4 slot flip + 파급 게이트 (y22 승격과 동형)
54
+
55
+ y8이 게이트를 통과하면: campaign.js y8 슬롯 `ship: false, open: true` → `ship: true`(open 제거); `CAMP-SHIP-UNMOVED`(engine.test.js:8020의 PIN 맵에서 y8 제거, shipped.length +1, shippedFields에 y8 추가); `PARK-SHIP-BAR-CALIBRATED` 비공허 절(y8이 "캘리브레이션이 verdict를 바꾸는" 예시였음 — 8079-8081 — 이 대체 예시 확보 필요).
56
+
57
+ ## 6. 리스크와 폴백
58
+
59
+ - **iterative measurement loop 필요**: 스폰 행·동행 위상·로그 off의 ��합을 스파이크로 쓸어 "award가 turn ≥3 착지 + 6/6 유지 + incongruence/mimic 유지"를 동시에 만족하는 지점을 찾는다. body-block 타이밍 커플링 때문에 한 번에 안 맞을 수 있음 — **구현의 첫 단계가 이 스파이크**.
60
+ - **폴백**: 스폰-뒤로가 6/6에 못 이르면 y3 기하 차용(대안 B, 진단 리포트) — y3는 earliest award turn 3, 144/144 캘리브레이션-무손실.
61
+ - **8079-8081 비공허 재료**: `PARK-SHIP-BAR-CALIBRATED`는 "적어도 한 모듈의 verdict가 캘리브레이션으로 바뀐다"를 y8로 확인한다. y8이 이제 6/6이면 이 예시가 사라짐 — 그 게이트의 비공허 절이 다른 미달 모듈(예: y10/y12는 여전히 skip0 vs skip2가 다를 수 있음)을 가리키도록 갱신 필요. 구현 시 이 게이트가 red가 되는 걸 먼저 확인.
62
+ - **clone/seam**: 다른 모듈·슬롯 무영향. read stack/mechanism 무수정.
63
+
64
+ ## 7. 완료 정의 (DoD)
65
+
66
+ - [ ] `_parkLogBuild` 스폰+동행 위상 재조형, 결정적 award가 turn ≥3 착지(검증).
67
+ - [ ] `PARK_LOG_SHIPPABLE`을 재측정 파생으로 전환, = true.
68
+ - [ ] faithful 6/6 @ PARK_CAL_TURNS, 24 base 시드 스윕 green.
69
+ - [ ] incongruence filtered 유지, mimic 0 유지(스윕).
70
+ - [ ] y8 슬롯 `ship: true`, 파급 게이트(CAMP-SHIP-UNMOVED / PARK-SHIP-BAR-CALIBRATED) 갱신.
71
+ - [ ] 전체 스위트 green.
72
+ - [ ] 로컬 서버에서 y8 타일 preview→정식 전환 육안 확인.
engine.js CHANGED
@@ -12199,6 +12199,17 @@ function parkLogWhys() { return { ..._PARK_LOG_WHYS }; }
12199
  // wrong — the body-block still poses C-N disjointly, which is what y8 was built to do, and it
12200
  // still does it 144/144. It just poses it one move too early to be allowed to count.
12201
  //
 
 
 
 
 
 
 
 
 
 
 
12202
  // THE C-N CONTRIBUTION STANDS, and it is worth keeping straight, because it is the thing y8 was
12203
  // built for and it is NOT what it lost. A C-vs-N award needs a state where the C- and N-compliant
12204
  // sets are DISJOINT, and the park had none (the x2 crossing was retired for exactly this; y12
 
12199
  // wrong — the body-block still poses C-N disjointly, which is what y8 was built to do, and it
12200
  // still does it 144/144. It just poses it one move too early to be allowed to count.
12201
  //
12202
+ // ^^^ THAT SPAWN-NUDGE PROGNOSIS WAS MEASURED AND DISPROVEN (2026-07-18; see
12203
+ // docs/superpowers/specs/2026-07-18-y8-log-ship-FINDING.md). A 315-combo sweep of (spawn Δ,
12204
+ // companion row, log off) yielded ZERO passing combos. Moving the spawn back DOES push the opener
12205
+ // past the span, but the starved pair's award does NOT re-land later — it is deleted, not
12206
+ // relocated, and each persona starves a DIFFERENT pair (goal loses GC+CN, safety loses GN, care
12207
+ // loses GC). awards are fragile to spawn position: shifting the walker changes his route, arrival
12208
+ // time, and the companion/log relative phase, so the original discriminating state is never
12209
+ // reproduced. A real fix must RE-POSE the starved pairs LATE — a forced neutral entry corridor of
12210
+ // length k WITH the companion and log delayed by the same k (board LAYOUT change), while PRESERVING
12211
+ // the body-block C-N poser. That is a redesign, not a spawn nudge; promotion is on hold.
12212
+ //
12213
  // THE C-N CONTRIBUTION STANDS, and it is worth keeping straight, because it is the thing y8 was
12214
  // built for and it is NOT what it lost. A C-vs-N award needs a state where the C- and N-compliant
12215
  // sets are DISJOINT, and the park had none (the x2 crossing was retired for exactly this; y12