• LINKS 0.19 — 결함 수정·알고리즘 개선·관리 기능·ARCA 0.1.14

    LINKS 0.19

    이전 릴리스 0.18 대비 변경 사항입니다. 루트 패키지는 0.19.0이고, ARCA는 0.1.13 → 0.1.14로 올렸습니다.

    업그레이드 주의 — 운영 데이터 전체 초기화 필요

    • schema 버전이 바뀌었습니다: f83505b0… → cd63767d…. 0.18 DB는 새 이미지가 변환하지 않고 멈춥니다.
    • 형식이 바뀌었습니다: RGSS 실행본 목록, 세이브 backup, artifact backup. 그래서 DB뿐 아니라 artifact·세이브 저장소도 함께 비워야 합니다.
    • 배포 순서: reset.sh --execute → update.sh. 그 뒤 관리자 패스키를 다시 등록하고 library를 다시 스캔하세요.
    • 기존 세이브·사용자·패스키는 이어지지 않습니다.
    • 0.18 이하 backup은 이 버전에서 복원할 수 없습니다.
    • 원본 game library는 읽기 전용이라 영향이 없습니다.

    환경 키 변경

    • 삭제
      • LINKS_USER_REGISTRATION_ENABLED: 공개 가입이 없어지고 초대제로 바뀌었습니다.
      • LINKS_DLSITE_HTML_EXPERIMENTAL_ENABLED: DLsite 실험 경로를 제거했습니다.
    • 추가 (기본값은 .env.example 참고)
      • LINKS_JOB_RETENTION_DAYS: 끝난 작업 기록 보존 기간(기본 90일)
      • LINKS_PLAYER_REPORT_RETENTION_DAYS: 처리 완료된 신고 보존 기간(기본 180일)
      • LINKS_ALERT_BACKUP_OVERDUE_HOURS, LINKS_ALERT_STORAGE_MIN_FREE_PERCENT, LINKS_ALERT_JOB_CONSECUTIVE_FAILURES: 운영 경고 기준(기본 48시간·10%·3건)
      • LINKS_RUNTIME_PACKAGE_WORKER_ID

    새 기능

    • 사용자 관리·초대제 가입
      • 공개 가입을 없앴습니다. 관리자가 1회용·만료 있는 초대 링크(기본 7일)를 만들면, 받은 사람이 패스키로 가입합니다.
      • 관리자 "사용자" 탭에서 목록을 보고 비활성화·재활성화할 수 있습니다.
      • 비활성화하면 catalog 세션, Player 세션, 아직 쓰지 않은 실행 권한을 즉시 폐기합니다.
      • 자기 자신과 마지막 관리자는 비활성화할 수 없습니다. 패스키를 잃어버리면 재등록 초대로 복구합니다.
    • 관리자 "작업" 탭
      • 실패한 작업 목록을 보여 주고, 재개할 수 있게 했습니다. 재개할 수 없으면 이유를 표시합니다.
      • 기능별 worker 응답 상태와 큐 통계를 보여 줍니다.
      • 운영 경고 배지(서버가 판정)를 띄웁니다: backup 실패·미실행, 저장소 여유 부족, 같은 유형 작업 연속 실패.
    • 감사 기록 조회: "로그" 탭 안에 넣었습니다. 허용된 필드만 보여 주고, 사유·식별 token은 숨깁니다.
    • 매칭 검토
      • 추천·충돌·근거·점수 범위 필터와 점수순 정렬을 넣었습니다.
      • 이전에 "관련 없음"으로 처리한 쌍은 기본으로 숨깁니다.
    • 다시 수집 범위: 없는 것만 / 전부 / parser 갱신분 / 실패분 / 오래된 것(30일, 오래된 순으로 실행). 게임 몇 개만 지정한 요청은 먼저 처리합니다.
    • 표지 직접 선택: 관리자가 이미 수집된 공급자 이미지 중에서 고릅니다. 원본은 보존하고, 선택은 해제할 수 있습니다.
    • 탐색
      • 공급자별 태그 둘러보기(개수 표시)를 넣었습니다.
      • 개인 라이브러리를 저장순·최근 실행순·제목순으로 정렬하고, 전체 수를 표시합니다.
      • 이미지 뷰어에 로딩 표시를 넣고, 앞뒤 이미지를 미리 받습니다.
    • 버그 신고: 관리자가 "처리 완료"를 표시할 수 있습니다. 처리 완료된 신고는 180일 뒤 정리합니다.
    • 세이브 충돌 보존: 두 탭에서 동시에 저장해 충돌하면, 진 쪽을 "충돌로 보존된 세이브"로 이력에 남깁니다(최대 5개).
    • HTML5 엔진 진단 명령: 인식하지 못한 HTML5 엔진 후보의 개수만 셉니다. 작품명·경로는 출력하지 않습니다.

    검색·매칭 알고리즘

    • 검색
      • 가나·물결표·전각·구두점을 같은 글자로 봅니다(fold v2, JS와 SQL이 같은 결과).
      • 여러 단어는 모두 들어간 게임만 찾습니다(최대 5개). 제작사 이름으로도 검색됩니다.
      • 검색하는 동안의 기본 정렬은 "검색 일치순"입니다. 외부 ID 일치 → 제목 완전 일치 → 앞부분 일치 → 부분 일치 순입니다.
    • 폴더 제목 매칭
      • 정규화 v2에서 가나, 로마 숫자(II·Ⅱ → 2), &·と·and를 통일합니다.
      • 폴더 제목이 공급자 제목과 정규화 뒤 완전히 같으면 "수락"을 추천합니다(확정은 관리자).
      • 점수 버전: match-score-v4, exact-id-link-v3
    • 상품 폴더 인식 확장: [RJ…]제목처럼 붙여 쓴 이름, 서클·분류 괄호, 버전·체험판·DL판 표기를 인식합니다.
    • 설치본 비교 v2
      • 안쪽 wrapper 폴더 이름을 무시합니다. 그래서 버전업하거나 이름만 바뀐 사본도 후보로 잡힙니다.
      • 같은 외부 ID를 가진 설치본끼리는 폴더 구조만 비교해 번역판·패치판 후보로 올립니다. 병합은 하지 않습니다.
    • 판별 규칙: classifier v9
      • 상위 묶음 폴더 이름은 역할 근거로 쓰지 않습니다.
      • 깊은 곳의 archive는 가장 가까운 설치본에 포함합니다.
      • Game.ini는 ARCA 0.1.14 공개 입력 계약을 따릅니다. 대소문자 무관으로 찾고, 대소문자만 다른 파일이 여러 개면 충돌로 처리합니다. BOM이 붙은 파일은 미지원입니다.
    • 정렬 고정: fingerprint, 산출물·검증 정렬, 경로 대소문자 비교를 서버 언어 설정·ICU 버전과 무관한 코드 포인트 순으로 고정했습니다(fingerprint v2 등).

    크롤링

    • DLsite는 저장된 최종 주소에서 시작합니다. 다시 수집할 때 페이지 요청이 4회에서 2회로 줄었습니다(합성 측정).
    • 표지 이미지 요청이 막혀 있어도 상세 정보는 먼저 게시합니다. 표지는 다음 수집 때 받습니다.
    • VNDB는 100개 단위로 묶어 조회하고, enrich보다 먼저 실행합니다. release 조회는 250회에서 3회로 줄었습니다(합성 측정).
    • 설치본 1개만 지정한 "다시 수집"은 24시간 cache를 무시하고 새로 받습니다.
    • 정확한 ID로 만든 작품 연결 후보를 수집이 끝난 뒤 다시 채점합니다.
    • 수정한 결함
      • 설정하지 않은 공급자 때문에 "수집 중"이 계속 표시되고 화면이 무한히 다시 조회하던 문제
      • VNDB가 일시적으로 실패하면 검토 후보가 사라지던 문제
      • DLsite 표지 주소가 허용 목록과 조금만 달라도 상세 정보까지 버리던 문제
    • "전체 다시 수집"을 한 번에 접수합니다. 1.6만 개에서 메모리 부족으로 실패하던 것이 1.7초에 끝납니다(합성 측정).
    • Getchu는 연령 확인 없이는 내용을 받을 수 없을 수 있어 꺼 둔 상태로 유지합니다(BLOCKED).

    성능 (모두 합성 데이터 측정)

    항목 이전 이후
    검색(설치본 1만 개, PostgreSQL JIT 해제·2단계 조회) 수 초 약 0.1~0.2초
    목록 마지막 페이지(1만 개) 6.5~10초 약 50ms
    스캔 완료 단계(10만 entry·후보 5천) 65.8초 0.13초
    재연결 후보 계산(5천×5천) 약 7초 약 0.6초
    VX 준비 시 원본 읽기 9회 3회
    세이브 목록 100행 368ms 171ms
    실행 준비 목록 100행 228ms 14ms
    북마크 상세 100행 329ms 78ms
    • 범위 밖 페이지를 요청하면 서버가 마지막 페이지로 바꿔 보여 줍니다. 목록에는 쿼리 시간 제한, 요청 한도, 페이지 상한(10,000)을 넣었습니다.
    • Player
      • MZ의 script·plugin을 최대 4개씩 미리 받습니다.
      • VX artifact를 다시 요청할 때 서버가 전체 hash를 다시 계산하지 않습니다.
      • 일시적으로 실패한 asset은 다시 받을 수 있습니다.
      • OPFS 공간이 부족하면 cache만 포기하고 실행은 계속합니다(16MiB 이하 파일).
    • 작은 이미지 칸과 이미지 뷰어는 원본 대신 축소본(WebP)을 받습니다.

    신뢰성

    • 실행 준비
      • 이전 build와 같은 내용으로 돌아온 설치본이 준비에 실패하던 문제를 고쳤습니다. 이미 정리된 build로 돌아온 경우에는 자동으로 다시 준비합니다.
      • 오류 코드가 원인별로 보존됩니다. 재시도해도 성공할 수 없는 실패는 바로 끝냅니다.
    • 스캔
      • 하위 폴더 하나의 읽기 오류는 그 폴더만 경고로 격리합니다.
      • 상위 폴더가 바뀌면 지금처럼 실패로 처리합니다(결정 기록).
    • GC: VX/VX Ace build GC가 멈추던 문제를 고쳤고, 설치본끼리 공유하는 실행본을 보호합니다.
    • 표지: 손상된 저장 파일은 자동으로 복구하고, API는 500 대신 503을 반환합니다. 일시적인 이미지 decode 실패는 재시도합니다.
    • 로그·보존
      • worker 실패 로그를 관리자 로그 화면에서 읽을 수 있습니다. catalog healthcheck(/readyz)와 로그 순환(10MB×3)을 넣었습니다.
      • 끝난 작업 기록은 90일 뒤 정리합니다. 진행 중 작업, 재개할 수 있는 실패 작업, 감사 기록이 참조하는 작업은 보존합니다.

    ARCA 0.1.14

    • 자체 runtime ZIP 해제기를 공개 verifyArcaRuntimeDirectory로 바꿨고, contracts 검증은 verifyArcaContracts로 바꿨습니다.
    • VX/VX Ace 준비 화면이 ARCA Builder의 공식 진행 이벤트(단계·처리량)를 보여 줍니다. 실패는 failure-report code로 분류합니다.
    • ARCA_RTP_*, ARCA_RELEASE_* 오류 code를 쓰고, compose 격리 설정이 ARCA 공개 helper와 같은지 검사합니다.
    • 실행 엔진(native runtime)은 0.1.13과 같습니다.

    정리

    • DB 초기화로 필요 없어진 호환 경로를 제거했습니다: 이전 session·cursor·snapshot·manifest v2 등.
    • 번역 검수 분기와 DLsite 실험 경로를 제거했고, 기본 glossary seed를 추가했습니다.
    • 문서를 최신화하고 중복을 정리했습니다.

    알려진 제한

    • 폴더 제목 정규화 v2의 한계: 한자 사이의 と가 원래 단어 일부인 경우와 가나 동음이의어는 같은 제목으로 볼 수 있습니다. 확정은 관리자가 근거 label을 보고 합니다.
    • ARCA SDK 새 기능(2단계 실행·공식 로딩 진행률)과 16MiB 초과 파일의 OPFS 공간 부족 처리는 실제 게임 측정 때 진행합니다. keyboard.passthrough는 보류했습니다.
    • ARCA registry에서 @rgss23/arca@0.1.13을 받을 수 없어, 0.18 이하 commit을 다시 설치할 수 없습니다. ARCA에 보존을 요청해 두었습니다.

    검증

    • PASS: 각 차수의 통합 소스에서 실행했습니다.
      • static, unit(최종 843 tests), 전체 schema fresh(188 tests), provider contract
      • scanner, runtime-workers, RGSS builder, backup-restore(.sh·.ps1), 운영 backup, translation import
      • 실제 WebAuthn 패스키 acceptance(Chromium)
      • 관련 browser check(Chromium·Firefox)
    • NOT RUN: 실제 게임 전체 acceptance(입력·오디오·save/reload), 실제 library 정확도·시간 측정, NAS 배포, live 공급자 호출, Firefox 실제 WebAuthn

    배포 파일과 이미지

    • 이미지: git.2ex.dev/hanyul/links:0.19 = latest, digest sha256:54de7a6b06cf06f9979611cf9dd75c38bf1eea9a882a14162411f5fde082bff4
    • NAS 배포 파일 SHA-256 (tag 0.19):
    e63f9cccdaa99f26cedc2d5583c22d0cf036e57d4df4a9f21a381c65ee269e8c  compose.yaml
    6e1fd3f2f73faee52abca28c8552cde417f496d86fc3d78c7001dec480e171a3  infra/docker/Caddyfile
    39a4c55050e76043c8ca70f11f59dbdf08fff7ef38c1f1ec878f96194988d9d8  ops/backup-verify.compose.yaml
    590c58c5adc610cfe369c64e7d3c297ae172a7e68698c6ee23ee283dac2e69f9  ops/deploy-registry.sh
    89375a986b3cb64cf74145541701b32c6a0e983a72ca46be21a8bcfad7beaa3d  ops/backup-registry.sh
    5a9c19ba45b598974cc4393952da58df454ae9430257b927ac5106a114b8033e  ops/reset-registry.sh
    
    Downloads 2