{
  "schema_version": "1.0",
  "baseline": "A-admin-control-plane-v2b",
  "phase": "2b",
  "updated_at": "2026-04-19",
  "owner": "session_a",
  "honest_note": "TTL evaluation examples demonstrate how Phase 2b computes ttl_state from (sla_due_at, closed_at, state, matrix_row.ttl_rule) at a given as_of timestamp. Engine is decision-only: it READS the approval_store (file-backed in 2b) and RETURNS a ttl_state without mutating the row. Prec-8 fail-safe: when ambiguous, engine MUST rank the row as expired (safer to deny than permit). These examples are paired with approval_examples.json rows so the full decision boundary is testable end-to-end.",
  "ttl_semantics_summary": {
    "states": [
      { "ttl_state": "valid", "rule_th": "SLA ยังไม่หมด และ state ∈ {signed_full}", "rule_en": "sla_due_at in the future AND state is signed_full" },
      { "ttl_state": "near_expiry", "rule_th": "เหลือ ≤15 นาทีก่อน SLA", "rule_en": "<=15 min remaining before sla_due_at" },
      { "ttl_state": "just_expired", "rule_th": "เพิ่งหมด SLA ≤1 ชั่วโมง", "rule_en": "sla_due_at crossed within the last 1 hour" },
      { "ttl_state": "stale", "rule_th": "หมดนานกว่า 1 ชั่วโมง · ต้องต่ออายุผ่าน flow ใหม่", "rule_en": "more than 1 hour past sla_due_at · requires fresh approval flow" },
      { "ttl_state": "not_applicable", "rule_th": "state ∈ {pending, withdrawn, rejected, signed_partial} · TTL ไม่มีผลเพราะไม่ valid เลย", "rule_en": "state in {pending, withdrawn, rejected, signed_partial} · TTL irrelevant because approval never reached valid" },
      { "ttl_state": "unknown", "rule_th": "SLA field ขาด หรือ closed_at ผิดรูป · engine ต้องใช้ prec-8 fail-safe (treat as expired)", "rule_en": "missing sla_due_at or malformed closed_at · engine applies prec-8 fail-safe (treat as expired)" }
    ],
    "fail_safe_note": "Prec-8 fail-safe: engine ranks missing/malformed TTL as EXPIRED, never as VALID. Consumers of /api/policy/sensitive.check.2b rely on this."
  },
  "honest_limits": [
    "TTL is EVALUATED not ENFORCED · engine does not mutate expired rows, does not notify owners, does not trigger re-open flow",
    "as_of time in these examples is illustrative · real engine uses server wall clock (UTC)",
    "No renewal API · stale rows require a new approval_id via Admin Control Plane approval_queue (outside Phase 2b)",
    "File-backed store is read at request time · no caching · no invalidation; deferred to FF 2b+ cache semantics discussion"
  ],
  "examples": [
    {
      "id": "TTL-EX-V100-fresh",
      "approval_ref": "APP-260419-V100",
      "at_a_glance": "signed_full · SLA 4h · still in window",
      "as_of": "2026-04-19T10:15:00Z",
      "sla_due_at": "2026-04-19T14:00:00Z",
      "computed": {
        "ttl_state": "valid",
        "ttl_remaining_minutes": 225,
        "rationale": "signed_full · now is 3h 45min before sla_due_at · no expiry applied"
      },
      "decision_effect": "sensitive.check.2b → allow (approval satisfies matrix_row + still valid)"
    },
    {
      "id": "TTL-EX-V200-near",
      "approval_ref": "APP-260419-V200",
      "at_a_glance": "signed_full · 12 min before SLA",
      "as_of": "2026-04-19T12:48:00Z",
      "sla_due_at": "2026-04-19T13:00:00Z",
      "computed": {
        "ttl_state": "near_expiry",
        "ttl_remaining_minutes": 12,
        "rationale": "signed_full but within 15-min warning band"
      },
      "decision_effect": "sensitive.check.2b → allow with warning · emits audit.boundary event {category: warning, reason: near_expiry}"
    },
    {
      "id": "TTL-EX-E400-just",
      "approval_ref": "APP-260419-E400",
      "at_a_glance": "signed_full but past SLA by 25 min",
      "as_of": "2026-04-18T13:25:00Z",
      "sla_due_at": "2026-04-18T13:00:00Z",
      "computed": {
        "ttl_state": "just_expired",
        "ttl_remaining_minutes": -25,
        "rationale": "state is signed_full on paper · but sla_due_at crossed 25 min ago · engine downgrades effective validity"
      },
      "decision_effect": "sensitive.check.2b → deny (approval_expired) · suggested_action: request fresh approval"
    },
    {
      "id": "TTL-EX-E400-stale",
      "approval_ref": "APP-260419-E400",
      "at_a_glance": "signed_full but past SLA by 26 hours",
      "as_of": "2026-04-19T15:00:00Z",
      "sla_due_at": "2026-04-18T13:00:00Z",
      "computed": {
        "ttl_state": "stale",
        "ttl_remaining_minutes": -1560,
        "rationale": "well beyond 1-hour grace · engine marks stale · requires fresh approval_id"
      },
      "decision_effect": "sensitive.check.2b → deny (approval_stale) · suggested_action: open new approval queue item"
    },
    {
      "id": "TTL-EX-P300-not-applicable",
      "approval_ref": "APP-260419-P300",
      "at_a_glance": "signed_partial · never became valid",
      "as_of": "2026-04-19T10:15:00Z",
      "sla_due_at": "2026-04-19T14:00:00Z",
      "computed": {
        "ttl_state": "not_applicable",
        "ttl_remaining_minutes": null,
        "rationale": "state=signed_partial · required 2 signers but only 1 signed · TTL does not apply because approval never reached full validity"
      },
      "decision_effect": "sensitive.check.2b → deny (dual_signers_required) · TTL is not the reason; state is"
    },
    {
      "id": "TTL-EX-P500-pending",
      "approval_ref": "APP-260419-P500",
      "at_a_glance": "pending · SLA still running",
      "as_of": "2026-04-19T10:15:00Z",
      "sla_due_at": "2026-04-19T14:00:00Z",
      "computed": {
        "ttl_state": "not_applicable",
        "ttl_remaining_minutes": null,
        "rationale": "state=pending · not valid yet · TTL gate does not fire for pending rows"
      },
      "decision_effect": "sensitive.check.2b → deny (approval_state_invalid, sub_reason=pending)"
    },
    {
      "id": "TTL-EX-malformed",
      "approval_ref": "APP-260419-MALFORMED-FX",
      "at_a_glance": "signed_full but sla_due_at field missing",
      "as_of": "2026-04-19T10:15:00Z",
      "sla_due_at": null,
      "computed": {
        "ttl_state": "unknown",
        "ttl_remaining_minutes": null,
        "rationale": "sla_due_at missing · prec-8 fail-safe applies · rank as expired (safer to deny)"
      },
      "decision_effect": "sensitive.check.2b → deny (approval_expired, sub_reason=fail_safe_prec_8) · logged as warning for owner review"
    },
    {
      "id": "TTL-EX-W600-withdrawn",
      "approval_ref": "APP-260419-W600",
      "at_a_glance": "withdrawn · row closed by submitter",
      "as_of": "2026-04-19T10:15:00Z",
      "sla_due_at": "2026-04-19T14:00:00Z",
      "computed": {
        "ttl_state": "not_applicable",
        "ttl_remaining_minutes": null,
        "rationale": "closed terminal state · TTL irrelevant"
      },
      "decision_effect": "sensitive.check.2b → deny (approval_state_invalid, sub_reason=withdrawn)"
    },
    {
      "id": "TTL-EX-R700-rejected",
      "approval_ref": "APP-260419-R700",
      "at_a_glance": "rejected · terminal",
      "as_of": "2026-04-19T10:15:00Z",
      "sla_due_at": "2026-04-19T14:00:00Z",
      "computed": {
        "ttl_state": "not_applicable",
        "ttl_remaining_minutes": null,
        "rationale": "closed terminal state · TTL does not apply to rejected rows"
      },
      "decision_effect": "sensitive.check.2b → deny (approval_state_invalid, sub_reason=rejected)"
    },
    {
      "id": "TTL-EX-S800-platform-global",
      "approval_ref": "APP-260419-S800",
      "at_a_glance": "platform-global · signed_full · SLA 24h",
      "as_of": "2026-04-19T10:15:00Z",
      "sla_due_at": "2026-04-20T06:00:00Z",
      "computed": {
        "ttl_state": "valid",
        "ttl_remaining_minutes": 1185,
        "rationale": "signed_full by dual signers · still 19h 45min in SLA window"
      },
      "decision_effect": "sensitive.check.2b → allow (platform-global decision remains within TTL)"
    }
  ],
  "pair_with": {
    "approval_examples": "docs/runtime/admin-control-plane-service/approval_examples.json",
    "audit_event_examples": "docs/runtime/admin-control-plane-service/audit_event_examples.json",
    "contract": "docs/runtime/admin-control-plane-service/phase_2b_contract.json"
  }
}
