{"abstract":"A UTC UNTIL in a zone east of UTC cuts off the last local instance.","category":"Calendar recurrence rules","checks":7,"contract":"A daily-interval timed series in a fixed local offset (offset_min east of UTC). until may be None, a date (inclusive through the end of that local day, i.e. 23:59), a local date-time (inclusive), or a UTC date-time ending in Z (converted to local by adding offset_min). count may be None; count 0 means no instances. When both are given the series stops at whichever limit is reached first. Unbounded series are capped at 40 instances. Return ISO local date-times.","evaluation_group":"w2-calendar-recurrence-rules-until-count-semantics","failed_approach":"The partial repair `dt.datetime.fromisoformat(until[:-1])` ignores the offset and compares UTC with local wall time.","family":"w2-calendar-recurrence-rules-until-count-semantics-utc-until","id":"FA-77196","implementations":{"attempt":{"sha256":"c303c34bce9985cd9ae60574cbb079a75116e13b84200690414109fa4fb2dcd7","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\nimport datetime as dt\nimport calendar\nN = 1\nobservations = []\ndef solve(dtstart, interval, count, until, offset_min):\n    first = dt.datetime.fromisoformat(dtstart)\n    if until is None:\n        limit = None\n    elif until.endswith('Z'):\n        limit = dt.datetime.fromisoformat(until[:-1])\n    elif len(until) == 10:\n        limit = dt.datetime.combine(dt.date.fromisoformat(until), dt.time(23, 59))\n    else:\n        limit = dt.datetime.fromisoformat(until)\n    out = []\n    for k in range(40):\n        t = first + dt.timedelta(days=k * interval)\n        if limit is not None and t > limit:\n            break\n        if count is not None and len(out) >= count:\n            break\n        out.append(t.isoformat(timespec='minutes'))\n    return out\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[('regression: count and until both set',\n   ['2024-01-01T09:00', 1, 3, '2024-01-10', 0],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00']),\n  ('date until includes that day',\n   ['2024-01-01T09:00', 2, None, '2024-01-07', 0],\n   ['2024-01-01T09:00', '2024-01-03T09:00', '2024-01-05T09:00', '2024-01-07T09:00']),\n  ('date until evening event',\n   ['2024-01-01T20:00', 1, None, '2024-01-03', 60],\n   ['2024-01-01T20:00', '2024-01-02T20:00', '2024-01-03T20:00']),\n  ('local until exact',\n   ['2024-01-01T09:00', 1, None, '2024-01-04T09:00', 0],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00', '2024-01-04T09:00']),\n  ('local until earlier time',\n   ['2024-01-01T09:00', 1, None, '2024-01-04T08:00', 0],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00']),\n  ('utc until east offset',\n   ['2024-01-01T09:00', 1, None, '2024-01-03T07:00Z', 120],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00']),\n  ('utc until west offset',\n   ['2024-01-01T09:00', 1, None, '2024-01-03T15:30Z', -300],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00'])],\n [('date until evening event',\n   ['2024-01-01T20:00', 1, None, '2024-01-03', 60],\n   ['2024-01-01T20:00', '2024-01-02T20:00', '2024-01-03T20:00']),\n  ('local until exact',\n   ['2024-01-01T09:00', 1, None, '2024-01-04T09:00', 0],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00', '2024-01-04T09:00']),\n  ('local until earlier time',\n   ['2024-01-01T09:00', 1, None, '2024-01-04T08:00', 0],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00']),\n  ('utc until east offset',\n   ['2024-01-01T09:00', 1, None, '2024-01-03T07:00Z', 120],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00']),\n  ('utc until west offset',\n   ['2024-01-01T09:00', 1, None, '2024-01-03T15:30Z', -300],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00']),\n  ('count zero', ['2024-01-01T09:00', 1, 0, None, 0], []),\n  ('count zero with until', ['2024-01-01T09:00', 1, 0, '2024-02-01', 0], [])],\n [('local until earlier time',\n   ['2024-01-01T09:00', 1, None, '2024-01-04T08:00', 0],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00']),\n  ('utc until east offset',\n   ['2024-01-01T09:00', 1, None, '2024-01-03T07:00Z', 120],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00']),\n  ('utc until west offset',\n   ['2024-01-01T09:00', 1, None, '2024-01-03T15:30Z', -300],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00']),\n  ('count zero', ['2024-01-01T09:00', 1, 0, None, 0], []),\n  ('count zero with until', ['2024-01-01T09:00', 1, 0, '2024-02-01', 0], []),\n  ('until before count reached',\n   ['2024-01-01T09:00', 3, 10, '2024-01-08', 0],\n   ['2024-01-01T09:00', '2024-01-04T09:00', '2024-01-07T09:00']),\n  ('count before until reached',\n   ['2024-03-01T18:30', 7, 2, '2024-12-31T00:00Z', 60],\n   ['2024-03-01T18:30', '2024-03-08T18:30'])],\n [('utc until west offset',\n   ['2024-01-01T09:00', 1, None, '2024-01-03T15:30Z', -300],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00']),\n  ('count zero', ['2024-01-01T09:00', 1, 0, None, 0], []),\n  ('count zero with until', ['2024-01-01T09:00', 1, 0, '2024-02-01', 0], []),\n  ('until before count reached',\n   ['2024-01-01T09:00', 3, 10, '2024-01-08', 0],\n   ['2024-01-01T09:00', '2024-01-04T09:00', '2024-01-07T09:00']),\n  ('count before until reached',\n   ['2024-03-01T18:30', 7, 2, '2024-12-31T00:00Z', 60],\n   ['2024-03-01T18:30', '2024-03-08T18:30']),\n  ('regression: count and until both set',\n   ['2024-01-01T09:00', 1, 3, '2024-01-10', 0],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00']),\n  ('date until includes that day',\n   ['2024-01-01T09:00', 2, None, '2024-01-07', 0],\n   ['2024-01-01T09:00', '2024-01-03T09:00', '2024-01-05T09:00', '2024-01-07T09:00']),\n  ('utc until east offset',\n   ['2024-01-01T09:00', 1, None, '2024-01-03T07:00Z', 120],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00'])],\n [('count zero with until', ['2024-01-01T09:00', 1, 0, '2024-02-01', 0], []),\n  ('until before count reached',\n   ['2024-01-01T09:00', 3, 10, '2024-01-08', 0],\n   ['2024-01-01T09:00', '2024-01-04T09:00', '2024-01-07T09:00']),\n  ('count before until reached',\n   ['2024-03-01T18:30', 7, 2, '2024-12-31T00:00Z', 60],\n   ['2024-03-01T18:30', '2024-03-08T18:30']),\n  ('regression: count and until both set',\n   ['2024-01-01T09:00', 1, 3, '2024-01-10', 0],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00']),\n  ('date until includes that day',\n   ['2024-01-01T09:00', 2, None, '2024-01-07', 0],\n   ['2024-01-01T09:00', '2024-01-03T09:00', '2024-01-05T09:00', '2024-01-07T09:00']),\n  ('date until evening event',\n   ['2024-01-01T20:00', 1, None, '2024-01-03', 60],\n   ['2024-01-01T20:00', '2024-01-02T20:00', '2024-01-03T20:00']),\n  ('local until exact',\n   ['2024-01-01T09:00', 1, None, '2024-01-04T09:00', 0],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00', '2024-01-04T09:00']),\n  ('utc until east offset',\n   ['2024-01-01T09:00', 1, None, '2024-01-03T07:00Z', 120],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00'])]]\nfor label, args, expected in fixtures[N-1]:\n    check(label, solve(*args), expected)\nprint(json.dumps({\"observations\": observations, \"passed\": all(x[\"passed\"] for x in observations)}, ensure_ascii=False))\nraise SystemExit(0 if all(x[\"passed\"] for x in observations) else 1)\n"},"broken":{"sha256":"35caf3d5528e3518b8d7a1a1efae696b8dd98b91cf5ea65286b7a961142ff88b","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\nimport datetime as dt\nimport calendar\nN = 1\nobservations = []\ndef solve(dtstart, interval, count, until, offset_min):\n    first = dt.datetime.fromisoformat(dtstart)\n    if until is None:\n        limit = None\n    elif until.endswith('Z'):\n        limit = dt.datetime.fromisoformat(until[:-1]) - dt.timedelta(minutes=offset_min)\n    elif len(until) == 10:\n        limit = dt.datetime.combine(dt.date.fromisoformat(until), dt.time(23, 59))\n    else:\n        limit = dt.datetime.fromisoformat(until)\n    out = []\n    for k in range(40):\n        t = first + dt.timedelta(days=k * interval)\n        if limit is not None and t > limit:\n            break\n        if count is not None and len(out) >= count:\n            break\n        out.append(t.isoformat(timespec='minutes'))\n    return out\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[('regression: count and until both set',\n   ['2024-01-01T09:00', 1, 3, '2024-01-10', 0],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00']),\n  ('date until includes that day',\n   ['2024-01-01T09:00', 2, None, '2024-01-07', 0],\n   ['2024-01-01T09:00', '2024-01-03T09:00', '2024-01-05T09:00', '2024-01-07T09:00']),\n  ('date until evening event',\n   ['2024-01-01T20:00', 1, None, '2024-01-03', 60],\n   ['2024-01-01T20:00', '2024-01-02T20:00', '2024-01-03T20:00']),\n  ('local until exact',\n   ['2024-01-01T09:00', 1, None, '2024-01-04T09:00', 0],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00', '2024-01-04T09:00']),\n  ('local until earlier time',\n   ['2024-01-01T09:00', 1, None, '2024-01-04T08:00', 0],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00']),\n  ('utc until east offset',\n   ['2024-01-01T09:00', 1, None, '2024-01-03T07:00Z', 120],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00']),\n  ('utc until west offset',\n   ['2024-01-01T09:00', 1, None, '2024-01-03T15:30Z', -300],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00'])],\n [('date until evening event',\n   ['2024-01-01T20:00', 1, None, '2024-01-03', 60],\n   ['2024-01-01T20:00', '2024-01-02T20:00', '2024-01-03T20:00']),\n  ('local until exact',\n   ['2024-01-01T09:00', 1, None, '2024-01-04T09:00', 0],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00', '2024-01-04T09:00']),\n  ('local until earlier time',\n   ['2024-01-01T09:00', 1, None, '2024-01-04T08:00', 0],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00']),\n  ('utc until east offset',\n   ['2024-01-01T09:00', 1, None, '2024-01-03T07:00Z', 120],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00']),\n  ('utc until west offset',\n   ['2024-01-01T09:00', 1, None, '2024-01-03T15:30Z', -300],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00']),\n  ('count zero', ['2024-01-01T09:00', 1, 0, None, 0], []),\n  ('count zero with until', ['2024-01-01T09:00', 1, 0, '2024-02-01', 0], [])],\n [('local until earlier time',\n   ['2024-01-01T09:00', 1, None, '2024-01-04T08:00', 0],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00']),\n  ('utc until east offset',\n   ['2024-01-01T09:00', 1, None, '2024-01-03T07:00Z', 120],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00']),\n  ('utc until west offset',\n   ['2024-01-01T09:00', 1, None, '2024-01-03T15:30Z', -300],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00']),\n  ('count zero', ['2024-01-01T09:00', 1, 0, None, 0], []),\n  ('count zero with until', ['2024-01-01T09:00', 1, 0, '2024-02-01', 0], []),\n  ('until before count reached',\n   ['2024-01-01T09:00', 3, 10, '2024-01-08', 0],\n   ['2024-01-01T09:00', '2024-01-04T09:00', '2024-01-07T09:00']),\n  ('count before until reached',\n   ['2024-03-01T18:30', 7, 2, '2024-12-31T00:00Z', 60],\n   ['2024-03-01T18:30', '2024-03-08T18:30'])],\n [('utc until west offset',\n   ['2024-01-01T09:00', 1, None, '2024-01-03T15:30Z', -300],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00']),\n  ('count zero', ['2024-01-01T09:00', 1, 0, None, 0], []),\n  ('count zero with until', ['2024-01-01T09:00', 1, 0, '2024-02-01', 0], []),\n  ('until before count reached',\n   ['2024-01-01T09:00', 3, 10, '2024-01-08', 0],\n   ['2024-01-01T09:00', '2024-01-04T09:00', '2024-01-07T09:00']),\n  ('count before until reached',\n   ['2024-03-01T18:30', 7, 2, '2024-12-31T00:00Z', 60],\n   ['2024-03-01T18:30', '2024-03-08T18:30']),\n  ('regression: count and until both set',\n   ['2024-01-01T09:00', 1, 3, '2024-01-10', 0],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00']),\n  ('date until includes that day',\n   ['2024-01-01T09:00', 2, None, '2024-01-07', 0],\n   ['2024-01-01T09:00', '2024-01-03T09:00', '2024-01-05T09:00', '2024-01-07T09:00']),\n  ('utc until east offset',\n   ['2024-01-01T09:00', 1, None, '2024-01-03T07:00Z', 120],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00'])],\n [('count zero with until', ['2024-01-01T09:00', 1, 0, '2024-02-01', 0], []),\n  ('until before count reached',\n   ['2024-01-01T09:00', 3, 10, '2024-01-08', 0],\n   ['2024-01-01T09:00', '2024-01-04T09:00', '2024-01-07T09:00']),\n  ('count before until reached',\n   ['2024-03-01T18:30', 7, 2, '2024-12-31T00:00Z', 60],\n   ['2024-03-01T18:30', '2024-03-08T18:30']),\n  ('regression: count and until both set',\n   ['2024-01-01T09:00', 1, 3, '2024-01-10', 0],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00']),\n  ('date until includes that day',\n   ['2024-01-01T09:00', 2, None, '2024-01-07', 0],\n   ['2024-01-01T09:00', '2024-01-03T09:00', '2024-01-05T09:00', '2024-01-07T09:00']),\n  ('date until evening event',\n   ['2024-01-01T20:00', 1, None, '2024-01-03', 60],\n   ['2024-01-01T20:00', '2024-01-02T20:00', '2024-01-03T20:00']),\n  ('local until exact',\n   ['2024-01-01T09:00', 1, None, '2024-01-04T09:00', 0],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00', '2024-01-04T09:00']),\n  ('utc until east offset',\n   ['2024-01-01T09:00', 1, None, '2024-01-03T07:00Z', 120],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00'])]]\nfor label, args, expected in fixtures[N-1]:\n    check(label, solve(*args), expected)\nprint(json.dumps({\"observations\": observations, \"passed\": all(x[\"passed\"] for x in observations)}, ensure_ascii=False))\nraise SystemExit(0 if all(x[\"passed\"] for x in observations) else 1)\n"},"fixed":{"sha256":"62d860073f1d023df60524763ad01747833336b8c39e0d220444c8616185034e","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\nimport datetime as dt\nimport calendar\nN = 1\nobservations = []\ndef solve(dtstart, interval, count, until, offset_min):\n    first = dt.datetime.fromisoformat(dtstart)\n    if until is None:\n        limit = None\n    elif until.endswith('Z'):\n        limit = dt.datetime.fromisoformat(until[:-1]) + dt.timedelta(minutes=offset_min)\n    elif len(until) == 10:\n        limit = dt.datetime.combine(dt.date.fromisoformat(until), dt.time(23, 59))\n    else:\n        limit = dt.datetime.fromisoformat(until)\n    out = []\n    for k in range(40):\n        t = first + dt.timedelta(days=k * interval)\n        if limit is not None and t > limit:\n            break\n        if count is not None and len(out) >= count:\n            break\n        out.append(t.isoformat(timespec='minutes'))\n    return out\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[('regression: count and until both set',\n   ['2024-01-01T09:00', 1, 3, '2024-01-10', 0],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00']),\n  ('date until includes that day',\n   ['2024-01-01T09:00', 2, None, '2024-01-07', 0],\n   ['2024-01-01T09:00', '2024-01-03T09:00', '2024-01-05T09:00', '2024-01-07T09:00']),\n  ('date until evening event',\n   ['2024-01-01T20:00', 1, None, '2024-01-03', 60],\n   ['2024-01-01T20:00', '2024-01-02T20:00', '2024-01-03T20:00']),\n  ('local until exact',\n   ['2024-01-01T09:00', 1, None, '2024-01-04T09:00', 0],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00', '2024-01-04T09:00']),\n  ('local until earlier time',\n   ['2024-01-01T09:00', 1, None, '2024-01-04T08:00', 0],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00']),\n  ('utc until east offset',\n   ['2024-01-01T09:00', 1, None, '2024-01-03T07:00Z', 120],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00']),\n  ('utc until west offset',\n   ['2024-01-01T09:00', 1, None, '2024-01-03T15:30Z', -300],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00'])],\n [('date until evening event',\n   ['2024-01-01T20:00', 1, None, '2024-01-03', 60],\n   ['2024-01-01T20:00', '2024-01-02T20:00', '2024-01-03T20:00']),\n  ('local until exact',\n   ['2024-01-01T09:00', 1, None, '2024-01-04T09:00', 0],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00', '2024-01-04T09:00']),\n  ('local until earlier time',\n   ['2024-01-01T09:00', 1, None, '2024-01-04T08:00', 0],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00']),\n  ('utc until east offset',\n   ['2024-01-01T09:00', 1, None, '2024-01-03T07:00Z', 120],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00']),\n  ('utc until west offset',\n   ['2024-01-01T09:00', 1, None, '2024-01-03T15:30Z', -300],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00']),\n  ('count zero', ['2024-01-01T09:00', 1, 0, None, 0], []),\n  ('count zero with until', ['2024-01-01T09:00', 1, 0, '2024-02-01', 0], [])],\n [('local until earlier time',\n   ['2024-01-01T09:00', 1, None, '2024-01-04T08:00', 0],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00']),\n  ('utc until east offset',\n   ['2024-01-01T09:00', 1, None, '2024-01-03T07:00Z', 120],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00']),\n  ('utc until west offset',\n   ['2024-01-01T09:00', 1, None, '2024-01-03T15:30Z', -300],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00']),\n  ('count zero', ['2024-01-01T09:00', 1, 0, None, 0], []),\n  ('count zero with until', ['2024-01-01T09:00', 1, 0, '2024-02-01', 0], []),\n  ('until before count reached',\n   ['2024-01-01T09:00', 3, 10, '2024-01-08', 0],\n   ['2024-01-01T09:00', '2024-01-04T09:00', '2024-01-07T09:00']),\n  ('count before until reached',\n   ['2024-03-01T18:30', 7, 2, '2024-12-31T00:00Z', 60],\n   ['2024-03-01T18:30', '2024-03-08T18:30'])],\n [('utc until west offset',\n   ['2024-01-01T09:00', 1, None, '2024-01-03T15:30Z', -300],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00']),\n  ('count zero', ['2024-01-01T09:00', 1, 0, None, 0], []),\n  ('count zero with until', ['2024-01-01T09:00', 1, 0, '2024-02-01', 0], []),\n  ('until before count reached',\n   ['2024-01-01T09:00', 3, 10, '2024-01-08', 0],\n   ['2024-01-01T09:00', '2024-01-04T09:00', '2024-01-07T09:00']),\n  ('count before until reached',\n   ['2024-03-01T18:30', 7, 2, '2024-12-31T00:00Z', 60],\n   ['2024-03-01T18:30', '2024-03-08T18:30']),\n  ('regression: count and until both set',\n   ['2024-01-01T09:00', 1, 3, '2024-01-10', 0],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00']),\n  ('date until includes that day',\n   ['2024-01-01T09:00', 2, None, '2024-01-07', 0],\n   ['2024-01-01T09:00', '2024-01-03T09:00', '2024-01-05T09:00', '2024-01-07T09:00']),\n  ('utc until east offset',\n   ['2024-01-01T09:00', 1, None, '2024-01-03T07:00Z', 120],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00'])],\n [('count zero with until', ['2024-01-01T09:00', 1, 0, '2024-02-01', 0], []),\n  ('until before count reached',\n   ['2024-01-01T09:00', 3, 10, '2024-01-08', 0],\n   ['2024-01-01T09:00', '2024-01-04T09:00', '2024-01-07T09:00']),\n  ('count before until reached',\n   ['2024-03-01T18:30', 7, 2, '2024-12-31T00:00Z', 60],\n   ['2024-03-01T18:30', '2024-03-08T18:30']),\n  ('regression: count and until both set',\n   ['2024-01-01T09:00', 1, 3, '2024-01-10', 0],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00']),\n  ('date until includes that day',\n   ['2024-01-01T09:00', 2, None, '2024-01-07', 0],\n   ['2024-01-01T09:00', '2024-01-03T09:00', '2024-01-05T09:00', '2024-01-07T09:00']),\n  ('date until evening event',\n   ['2024-01-01T20:00', 1, None, '2024-01-03', 60],\n   ['2024-01-01T20:00', '2024-01-02T20:00', '2024-01-03T20:00']),\n  ('local until exact',\n   ['2024-01-01T09:00', 1, None, '2024-01-04T09:00', 0],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00', '2024-01-04T09:00']),\n  ('utc until east offset',\n   ['2024-01-01T09:00', 1, None, '2024-01-03T07:00Z', 120],\n   ['2024-01-01T09:00', '2024-01-02T09:00', '2024-01-03T09:00'])]]\nfor label, args, expected in fixtures[N-1]:\n    check(label, solve(*args), expected)\nprint(json.dumps({\"observations\": observations, \"passed\": all(x[\"passed\"] for x in observations)}, ensure_ascii=False))\nraise SystemExit(0 if all(x[\"passed\"] for x in observations) else 1)\n"}},"limitations":"Stipulated, bounded recurrence-expansion model evaluated offline on explicit fixtures; it is not a complete iCalendar implementation and makes no claim of standards conformance. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.","method":"Deterministic executable model with adversarial boundary fixtures.","provenance":{"created_by":"Failure Map","dependencies":"Python standard library","family":"w2-calendar-recurrence-rules-until-count-semantics-utc-until","generated_at":"2026-09-29T14:49:23.255380+00:00","license":"CC0-1.0","python":"3.12.14","seed":1,"split":"open-access"},"relevance":"Recurring calendar series are expanded into concrete instances for display, reminders and conflict checks.","repair":"At the utc until decision use `dt.datetime.fromisoformat(until[:-1]) + dt.timedelta(minutes=offset_min)`, leaving the other decision sites of the model unchanged.","root_cause":"The UTC UNTIL is converted to local time in the wrong direction.","sha256":"1fba92f1a29a671dd2213e5dff32ef486c39e93c4ecf2926598e3c07ec1092b7","title":"UNTIL value forms and COUNT/UNTIL precedence for timed series: utc until · case 01","variant":1,"variant_policy":"Five numbered records share a model and may reuse boundary fixtures.","verification":{"attempt":{"elapsed_ms":41.51,"exit_code":1,"observations":[{"actual":["2024-01-01T09:00","2024-01-02T09:00","2024-01-03T09:00"],"check":"regression: count and until both set","expected":["2024-01-01T09:00","2024-01-02T09:00","2024-01-03T09:00"],"passed":true},{"actual":["2024-01-01T09:00","2024-01-03T09:00","2024-01-05T09:00","2024-01-07T09:00"],"check":"date until includes that day","expected":["2024-01-01T09:00","2024-01-03T09:00","2024-01-05T09:00","2024-01-07T09:00"],"passed":true},{"actual":["2024-01-01T20:00","2024-01-02T20:00","2024-01-03T20:00"],"check":"date until evening event","expected":["2024-01-01T20:00","2024-01-02T20:00","2024-01-03T20:00"],"passed":true},{"actual":["2024-01-01T09:00","2024-01-02T09:00","2024-01-03T09:00","2024-01-04T09:00"],"check":"local until exact","expected":["2024-01-01T09:00","2024-01-02T09:00","2024-01-03T09:00","2024-01-04T09:00"],"passed":true},{"actual":["2024-01-01T09:00","2024-01-02T09:00","2024-01-03T09:00"],"check":"local until earlier time","expected":["2024-01-01T09:00","2024-01-02T09:00","2024-01-03T09:00"],"passed":true},{"actual":["2024-01-01T09:00","2024-01-02T09:00"],"check":"utc until east offset","expected":["2024-01-01T09:00","2024-01-02T09:00","2024-01-03T09:00"],"passed":false},{"actual":["2024-01-01T09:00","2024-01-02T09:00","2024-01-03T09:00"],"check":"utc until west offset","expected":["2024-01-01T09:00","2024-01-02T09:00","2024-01-03T09:00"],"passed":true}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"regression: count and until both set\", \"actual\": [\"2024-01-01T09:00\", \"2024-01-02T09:00\", \"2024-01-03T09:00\"], \"expected\": [\"2024-01-01T09:00\", \"2024-01-02T09:00\", \"2024-01-03T09:00\"], \"passed\": true}, {\"check\": \"date until includes that day\", \"actual\": [\"2024-01-01T09:00\", \"2024-01-03T09:00\", \"2024-01-05T09:00\", \"2024-01-07T09:00\"], \"expected\": [\"2024-01-01T09:00\", \"2024-01-03T09:00\", \"2024-01-05T09:00\", \"2024-01-07T09:00\"], \"passed\": true}, {\"check\": \"date until evening event\", \"actual\": [\"2024-01-01T20:00\", \"2024-01-02T20:00\", \"2024-01-03T20:00\"], \"expected\": [\"2024-01-01T20:00\", \"2024-01-02T20:00\", \"2024-01-03T20:00\"], \"passed\": true}, {\"check\": \"local until exact\", \"actual\": [\"2024-01-01T09:00\", \"2024-01-02T09:00\", \"2024-01-03T09:00\", \"2024-01-04T09:00\"], \"expected\": [\"2024-01-01T09:00\", \"2024-01-02T09:00\", \"2024-01-03T09:00\", \"2024-01-04T09:00\"], \"passed\": true}, {\"check\": \"local until earlier time\", \"actual\": [\"2024-01-01T09:00\", \"2024-01-02T09:00\", \"2024-01-03T09:00\"], \"expected\": [\"2024-01-01T09:00\", \"2024-01-02T09:00\", \"2024-01-03T09:00\"], \"passed\": true}, {\"check\": \"utc until east offset\", \"actual\": [\"2024-01-01T09:00\", \"2024-01-02T09:00\"], \"expected\": [\"2024-01-01T09:00\", \"2024-01-02T09:00\", \"2024-01-03T09:00\"], \"passed\": false}, {\"check\": \"utc until west offset\", \"actual\": [\"2024-01-01T09:00\", \"2024-01-02T09:00\", \"2024-01-03T09:00\"], \"expected\": [\"2024-01-01T09:00\", \"2024-01-02T09:00\", \"2024-01-03T09:00\"], \"passed\": true}], \"passed\": false}\n"},"broken":{"elapsed_ms":39.803,"exit_code":1,"observations":[{"actual":["2024-01-01T09:00","2024-01-02T09:00","2024-01-03T09:00"],"check":"regression: count and until both set","expected":["2024-01-01T09:00","2024-01-02T09:00","2024-01-03T09:00"],"passed":true},{"actual":["2024-01-01T09:00","2024-01-03T09:00","2024-01-05T09:00","2024-01-07T09:00"],"check":"date until includes that day","expected":["2024-01-01T09:00","2024-01-03T09:00","2024-01-05T09:00","2024-01-07T09:00"],"passed":true},{"actual":["2024-01-01T20:00","2024-01-02T20:00","2024-01-03T20:00"],"check":"date until evening event","expected":["2024-01-01T20:00","2024-01-02T20:00","2024-01-03T20:00"],"passed":true},{"actual":["2024-01-01T09:00","2024-01-02T09:00","2024-01-03T09:00","2024-01-04T09:00"],"check":"local until exact","expected":["2024-01-01T09:00","2024-01-02T09:00","2024-01-03T09:00","2024-01-04T09:00"],"passed":true},{"actual":["2024-01-01T09:00","2024-01-02T09:00","2024-01-03T09:00"],"check":"local until earlier time","expected":["2024-01-01T09:00","2024-01-02T09:00","2024-01-03T09:00"],"passed":true},{"actual":["2024-01-01T09:00","2024-01-02T09:00"],"check":"utc until east offset","expected":["2024-01-01T09:00","2024-01-02T09:00","2024-01-03T09:00"],"passed":false},{"actual":["2024-01-01T09:00","2024-01-02T09:00","2024-01-03T09:00"],"check":"utc until west offset","expected":["2024-01-01T09:00","2024-01-02T09:00","2024-01-03T09:00"],"passed":true}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"regression: count and until both set\", \"actual\": [\"2024-01-01T09:00\", \"2024-01-02T09:00\", \"2024-01-03T09:00\"], \"expected\": [\"2024-01-01T09:00\", \"2024-01-02T09:00\", \"2024-01-03T09:00\"], \"passed\": true}, {\"check\": \"date until includes that day\", \"actual\": [\"2024-01-01T09:00\", \"2024-01-03T09:00\", \"2024-01-05T09:00\", \"2024-01-07T09:00\"], \"expected\": [\"2024-01-01T09:00\", \"2024-01-03T09:00\", \"2024-01-05T09:00\", \"2024-01-07T09:00\"], \"passed\": true}, {\"check\": \"date until evening event\", \"actual\": [\"2024-01-01T20:00\", \"2024-01-02T20:00\", \"2024-01-03T20:00\"], \"expected\": [\"2024-01-01T20:00\", \"2024-01-02T20:00\", \"2024-01-03T20:00\"], \"passed\": true}, {\"check\": \"local until exact\", \"actual\": [\"2024-01-01T09:00\", \"2024-01-02T09:00\", \"2024-01-03T09:00\", \"2024-01-04T09:00\"], \"expected\": [\"2024-01-01T09:00\", \"2024-01-02T09:00\", \"2024-01-03T09:00\", \"2024-01-04T09:00\"], \"passed\": true}, {\"check\": \"local until earlier time\", \"actual\": [\"2024-01-01T09:00\", \"2024-01-02T09:00\", \"2024-01-03T09:00\"], \"expected\": [\"2024-01-01T09:00\", \"2024-01-02T09:00\", \"2024-01-03T09:00\"], \"passed\": true}, {\"check\": \"utc until east offset\", \"actual\": [\"2024-01-01T09:00\", \"2024-01-02T09:00\"], \"expected\": [\"2024-01-01T09:00\", \"2024-01-02T09:00\", \"2024-01-03T09:00\"], \"passed\": false}, {\"check\": \"utc until west offset\", \"actual\": [\"2024-01-01T09:00\", \"2024-01-02T09:00\", \"2024-01-03T09:00\"], \"expected\": [\"2024-01-01T09:00\", \"2024-01-02T09:00\", \"2024-01-03T09:00\"], \"passed\": true}], \"passed\": false}\n"},"fixed":{"elapsed_ms":43.058,"exit_code":0,"observations":[{"actual":["2024-01-01T09:00","2024-01-02T09:00","2024-01-03T09:00"],"check":"regression: count and until both set","expected":["2024-01-01T09:00","2024-01-02T09:00","2024-01-03T09:00"],"passed":true},{"actual":["2024-01-01T09:00","2024-01-03T09:00","2024-01-05T09:00","2024-01-07T09:00"],"check":"date until includes that day","expected":["2024-01-01T09:00","2024-01-03T09:00","2024-01-05T09:00","2024-01-07T09:00"],"passed":true},{"actual":["2024-01-01T20:00","2024-01-02T20:00","2024-01-03T20:00"],"check":"date until evening event","expected":["2024-01-01T20:00","2024-01-02T20:00","2024-01-03T20:00"],"passed":true},{"actual":["2024-01-01T09:00","2024-01-02T09:00","2024-01-03T09:00","2024-01-04T09:00"],"check":"local until exact","expected":["2024-01-01T09:00","2024-01-02T09:00","2024-01-03T09:00","2024-01-04T09:00"],"passed":true},{"actual":["2024-01-01T09:00","2024-01-02T09:00","2024-01-03T09:00"],"check":"local until earlier time","expected":["2024-01-01T09:00","2024-01-02T09:00","2024-01-03T09:00"],"passed":true},{"actual":["2024-01-01T09:00","2024-01-02T09:00","2024-01-03T09:00"],"check":"utc until east offset","expected":["2024-01-01T09:00","2024-01-02T09:00","2024-01-03T09:00"],"passed":true},{"actual":["2024-01-01T09:00","2024-01-02T09:00","2024-01-03T09:00"],"check":"utc until west offset","expected":["2024-01-01T09:00","2024-01-02T09:00","2024-01-03T09:00"],"passed":true}],"passed":true,"stderr":"","stdout":"{\"observations\": [{\"check\": \"regression: count and until both set\", \"actual\": [\"2024-01-01T09:00\", \"2024-01-02T09:00\", \"2024-01-03T09:00\"], \"expected\": [\"2024-01-01T09:00\", \"2024-01-02T09:00\", \"2024-01-03T09:00\"], \"passed\": true}, {\"check\": \"date until includes that day\", \"actual\": [\"2024-01-01T09:00\", \"2024-01-03T09:00\", \"2024-01-05T09:00\", \"2024-01-07T09:00\"], \"expected\": [\"2024-01-01T09:00\", \"2024-01-03T09:00\", \"2024-01-05T09:00\", \"2024-01-07T09:00\"], \"passed\": true}, {\"check\": \"date until evening event\", \"actual\": [\"2024-01-01T20:00\", \"2024-01-02T20:00\", \"2024-01-03T20:00\"], \"expected\": [\"2024-01-01T20:00\", \"2024-01-02T20:00\", \"2024-01-03T20:00\"], \"passed\": true}, {\"check\": \"local until exact\", \"actual\": [\"2024-01-01T09:00\", \"2024-01-02T09:00\", \"2024-01-03T09:00\", \"2024-01-04T09:00\"], \"expected\": [\"2024-01-01T09:00\", \"2024-01-02T09:00\", \"2024-01-03T09:00\", \"2024-01-04T09:00\"], \"passed\": true}, {\"check\": \"local until earlier time\", \"actual\": [\"2024-01-01T09:00\", \"2024-01-02T09:00\", \"2024-01-03T09:00\"], \"expected\": [\"2024-01-01T09:00\", \"2024-01-02T09:00\", \"2024-01-03T09:00\"], \"passed\": true}, {\"check\": \"utc until east offset\", \"actual\": [\"2024-01-01T09:00\", \"2024-01-02T09:00\", \"2024-01-03T09:00\"], \"expected\": [\"2024-01-01T09:00\", \"2024-01-02T09:00\", \"2024-01-03T09:00\"], \"passed\": true}, {\"check\": \"utc until west offset\", \"actual\": [\"2024-01-01T09:00\", \"2024-01-02T09:00\", \"2024-01-03T09:00\"], \"expected\": [\"2024-01-01T09:00\", \"2024-01-02T09:00\", \"2024-01-03T09:00\"], \"passed\": true}], \"passed\": true}\n"}},"verified":true,"visibility":"public"}