Green Property Checks는 Flake Freeze Token을 재충전해서는 안 됩니다
요약
이 문서는 Flake freeze 토큰의 쓰기 정책과 자동화된 검사 시스템의 설계 원칙을 설명합니다. 속성 통과, 픽스처 일치, 그리고 freeze 토큰은 각각 독립적인 정보를 담아야 하며, 이들을 하나의 녹색 비트로 합치는 것은 잘못된 방식입니다. 자동화된 검사는 토큰을 지출할 수는 있지만, 새로운 토큰을 발행하거나 재충전해서는 안 되며, 각 검사 결과는 자신의 필드만 작성해야 합니다.
핵심 포인트
- 속성 통과와 픽스처 일치는 독립적인 정보를 유지해야 합니다.
- 자동화된 검사는 토큰 지출은 가능하나, 신규 발행이나 재충전은 금지됩니다.
- 검사 시스템 설계 시 각 결과(Property, Fixture, Token)는 별도의 필드를 사용해야 합니다.
Flake freeze는 단일 지출(single-spend) 토큰입니다. 나중에 속성 통과(property pass)가 되어도 리플레이 예산(replay budget)이 채워지지 않으며, 픽스처 일치(fixture match)가 되어도 만료 시점(expiry)이 이동하지 않습니다. 이 세 가지 결과는 서로 다른 질문에 답합니다. 이것들을 하나의 녹색 비트(green bit)로 합치는 것이 임시 면제(temporary waiver)를 영구적인 병합 규칙(permanent merge rule)으로 만드는 방식입니다.
Agent 패치(patch)들은 이러한 붕괴를 쉽게 만듭니다. diff는 모든 잠긴 출력(locked output)을 보존하면서도, 픽스처가 결코 명시하지 않은 불변성(invariant)을 깨뜨릴 수 있습니다. diff는 알려진 Flake 하나를 건드릴 수도 있지만, 여전히 병합하기에 잘못된 변경일 수 있습니다. 상태 코드(Status codes)는 분할(split)을 숨깁니다. 이 노트는 freeze ledger에 대한 쓰기 정책을 명시합니다: 자동화된 검사(automated checks)는 토큰을 지출할 수 있지만, 새 토큰을 발행하거나 재충전해서는 안 됩니다.
아래 프로그램은 2026-10-09T00:00:00Z의 고정 클럭을 가진 예시적인 명세입니다. 이는 실제 운영 실패율(production failure rates) 보고서가 아닙니다. 여기에 나열된 결과들은 이 예제가 생성하도록 작성된 것들입니다.
세 가지 답변을 세 개의 필드에 유지하기
속성 검사(Property checks)는 diff가 골든 파일(golden file) 없이 평가할 수 있는 불변성을 보존하는지 여부를 나타냅니다. 픽스처 잠금(Fixture locks)은 관찰된 출력(observed outputs)이 여전히 잠긴 다이제스트(locked digest)로 해시되는지를 나타냅니다. freeze 토큰은 검토자(reviewer)가 이미 이 실패 시그니처를 비차단적(non-blocking)으로 분류했는지, 그리고 그 분류에 아직 예산이 남아있는지를 나타냅니다.
각 검사(check)는 자신의 필드만 작성합니다. 속성 통과(property pass)는 property=pass를 저장할 뿐, remaining_replays를 증가시키지 않습니다. 픽스처 일치(fixture match)는 fixture=match를 저장할 뿐, 새로운 expires_at을 할당하지 않습니다. 토큰을 생성하는 것은 오직 mint 명령어뿐이며, 이 명령어는 패치 작성자가 제공할 수 없는 검토자 ID를 요구합니다.
Abstain은 통과(pass)가 아닙니다. 만약 불변성 모듈이 임포트(import)에 실패하면, 판결은 abstain이고 입장은 중단됩니다. 픽스처 파일이 없으면, 판결은 missing이며 match가 아닙니다. 조회 순서(Lookup order)가 여기서 주장이 아닙니다. 주장은 토큰 행(token row)이 이미 손에 있을 때 검사가 어떤 필드를 작성할 수 있는지입니다.
자동화하기 전에 매트릭스를 읽으십시오
행(Rows)은 입력입니다. 마지막 열만이 허용되는 액션입니다. write는 원장 행 자체를 변경해야 할 때만 참(true)입니다.
| Property | Fixture | Token | Action | Write row |
|---|---|---|---|---|
| fail | any | any | reject, do not read the token | no |
| ... | ||||
| 마지막 행은 재충전 금지 규칙(non-refill rule)입니다. 일치하는 경우 이 패치(patch)를 허용할 수 있습니다. 이는 테스트 ID가 공유되는 다른 토큰을 확장해서는 안 됩니다. 두 개의 서명(signatures)은 서로 다른 행입니다. 테스트 ID, 정규화된 메시지(normalized message), 그리고 Fixture ID를 해시합니다. 그 키에 패치 본문(patch body)을 넣지 마십시오. |
재생성된 차이점(diff)은 새로운 patch_id이지만, 동일한 서명을 재현하는 경우 여전히 활성 토큰을 사용할 수 있습니다. 하지만 이 토큰을 재충전할 수는 없습니다. 사용(Spending)과 재충전(Refilling)은 다른 쓰기 작업입니다. 이 둘을 분리하는 것이 핵심입니다.
서명을 정규화한 후 발행 (Normalize the signature, then mint)
불안정한 텍스트는 예산(budget)을 소진시킵니다. 어설션 메시지(assertion messages) 안에 포함된 타임스탬프와 무작위 ID는 실행할 때마다 새로운 키를 생성하여, 원장이 의도한 행을 절대 사용하지 않게 만듭니다.
- 해싱하기 전에 실패 메시지에서 타임스탬프와 생성된 ID를 제거합니다(Strip).
- 테스트 ID, 정규화된 메시지, 그리고 Fixture ID로부터
failure_signature를 구축합니다. - 이 부분들 중 어느 하나라도 비어 있으면 발행을 거부합니다.
- 원장 시계에
reviewer,reason_code,remaining_replays, 그리고expires_at을 UTC로 저장합니다. - 패치를 작성한 프로세스로부터의 발행을 거부합니다. 리뷰어 ID는 별도의 명령으로 제공되어야 합니다.
실시간 로그 대신 고정 샘플을 사용하는 로컬 정규화 검사:
python3 - <<'PY'
import hashlib, re
msg =
1. diff를 해시하고 `patch_id`를 저장합니다. 이 단계에서는 모델을 호출하지 마십시오.
2. 인프로세스(in-process)에서 속성 검사(property checks)를 실행합니다. `pass`, `fail`, 또는 `abstain`을 기록합니다. `fail` 또는 `abstain`인 경우 중단합니다. 토큰 저장소(token store)를 열지 마십시오.
3. 잠긴 피처(locked fixtures)를 재실행합니다. `match`, `mismatch`, 또는 `missing`을 기록합니다. `missing`인 경우 중단하고 잠금 작업(lock task)을 엽니다.
4. `mismatch`의 경우, `failure_signature`를 도출하여 해당 시그니처에 대한 토큰만 로드합니다.
5. 행이 누락되었거나(`row is missing`), `expires_at`이 원장 클럭(ledger clock)보다 이후가 아닌 경우 거부합니다. 자동 발행(auto-mint)하지 마십시오.
6. `remaining_replays`가 0인 경우, 해당 행을 만료로 표시하고 거부합니다. 이 쓰기 작업은 소진(exhaustion) 기록일 뿐이며 새로운 예산(budget)을 부여하지 않습니다.
7. 예산이 남아 있는 경우, 비교-교환(compare-and-swap) 방식으로 1을 감소시킨 후 보류(hold)합니다. 보류는 병합(merge)이 아닙니다.
8. `pass`와 `match`의 경우, 허용하고 `write=false`로 설정합니다. 모든 필드가 변경되지 않은 것처럼 보여도 토큰 객체는 영구 저장(persist)하지 마십시오.
9. 별도의 상위 명령어(separate command)를 통해서만 발행(Mint)하십시오. 자동화가 비용을 지출할 수 있습니다. 생성하거나, 통과 후 재충전할 수는 없습니다.
Step 8은 팀들이 녹색 스위트(green suite)가 플레이크(flake)가 사라졌다는 증거처럼 느낄 때 건너뛰는 부분입니다. 녹색 증거는 이 패치(patch)를 허용할 수 있지만, 미래의 누락이 더 큰 예산을 받아야 한다는 증거는 아닙니다. `write`가 false일 때 반환된 객체를 영구 저장하는 것은 결함(defect)인데, 왜냐하면 나중에 `decide` 내부에서 편집을 통해 필드를 재충전할 수 있고 저장이 이를 커밋하기 때문입니다.
## 실행 가능한 명세(Specification you can run)
다음 내용을 `freeze_token_gate.py`로 저장하십시오. 이는 고정된 클럭을 사용하므로 결과가 러너의 시간에 의존하지 않습니다. 소켓을 열지 않습니다. 이를 측정된 CI 보고서라기보다는 쓰기 비트(write bit)에 대한 명세로 취급하십시오.
import hashlib
import json
from datetime import datetime, timedelta, timezone
...
파일을 작성된 대로 실행했을 때 지정되는 결과는 다음과 같습니다:
- `fail`은 `reject`, `write=false`, 예산(budget)이 여전히 `2`를 반환합니다.
- `pass`와 `match`는 `admit`, `write=false`, 예산이 여전히 `2`, 만료일(expiry)도 동일하게 반환합니다.
- `pass`와 `mismatch`는 `hold`, `write=true`, 예산 `1`, 만료일은 동일하게 반환합니다.
- `abstain`은 `quarantine`, `write=false`, 예산이 여전히 `2`를 반환합니다.
두 번째 `hold`를 위해 사용된 객체(spent object)를 다시 전달하면, 다음 호출은 반드시 예산 `0`으로 `reject`해야 합니다. 이 순서가 재실행 예산(replay budget)입니다. 이것은 재시도 루프(retry loop)가 아니며, 모델을 호출할 이유도 아닙니다. 만료 타임스탬프는 원래 발행된(original mint) 기록에 남아 있습니다.
`tests/test_freeze_token_gate.py`에서 비재충전 규칙(non-refill rule)을 잠급니다:
from freeze_token_gate import FIXED_NOW, decide, mint
def test_admit_does_not_refill_or_extend():
...
python3 freeze_token_gate.py
python3 -m pytest -q tests/test_freeze_token_gate.py
만약 `test_admit_does_not_refill_or_extend`가 실패한다면, admit 경로는 동결(freeze) 행을 기록하고 있다는 의미입니다. 네트워크 클라이언트를 작업에 추가하기 전에 이 쓰기(write)를 중단하고 제거하십시오. 또한 `expires_at`을 새로 고치는 녹색 테스트 스위트(green suite)는 더 강력한 스위트가 아닙니다. 그것은 성공할 때마다 커지는 면제(waiver)일 뿐입니다.
## 무료 초안이 머무를 수 있는 곳
1단계부터 8단계까지는 로컬에서 이루어집니다. 모델 호출은 레저가 이미 재생성 가능(regenerable)하다고 표시한 이유 코드를 가지고 `reject`를 반환하고, 새로운 `patch_id`와 함께 새 diff를 생성할 때만 적격합니다. `hold`는 적격하지 않습니다. 누락된 정보(miss)는 이미 분류되었으므로, 다른 초안은 해당 행을 소비하거나 재충전해서는 안 됩니다.
공개: 이 기사는 MonkeyCode의 제품 홍보 활동의 일환으로 작성되었습니다.
MonkeyCode의 무료 모델 접근은 새로운 diff를 위한 초안 소스로 적합합니다. 이 서비스의 무료 서버 옵션은 격리된 리플레이 호스트로 사용될 수 있으므로, 실패 시그니처는 공유 러너의 남은 상태가 아닌 깨끗한 실행에서 가져옵니다. 두 서비스 모두 동결 권한(freeze authority)을 가지고 있지는 않습니다. mint 명령어는 여전히 초안 프로세스가 제공할 수 없는 검토자 ID를 필요로 합니다. 이 두 가지 가용성 주장은 운영자가 명시한 옵션일 뿐입니다. 이는 할당량(quota), 하드웨어 형태, 지연 시간 제한(latency bound) 또는 무료 경로가 유지된다는 약속이 아닙니다. 만약 그 경로가 중단되었다면, 다른 리플레이 호스트에서 동일한 원장(ledger)을 실행하십시오. 하나의 엔드포인트에 도달할 수 없다고 해서 토큰 규칙을 건너뛰지 마십시오.
초안 호출의 적격성은 측정된 성공률이 아니라 정책 목록입니다:
- 재생 가능한 이유 코드: `format`, `import-order`, `unused-symbol`.
- 재생 불가능한 경우: invariant failure, missing fixture, abstain, expired token, exhausted budget.
- 보류 상태(hold)가 아니어야 하며, mint를 대체할 수 없습니다.
속성 모듈과 픽스처 파일은 초안의 편집 가능한 경로에서 제외하십시오. invariant를 수정하거나 golden 파일을 재작성하여 플레이크를 '수정'하는 모델은 통과를 조작하는 것입니다. 빈 초안 출력은 동일한 호출을 다시 시도하라는 신호가 아니라 `abstain`으로 처리하십시오. 그런 다음 토큰 행은 그대로 두십시오.
검토 로그에 diff 작성자 외의 검토자 ID를 이미 저장할 수 있다면, 어떤 초안 클라이언트를 연결하기 전에 하나의 불안정한(flaky) 시그니처로 비재충전 테스트를 실행하십시오.
## 제한 사항
시그니처 충돌이 주요 문제입니다. 실제 회귀는 알려진 플레이크와 동일한 정규화된 메시지를 방출할 수 있습니다. 그러면 원장은 플레이크 토큰을 소모하고 거부되었어야 할 패치를 보유하게 됩니다. 예산을 낮게 설정하고, 이유 코드가 단순히 단언 텍스트가 아니라 플레이크 메커니즘의 이름을 지정하도록 요구하십시오.
클럭 스큐(Clock skew)가 두 번째 문제입니다. `expires_at`을 UTC 기준 원장 클럭과 비교하십시오. 러너 클럭은 만료된 토큰을 활성 상태처럼 보이게 할 수 있습니다. 이것이 예시가 `FIXED_NOW`를 고정하는 이유이며, 프로덕션 코드가 로그 타임스탬프를 권한으로 신뢰해서는 안 되는 이유입니다.
인메모리 스토어는 두 개의 러너(runner)가 작동할 때 안전하지 않습니다. 둘 다 예산(budget) `1`을 읽고, 감소(decrement) 작업이 원자적(atomic)이지 않으면 모두 보유(hold) 상태를 유지할 수 있습니다. 이 버그는 플레이크(flake)처럼 보이지만 그렇지 않습니다. 보유 상태를 신뢰하기 전에 `(서명(signature), 남은 재생 횟수(remaining_replays))`에 대해 비교-교환(compare-and-swap)을 사용해야 합니다.
이 게이트가 패치가 정확하다는 것을 증명하지는 못합니다. 단지 세 개의 답변이 서로를 덮어쓰도록 허용되지 않았다는 것만 증명할 뿐입니다. 의미론적 검토(Semantic review)는 테이블 외부에 남아 있어야 합니다. 속성 검사(property check)가 통과되었다고 해도, 작성한 불변 조건(invariants)만큼만 강력합니다. 만약 그 불변 조건들이 피처 파일(fixture file)의 재진술이라면, 이름 두 개를 가진 하나의 검사에 불과합니다.
무료 티어 초안(Free-tier drafts)은 추가적인 제한을 가합니다. 초안은 비어 있거나, 주제에서 벗어나거나, 혹은 피처 일치(fixture match)를 강제하는 테스트 편집일 수 있습니다. 이러한 결과 중 어느 것도 동결 행(freeze row)에 `write=true`로 설정해서는 안 됩니다. 사용 가능성(Availability)도 변할 수 있습니다. 누락된 초안 호스트가 '레저 건너뛰기(skip the ledger)'로 퇴보하는 것이 아니라, '재생성 없음(no regeneration)'으로 퇴보하도록 재생(replay)을 구축하세요.
## 언제 건너뛸 것인가 (Who should skip it)
안정적인 서명(signature)을 생성할 수 없다면 레저를 건너뛰세요. 매번 실행마다 변경되는 키에 대한 동결은 추가 열이 붙은 무제한 면제입니다.
속성 명령어(property command)와 피처 명령어(fixture command)가 동일한 프로세스라면 건너뛰세요. 하나의 답변을 두 필드에 저장하고 그 분리를 통제라고 부르는 것은 아닙니다. 명령어를 먼저 분리하거나, 테이블이 작업을 수행하는 것처럼 가장하지 마십시오.
아무도 민트(mint)할 수 없기 때문에 배포해야 하는 인시던트 핫픽스(incident hotfix)의 경우 건너뛰세요. 인시던트 경로를 사용하세요. 나중에 민트하여 해당 핫픽스를 동결 테이블로 세탁하지 마십시오. 과거 날짜로 지정된 토큰은 이 설계가 지원하도록 의도된 감사(audit) 과정에서 우회(bypass)를 숨깁니다.
모델이 실패를 플레키하다고 결정하기를 원한다면 건너뛰세요. 그 결정 자체가 민트입니다. 패치를 작성한 프로세스에 그것을 두는 것은 write 비트가 유지하기 위해 존재하는 분리를 제거합니다.
## 감사를 위해 보존할 것 (What to retain for audit)
모든 보류(hold) 또는 거부(reject) 시 다섯 가지 필드를 유지해야 합니다: `patch_id`, property verdict, fixture verdict, token signature 또는 `none`, 그리고 write bit. 이 필드들만으로 admit이 언제 `expires_at`이나 `remaining_replays`를 영속화했는지 쿼리할 수 있습니다. 만약 나중에 변경 사항이 green path에서 예산을 재충전한다면, 해당 쿼리는 서술적 검토(narrative review) 없이 실패합니다.
-- 설명적인 감사(illustrative audit), 특정 공급업체 방언(vendor-specific dialect) 아님
select patch_id, property, fixture, token_signature, write_bit
from patch_gate_log
...
빈 결과는 비재충전 규칙에 대한 예상되는 정상 상태입니다. 쿼리가 반환하는 모든 행은 그날 스위트가 green이었더라도 게이트 결함(gate defect)입니다.
운영상의 결론은 명확합니다. freeze 토큰을 한 번 사용하세요. 예산이나 원장 시계에 따라 만료시키세요. 이를 재충전하려고 시도하는 모든 자동화된 경로, 무료 초안(free draft)을 포함하여 거부해야 합니다. Property checks와 fixture locks는 자체 열을 유지하며, green 결과가 무조건적인 승인(mint)은 아닙니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기