{
  "_comment": "task-2563 §3 FUC-3 1:1: logger.exception with secret masking fixture.",
  "_scenario": "owner_trigger_only.trigger_gemini_review() 호출 중 http_post 가 HTTPError 를 raise. logger.exception 이 호출되며 token 원문은 절대 노출되지 않고 GitHub diagnostic 필드만 redacted 형태로 기록.",
  "redaction_contract": {
    "redact_key_pattern_regex": "(?i)(token|authorization|api[_-]?key|secret|password)",
    "redact_value_sentinels": [
      "Bearer ",
      "ghp_",
      "github_pat_",
      "ghu_",
      "ghs_",
      "ghr_"
    ],
    "redact_placeholder": "<redacted>",
    "max_recursion_depth": 8,
    "applies_to_types": ["dict", "list", "tuple", "str", "other_via_str_cast"]
  },
  "diagnostic_fields_to_preserve": [
    "status",
    "x-github-request-id",
    "x-accepted-github-permissions",
    "documentation_url"
  ],
  "exception_scenarios": [
    {
      "label": "transient_http_500",
      "exc_type": "RuntimeError",
      "exc_message": "GitHub API 5xx (transient)",
      "status": 500,
      "response_headers": {
        "x-github-request-id": "ABCD:EF01:2345:6789:64ABCDEF",
        "x-accepted-github-permissions": "issues=write",
        "documentation_url": "https://docs.github.com/rest/issues/comments"
      },
      "expected_logger_calls": 1,
      "expected_http_post_calls": 1,
      "expected_audit_result": "FAILED",
      "expected_audit_error_code": "HTTP_POST_FAIL",
      "expected_audit_token_value_logged": false,
      "expected_audit_token_hash_prefix_length": 8,
      "secret_must_not_appear_in_log": "MY_SECRET_TOKEN_VALUE_2563"
    },
    {
      "label": "permission_403",
      "exc_type": "RuntimeError",
      "exc_message": "Resource not accessible by personal access token (insufficient scopes)",
      "status": 403,
      "response_headers": {
        "x-github-request-id": "DEAD:BEEF:1234:5678:CAFEFEED",
        "x-accepted-github-permissions": "issues=write,pull_requests=write",
        "documentation_url": "https://docs.github.com/rest/overview/permissions-required-for-fine-grained-personal-access-tokens"
      },
      "expected_logger_calls": 1,
      "expected_http_post_calls": 1,
      "expected_audit_result": "FAILED",
      "expected_audit_error_code": "HTTP_POST_FAIL"
    }
  ],
  "regression_assertions": [
    "logger.exception is called exactly once per failure",
    "logger.exception traceback is included (sys.exc_info present at call time)",
    "captured log record getMessage() does NOT contain token raw value sentinel",
    "captured log record getMessage() does NOT contain full Authorization header",
    "captured log record getMessage() contains status / x-github-request-id when present (redacted dict)",
    "audit JSONL still records FAILED + token_value_logged=False + token_hash_prefix",
    "no HTTP POST side effect (http_post mock receives 1 call only, the failed one)"
  ],
  "fail_closed_invariants": {
    "audit_failed_recorded": true,
    "audit_token_value_logged": false,
    "audit_token_hash_prefix_present": true,
    "http_post_extra_side_effects": 0,
    "logger_called_before_txn_record_failed": true
  }
}
