• LINKS 1.0.7 — backup이 VX/VX Ace build를 포함한 배포에서 실패하던 결함 수정

    LINKS 1.0.7

    이 hotfix 릴리스는 이전 릴리스 1.0.6(735ac60b1c) 위에 운영 backup 결함 수정만 얹었습니다. 최종 소스는 3f6c504352, 루트 패키지는 1.0.7, ARCA pin은 exact 0.1.18로 그대로입니다. 1.0.6 이하의 sh backup.sh는 VX/VX Ace(rgss-wasm) ready build가 하나라도 있으면 [2/8] pin 단계에서 artifact core manifest contains unknown or missing fields로 실패했습니다(web-static manifest parser를 모든 build에 적용한 결함). 이제 backup이 build adapter별 manifest 계약으로 pin·snapshot·복구 검증을 하고 RGSS build(Player tree·game/RTP CAS 객체·portable manifest)가 backup과 복구에 포함됩니다. schema는 바뀌지 않았습니다. DB 초기화와 migration이 필요 없습니다. backup 형식도 그대로(plan v2·artifact v2)이며 기존 web-static backup은 그대로 복구됩니다.

    업그레이드 주의: 1.0.6 → 1.0.7은 sh update.sh만 실행하고, 설치 뒤 반드시 sh backup.sh로 backup을 한 번 만들어 둡니다

    1. 대상·범위: 1.0.6 이하에서 sh backup.sh가 VX/VX Ace ready build가 하나라도 있으면 [2/8] Pausing runtime publication and pinning the runtime scope에서 artifact core manifest contains unknown or missing fields로 실패하던 결함을 고쳤습니다. pin·snapshot·복구 검증이 build의 adapter가 고른 계약(web-static은 artifact core manifest, rgss-wasm은 RGSS23 generation manifest v3)을 쓰고 알 수 없는 adapter·manifest는 실패합니다. rgss-wasm generation은 sealed.json이 나열한 Player tree 전체(runtime/ 하위 포함)와 game·RTP CAS 객체(package·portable manifest·artifact.json)가 snapshot·복구에 들어갑니다. backup 형식은 바뀌지 않았고(plan links-runtime-backup-plan-v2·artifact links-runtime-artifact-backup-v2) 기존 web-static backup과 호환됩니다. schema·migration·GC·contracts·배포 파일 7개는 1.0.6과 같습니다.
    2. 갱신 방법: 배포 디렉터리에서 sh update.sh만 실행합니다. schema는 바뀌지 않았고(infra/schema·infra/migrations·.env.example이 1.0.6과 같고 migration은 0개) reset.sh를 실행하지 않습니다. 바뀌는 것은 image뿐입니다. 1.0.7 설치 뒤 반드시 coordinator를 멈추고 sh backup.sh로 backup을 한 번 만들어 둡니다(운영 가이드 '운영 backup 명령'). 다음 1.0.8은 schema migration(게스트 공유 링크)을 포함하므로 그 전의 pre-update backup이 필수이며, 1.0.6 schema DB의 backup은 그 schema 버전을 사슬에 포함한 image(1.0.7)로만 만들 수 있습니다. report.json이 없는 backup 디렉터리는 실패한 backup입니다.
    3. NAS 조건 gate: 릴리스 전에 격리 docker:24.0.2-dind에서 이 갱신을 검증했습니다. host Compose는 공식 Docker Compose v2.20.1 binary(release의 게시 checksum으로 확인), stager는 1026:100, 원본 library 최상위는 0:0 000에 1026만 여는 ACL이었습니다. 1.0.6 배포에 합성 VX Ace(rgss-wasm, ARCA 0.1.18) ready build와 MZ(web-static) ready build, 로그인 사용자의 세이브를 만든 뒤 설치된 1.0.6 update.sh로 1.0.7 갱신(schema current, migration 0, 12 service network 일치, 모두 Watchtower 제외, readiness PASS), coordinator 정지 뒤 sh backup.sh 8단계 완료와 fresh restore drill(RGSS build·game/RTP CAS·save 포함), coordinator 재기동, 재-update(변경 없음)까지 모두 기대대로 끝났습니다(아래 검증). Synology build(v2.20.1-6047-g6817716)와 실제 NAS의 backup·복구는 확인 전입니다.

    NAS 절차(1.0.6에서):

    cd /volume1/docker/links
    sh update.sh
    docker compose --env-file .env.production --profile runtime stop runtime-package-coordinator
    sh backup.sh
    docker compose --env-file .env.production --profile runtime up -d --no-build runtime-package-coordinator
    

    update.sh가 성공하면 단계 표시 6줄 뒤에 Updated to 1.0.7 (catalog 91e3adb9fc5a), runtime.package ready.가 출력됩니다. backup.sh는 [1/8]부터 [8/8]까지 출력한 뒤 Backup <id> PASS. Copy the whole directory off-host and keep it at least 30 days.로 끝나고, 실패하면 원인 한 줄을 출력하고 nonzero로 끝납니다. backup 디렉터리 전체를 off-host로 복사해 둡니다.

    원본 game library는 읽기 전용으로 유지합니다. 이번 게시 작업에서 개발·운영 DB 초기화나 NAS 배포는 실행하지 않았습니다.

    backup 수정 내용

    • packages/db/src/runtime-backup-manifest.ts(신규): build adapter별 manifest dispatch(web-static parseArtifactCoreManifest, rgss-wasm parseRgss23PlayerGenerationManifest, 둘 다 기존 export), RGSS game/RTP artifact.json 기대값(manifest에서 재구성, DB descriptor_sha256과 manifest descriptorSha256 둘 다와 대조).
    • runtime-backup.ts: scope query가 runtime_builds.adapter를 읽고 행마다 그 adapter의 parser로 manifest hash가 build hash와 같은지, 연결된 CAS 객체가 manifest가 지정한 객체인지 검증합니다. adapter와 manifest 계약 불일치, 알 수 없는 adapter, manifest가 지정하지 않은 RGSS 객체, RTP 누락은 거부합니다.
    • runtime-backup-snapshot.ts: RGSS generation은 sealed.json(links-rgss23-player-generation-v2)을 build 게시 때와 같은 parseRgss23BuildResult로 manifest에 묶고 Player tree 전체를 기대 목록에 넣습니다. 봉인 디렉터리 검사를 generation·객체 root 아래 모든 디렉터리로 넓혀 나열되지 않은 항목을 거부하고, 복구가 하위 디렉터리까지 0555로 봉인합니다. web-static 경로의 기대 파일·바이트는 이전과 같습니다.
    • 바꾸지 않은 것: plan·artifact snapshot 형식 번호, ops/backup-registry.sh·ops/backup-verify.compose.yaml, schema·migration, GC(runtime-gc.ts), contracts, 배포 파일 7개, ARCA pin.

    문서

    • 운영 가이드: 'Backup과 restore'(범위에 rgss-wasm generation·CAS 객체 명시), '운영 backup 명령'(adapter별 manifest 검증, RGSS snapshot 구성, 1.0.6 이하 결함과 수정 image 조건)
    • 완료 기준선(backup 명령 설명, 운영 backup·backup/restore·static·unit 행), 개발 계획(NAS 전환 3항), tests README(backup runner 범위)

    알려진 제한(후속 과제)

    • 실제 NAS의 sh backup.sh와 복구는 NOT RUN입니다. 배포 뒤 운영자가 위 절차로 backup을 만들고 report.json의 executionStatus·restore·evidence를 확인합니다.
    • 1.0.8 예고: 관리자 공유 링크 게스트 재생(schema migration 0001_guest_play_links 포함), ARCA 0.1.19(모바일 고 DPR 배율), 게스트 catalog 차단. migration이 있으므로 1.0.8 갱신 전에 이 릴리스의 backup이 있어야 합니다. 1.0.8을 적용하면 기존 VX/VX Ace active build는 새 generation이 필요합니다(1.0.8 노트에서 안내).
    • 구형(1.0.6 이하) image는 RGSS build가 든 snapshot을 읽지 못하므로, 이 릴리스로 만든 backup의 복구에도 1.0.7 이후 image를 씁니다.
    • 1.0.6과 같은 제한: 실제 Cloudflare 경유 artifact header, VX Ace 실제 browser acceptance, Synology 실제 환경의 갱신, PowerShell coordinator 전체 실행은 NOT RUN입니다. update.sh는 network가 빠진 container를 스스로 감지하지 않습니다. 3단계 이후 실패하면 coordinator가 정지된 채 남습니다.

    검증과 남은 범위

    • PASS: backup-rgss 수정(1.0.6 base에 cherry-pick, 코드 diff는 원 커밋과 byte 동일)
      • 관련 unit runtime-backup.test.ts(5)·runtime-backup-snapshot.test.ts(8) PASS, 전체 unit 150개 파일·1,201개 test PASS, static(Prettier·ESLint·workspace·tests typecheck·docs-static), 문서 검사, git diff --check
      • run-ops-backup.sh(web-static active/retained + rgss-wasm active seed): Player lock 충돌 fail closed, 8단계 완료, fresh restore drill PASS, rgssWasmBuildRestored PASS, evidence 3, snapshot 20 files
      • run-backup-restore.sh phase-0 drill: phase-0-backup-restore PASS(restartPersistence·freshRestore·runtimeArtifactRestore·saveSnapshot·saveHistory·savePayloadPreflight·saveFreshRestore·saveSourceBuilds·saveBrowserRestore·completedRuntimeBackupEvidence·failedBackupEvidenceRejection 모두 PASS, preserved에 rgss-wasm active generation Player tree·game/RTP CAS 객체·portable manifest 포함)
      • schema gate: infra/schema·infra/migrations·.env.example 변경 없음이라 NOT RUN
      • 리뷰(R52): 병합 가능(필수 수정 0). 1.0.6 base 적용은 Fix·Test 무충돌, Docs는 완료 기준선·tests README의 1.0.6 행을 유지한 채 backup 범위·검증과 결함 기록만 가져왔습니다
    • PASS: 릴리스 gate(Compose v2.20.1, NAS 조건)
      • 환경: 격리 docker:24.0.2-dind(overlay2), host Compose는 공식 v2.20.1 linux-x86_64 binary(release의 게시 checksum과 일치). 합성 CA의 HTTPS release 서버가 Gitea를, 합성 TLS registry가 git.2ex.dev를 대신했습니다. registry에는 실제 1.0.6 image와 이 릴리스의 1.0.7 image를 넣었습니다. 배포 파일은 1.0.6 tag와 이 릴리스 커밋의 Git blob입니다. scanner·stager 1026:100, ./data bind store, 원본 library 최상위 0:0 000 + ACL u:1026:r-x.
      • 1.0.6 설치 → reset.sh → update.sh: exit 0, 12개 service, network 불일치 0, 모두 Watchtower 제외, readiness 0/0. 합성 VX Ace(rgss-wasm, ARCA 0.1.18 build) ready, MZ(web-static) ready, 로그인 사용자 세이브 201·북마크 1.
      • 1.0.7 게시(registry latest = 1.0.7, asset 없음) 뒤 설치된 1.0.6 update.sh: exit 0(52초), Pending migrations 줄 0, Updated to 1.0.7 (catalog b6551c4d7ee8), runtime.package ready.(합성 registry digest). 7개 파일이 1.0.7과 같고 .tmp 0. 12개 service, network 불일치 0, unhealthy 0, 12/12 Watchtower 제외, package·runtime readiness exit 0, coordinator 재시작 0, catalog·Player 1.0.7. schema current(expected=recorded 14481d17…, pending 0, migration history 0행), row count 불변(installations 3, bookmarks 1, users 1, runtimeBuilds 2, activeHeads 2, jobs 5), 같은 사용자의 세이브 GET 200에 ETag·bytes·Player save 파일 목록 동일, VX Ace 0.1.18 build ready·active 유지(새 generation 불필요), MZ ready.
      • coordinator 정지 → sh backup.sh(1.0.7): exit 0(18초). [1/8]부터 [8/8]까지 8줄, Backup <id> PASS 1줄, report.json executionStatus PASS·image latest. fresh restore drill([6/8], project links-backup-verify): 복원 DB schema checksum 14481d17…(backup과 동일, migration 0), runtimeBuilds 2(rgss-wasm active + web-static active), runtime snapshot 78 files·45.7 MB(RGSS Player tree·game/RTP CAS·portable manifest 포함), save 1 namespace·2 files, evidence 2 build(rgss-wasm·web-static 각 1, restorable_until 미래), active pin 0, runtime_backup_runs 1 completed·build_count 2, verify project container·volume 잔여 0.
      • coordinator 재기동: up -d --no-build runtime-package-coordinator exit 0, 7초 뒤 Package coordinator ready (ARCA 0.1.18, …) 새 ready 줄, 재시작 0. 12 service network 불일치 0, readiness exit 0.
      • 설치 상태에서 재-update: exit 0(35초), 같은 요약 줄, 배포 파일(크기·mtime) 불변·.tmp 0, 12 service network 불일치 0, 12/12 Watchtower 제외, readiness 0/0, VX·MZ projection ready, schema current, row count 유지(playSessions만 세이브 확인 세션으로 1 증가), Player save 파일 목록 동일.
    • PASS: 최종 1.0.7 소스. 릴리스 커밋 두 개(root version, 완료 기준선의 version 문구) 뒤 문서 검사, static, git diff --check를 다시 통과했습니다.
    • 게시 이미지: 같은 최종 소스에서 build했고, gate도 이 image로 실행했습니다. image 안에서 root version 1.0.7과 ARCA pin·설치본 0.1.18을 확인했습니다.
    • NOT RUN: 실제 NAS backup·복구와 1.0.6 → 1.0.7 갱신, 실제 ARCA generation(운영 DB)의 backup, retained RGSS build 개별 drill, 브라우저 matrix(변경은 backup 경로뿐), live provider, 개발 rebuild.

    배포 이미지와 파일

    • Git annotated tag는 1.0.7이고 최종 소스는 3f6c504352입니다(branch release-1.0.7, 1.0.6 base).
    • 단일 linux/amd64 이미지: git.2ex.dev/hanyul/links:1.0.7 = git.2ex.dev/hanyul/links:latest
    • 원격 digest: sha256:91e3adb9fc5a61cf4839dfd862fb60843cf0bb3f6014b4bb99885d0aea3d4d1a
    • release asset은 없습니다. update.sh가 tag 1.0.7의 7개 배포 파일을 HTTPS로 받습니다. 대응은 update.sh=ops/deploy-registry.sh, reset.sh=ops/reset-registry.sh, backup.sh=ops/backup-registry.sh이고, 나머지는 compose.yaml·infra/docker/Caddyfile·ops/backup-verify.compose.yaml·ops/runtime-package-coordinator.sh입니다.
    • 7개 배포 파일은 모두 1.0.6과 같습니다.
    Downloads 2