Files
trex-core/.proofline/criteria/ac-0040.md
T

4.5 KiB

id, status
id status
ac-0040 active

Ledger outbox idle poll 로그 억제와 운영 metric

Criterion

Ledger outbox writer는 pending row가 없는 poll마다 instance-local process-lifetime empty poll counter를 정확히 증가시키되 empty claim INFO를 생성하지 않아야 한다. non-empty batch claim은 configured instance_key, non-zero count, limit, 해당 batch의 non-empty correlation ID를 repository claim 순서와 동일한 correlation_ids JSON string array로 INFO에 남겨야 한다. empty poll은 claim INFO 자체를 생성하지 않으므로 correlation_ids field도 출력하지 않는다.

trex.slots.req의 spy=true 응답은 top-level ledger_outbox_metrics를 포함해야 한다. 정상 snapshot은 available=true, scope=process_lifetime, configured instance_key를 포함하고, claims object에서 empty_polls_total, claimed_batches_total, unavailable_total, lost_total, foreign_instance_total을, outcomes object에서 completed_total, duplicate_completed_total, retryable_failure_total, conflict_blocked_total, permanent_failure_total, dead_lettered_total을 각각 누락 없는 0 이상의 정수로 제공해야 한다. snapshot은 해당 daemon process의 configured instance writer만 집계하고 내부 mutable counter와 분리된 새 값이어야 한다. reader가 없거나 조회가 실패하면 available=false, scope=process_lifetime, configured instance_key, reason=ledger_outbox_metrics_unavailable만 포함한 snapshot을 반환하며 slots 조회 자체는 성공해야 한다. spy=false 응답에는 ledger_outbox_metrics key를 포함하지 않아야 한다.

TrexDaemon._ledger_loop()에서 writer가 예상 밖 예외를 던지면 reason=ledger_writer_run_once_failed, configured instance_key, exception class name인 exc_type만 ERROR로 남기고 다음 configured poll을 계속해야 한다. empty/non-empty/failure 관측 어디에도 credential, account identifier, token, password, DSN, provider payload, raw exception message, traceback 또는 exc_info가 포함되어서는 안 된다. fixed polling cadence, retry scheduling, claim lease, ownership/filtering과 기존 outcome 의미는 바뀌지 않아야 한다.

Verification

  • 성공 조건: 기본 ledger_interval_sec=1.0의 24시간에 해당하는 86,400회 empty run_once()를 실제 sleep 없이 instance-a와 instance-b writer에 각각 실행했을 때 각 empty_polls_total이 정확히 86,400이고 rendered INFO의 claim_result=empty 및 correlation_ids가 0건인지 확인한다. 한 개 이상의 item을 claim하면 batch INFO에 configured instance, non-zero count, limit와 repository claim 순서 그대로인 correlation_ids JSON string array가 있고 claimed_batches_total 및 처리 outcome totals가 맞는지 확인한다.
  • 운영 조회 조건: spy=true에서 정상 schema의 모든 key와 zero/default 정수, instance/process 격리, 매 호출 새 snapshot을 확인한다. reader absent 및 reader exception에서는 stable unavailable snapshot과 slots 응답 성공을 확인한다. spy=false에는 metrics key가 없음을 확인한다.
  • 실패·보안 조건: sentinel secret을 포함한 writer exception을 두 번의 loop tick 중 첫 tick에 주입해 ERROR reason·instance·exception type, 두 번째 tick 실행, raw sentinel·exception message·traceback·exc_info 부재를 확인한다. 기존 claim-lost, foreign/unowned, retryable, conflict, permanent, dead-letter, success와 duplicate outcome의 severity·counter·상태 전이가 유지되는지 확인한다.
  • 변경 없음 조건: AC-0029의 InMemory/PostgreSQL ownership, active lease exclusion, expiry recovery, stale-token fencing과 foreign/unowned isolation을 회귀 검증한다. ledger_interval_sec, retry next_retry_at, DB schema, ledger API와 dead-letter policy의 diff가 없는지 확인한다.
  • 문서 조건: docs/runtime-flows.md와 docs/interface-contract.md가 empty claim INFO suppression, spy operator-only metrics, process-lifetime 및 restart-reset scope, fixed cadence 유지, sanitized writer exception과 loop survival을 명시하는지 직접 검사한다.
  • 검사 방법: focused writer·messaging handler·daemon unit tests, InMemory parity tests, disposable PostgreSQL multi-instance tests, 전체 pytest, Ruff, compileall, proofline validate, git diff --check를 실행한다. PostgreSQL fixture가 없어서 skip되면 통과로 치환하지 않고 환경 미검증으로 보고한다.