고정 발행 감사

“추첨 전에 공개했는가”를 남기는 고정 발행 구조

추천 번호를 사후에 만들어 성공 사례처럼 보여주면 어떤 성과도 검증할 수 없습니다. 로또 시그널의 공개 발행은 발행일·대상 회차를 키로 삼아 표준 10줄을 한 번만 생성하고, 번호·점수·분석 근거를 포함한 해시를 남깁니다. 추첨 후에는 같은 기록에 등수·낙첨을 연결합니다.

작성 로또 시그널 데이터 에디터

1. 발행 키는 날짜와 대상 회차를 함께 묶습니다

서비스는 저장된 최신 확정 회차에 1을 더해 대상 회차를 정합니다. 발행 키는 YYYYMMDD-r{대상회차} 형식입니다. 예를 든 20260807-r1236은 형식을 설명하기 위한 가상 키이며, 2026년 8월 7일에 1236회를 대상으로 발행했다는 뜻입니다. 날짜만 쓰지 않는 이유는 공식 회차가 갱신된 날에 같은 날짜에도 대상 회차가 다른 발행본이 필요할 수 있기 때문입니다.

표준 발행 개수는 10줄입니다. 홈에서 3줄, 다른 화면에서 5줄를 요청해도 새로 생성하지 않고 고정된 10줄의 첫 3줄·앞 5줄을 돌려줍니다. 회차와 발행 키가 같은데 화면별 전체 해시가 다르게 보인다면 별도의 공개 발행이 아닌지, 보여주는 줄 수만 다른지를 먼저 확인해야 합니다.

2. 동시 요청은 전역 파일 잠금으로 한 번만 발행합니다

공개 페이지에 여러 사용자가 동시에 접속하면 같은 발행 키에 대해 여러 프로세스가 한꺼번에 생성을 시도할 수 있습니다. 서비스는 발행 저장소의 잠금 파일을 열고 배타 잠금을 얻은 프로세스만 읽기·생성·쓰기를 수행하게 합니다. 이미 유효한 파일이 있으면 새 번호를 만들지 않고 그 파일을 읽습니다.

파일이 없을 때만 published-daily-v1|target-{round} 문맥으로 엔진을 실행합니다. 시드에는 모드, 최신 기준 회차, 기준일과 문맥이 들어가므로 같은 코드·같은 데이터·같은 발행 문맥에서는 번호를 재현할 수 있습니다. 이 재현성은 교배·비보안 난수 보장이 아니라 감사와 회귀 테스트를 위한 설계입니다.

3. 임시 파일을 완성한 뒤 원자적으로 교체합니다

발행 내용은 JSON으로 직접 대상 파일에 덮어쓰지 않습니다. 먼저 난수 접미사가 포함된 새 임시 파일을 배타적 생성 모드로 열고, 전체 바이트를 끝까지 쓴 뒤 버퍼를 비웁니다. 파일 크기는 4MiB 이하로 제한하고, 쓰기가 완료된 임시 파일을 최종 경로로 이름 바꿔 교체합니다. 중간에 오류가 나면 임시 파일을 지우고 기존 발행본을 그대로 두도록 작성되어 있습니다.

이 절차는 파일이 절반만 쓰인 상태로 공개 요청에 읽히는 가능성을 줄입니다. 클라이언트의 저장 중단 방지와는 다른, 서버 파일 저장의 무결성 절차입니다. 읽을 때도 파일 크기를 먼저 검사하고, 유효한 JSON 배열인지 확인한 후 필드·회차·해시를 재검사합니다. 필수 값이 맞지 않은 파일은 유효하지 않은 백업으로 이름을 바꾸고 새로 발행합니다.

4. 결과 해시에 포함되는 필드를 공개합니다

SHA-256을 어떻게 만드는지 알 수 없다면 해시 문자열은 단순한 장식에 그칩니다. 서비스는 점수와 지표 배열의 키를 정렬한 후, 발행 메타데이터와 표준 10줄을 일정한 순서의 JSON으로 직렬화합니다. 그 문자열에 SHA-256을 적용한 64자 16진수가 결과 해시입니다.

영역해시 입력이유
발행 식별형식 버전, 엔진명, 엔진 지문, 모드어떤 구현이 생성했는지 구분
시점발행 키, 발행일, 대상 회차사후 소급 생성을 구분
데이터 경계기준 회차, 기준 추첨일대상 회차보다 이전 자료인지 확인
조합 원문라벨, 정렬된 번호 6개발행 후 번호 교체 감지
분석전체·균형·추세·희소·위험 점수, 세부 지표, 설명번호는 같고 점수만 사후 조정하는 변경 감지
후보 문맥후보 표본 수, 표본 내 상위 비율선택 근거가 바뀌었는지 확인

추첨 시각, 사후 확인 시각, 사후 등수는 해시 대상 조합 원문이 아닙니다. 당첨번호가 공개된 뒤 검증 상태를 추가할 수 있어야 하기 때문입니다. 다만 사후 판정은 원본 발행본을 덮어쓰지 않고 별도의 검증 필드로 보관합니다.

5. 엔진 지문은 출력이 아닌 생성 코드의 식별자입니다

결과 해시가 출력 내용을 식별한다면, 엔진 지문은 어떤 소스코드가 출력을 만들었는지 구분합니다. 현재 발행 서비스는 엔진 이름, 캐시 버전, 엔진 PHP 파일의 SHA-256을 결합해 엔진 지문을 만듭니다. 점수 가중치나 후보 필터 코드가 바뀌면 지문도 바뀌므로, 개정 전 발행본과 개정 후 발행본을 같은 엔진 버전처럼 합치는 오류를 줄입니다.

엔진 지문이 같다고 서버의 모든 환경이 같다는 뜻은 아닙니다. PHP 버전, 운영체제, DB 연결 상태, 외부 공식 데이터 응답은 별도 환경입니다. 그러므로 지문을 시스템 전체의 완전한 버전 증명으로 해석해서는 안 됩니다. 발행 기록에 데이터 기준 회차·기준일을 함께 남기는 이유가 이에 있습니다.

6. 파일과 데이터베이스는 서로 다른 장애 상황을 보완합니다

발행 원본은 서버의 JSON 파일에 먼저 고정되고, 같은 발행 메타데이터와 각 조합은 DB에도 저장을 시도합니다. DB 저장은 트랜잭션 안에서 발행 키를 잠그고, 이미 같은 키가 있으면 기존 결과 해시와 비교합니다. 키가 같은데 해시가 다르면 충돌로 거부합니다. 새 발행이면 발행 레코드를 넣고, 연결된 10개 조합을 순서대로 저장한 뒤 전체를 완료합니다.

DB가 잠시 연결되지 않아도 이미 쓰인 고정 파일은 공개 감사에 사용할 수 있습니다. 감사 조회는 DB 기록과 파일 목록을 합치고, 같은 키가 있으면 중복을 제거합니다. 이 설계는 공유 호스팅에서 DB 마이그레이션이나 연결이 일시적으로 안 되는 상황에서도 발행 근거를 잃지 않게 하는 데 유용합니다. 다만 파일과 DB가 모두 백업을 대체하는 것은 아니며, 서버 저장소 손실에 대비한 별도 백업은 필요합니다.

7. 추첨 후 판정은 원본을 바꾸지 않고 결과를 연결합니다

대상 회차 당첨번호가 저장되기 전에는 발행본의 상태가 ‘추첨 대기’입니다. 회차가 동기화된 뒤 각 줄을 당첨번호 6개와 대조하고, 6개 일치는 1등, 5개+보너스는 2등, 5개는 3등, 4개는 4등, 3개는 5등, 그 외은 낙첨으로 판정합니다. 일치 번호, 보너스 일치, 최고 일치 수, 당첨 조합 수를 함께 기록합니다.

실제 성과 장부는 발행 시점 이후 누적된 공개 발행본 전체를 분모로 사용합니다. 당첨 조합만 남기지 않고 낙첨 조합과 판정 대기 발행을 같이 보여줍니다. 4·5등은 고정 당첨금을 합산하지만, 1~3등은 회차별 변동 당첨금이므로 발생 건수로 분리합니다. 역사적 재실행 백테스트는 공개 운영 성과에 합치지 않습니다.

해시가 증명하지 못하는 것

  • 해시 일치는 발행 후 내용이 안 바뀌었다는 뜻이지, 번호의 예측력을 증명하지 않습니다.
  • 원본 회차 데이터가 잘못되었다면 잘못된 내용도 일관되게 해시화될 수 있습니다.
  • 엔진 지문은 핵심 엔진 소스를 구분하지만 서버 환경 전체의 완전한 재현 보증은 아닙니다.
  • 발행 파일이 남아 있는 동안의 감사 절차이므로 보존 주기·서버 백업이 따로 필요합니다.
  • 실제 당첨여부와 당첨금 지급은 실물 복권과 동행복권 공식 판정이 최종 기준입니다.

출처와 관련 자료