{"abstract":"Every collection grows the heap regardless of free space.","category":"Garbage collector invariants","checks":7,"contract":"After each full collection with live bytes L and capacity C: if the free share (C - L) / C is below min_free percent, grow to the smallest capacity whose free share is at least min_free, i.e. ceil(L * 100 / (100 - min_free)), never shrinking and never above max_heap; if the free share exceeds max_free percent, compute ceil(L * 100 / (100 - max_free)) floored at min_heap and move shrink_pct percent of the way from C toward it (integer arithmetic). Otherwise keep C. Return the capacity after each collection.","evaluation_group":"w2-garbage-collector-invariants-heap-resizing-policy","failed_approach":"Measuring free space relative to the live bytes understates the shortage.","family":"w2-garbage-collector-invariants-heap-resizing-policy-free-share-comparison","id":"FA-90836","implementations":{"attempt":{"sha256":"bb0728481a3df23b149598a6b89fc518065b92d874ee878d209afcebbd2ef15f","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(lives, cap0, min_heap, max_heap, min_free, max_free, shrink_pct):\n    cap = cap0\n    out = []\n    for live in lives:\n        free = cap - live\n        if free * 100 < min_free * live:\n            want = -(-live * 100 // (100 - min_free))\n            cap = min(max(want, cap), max_heap)\n        elif free * 100 > max_free * cap:\n            want = -(-live * 100 // (100 - max_free))\n            want = max(want, min_heap)\n            cap = cap - (cap - want) * shrink_pct // 100\n        out.append(cap)\n    return out\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\ncases = [[('regression: grow, hold and shrink',\n   ([150, 150, 61, 20], 200, 100, 1000, 40, 70, 50),\n   [250, 250, 227, 164]),\n  ('growth target rounds up', ([102], 150, 100, 1000, 40, 70, 50), [170]),\n  ('growth clamped at the maximum heap', ([701, 900], 800, 100, 1000, 40, 70, 50), [1000, 1000]),\n  ('shrinking stops at the minimum heap', ([11, 10, 10], 400, 150, 1000, 40, 70, 50), [275, 213, 182]),\n  ('shrink moves part of the way', ([31], 600, 100, 1000, 40, 70, 25), [476]),\n  ('free ratio exactly at the minimum', ([120, 181], 200, 100, 1000, 40, 70, 50), [200, 302]),\n  ('control: within the band', ([101], 200, 100, 1000, 40, 70, 50), [200])],\n [('regression: grow, hold and shrink',\n   ([150, 150, 62, 20], 200, 100, 1000, 40, 70, 50),\n   [250, 250, 229, 165]),\n  ('growth target rounds up', ([103], 150, 100, 1000, 40, 70, 50), [172]),\n  ('growth clamped at the maximum heap', ([702, 900], 800, 100, 1000, 40, 70, 50), [1000, 1000]),\n  ('shrinking stops at the minimum heap', ([12, 10, 10], 400, 150, 1000, 40, 70, 50), [275, 213, 182]),\n  ('shrink moves part of the way', ([32], 600, 100, 1000, 40, 70, 25), [477]),\n  ('free ratio exactly at the minimum', ([120, 182], 200, 100, 1000, 40, 70, 50), [200, 304]),\n  ('control: within the band', ([102], 200, 100, 1000, 40, 70, 50), [200])],\n [('regression: grow, hold and shrink',\n   ([150, 150, 63, 20], 200, 100, 1000, 40, 70, 50),\n   [250, 250, 230, 165]),\n  ('growth target rounds up', ([104], 150, 100, 1000, 40, 70, 50), [174]),\n  ('growth clamped at the maximum heap', ([703, 900], 800, 100, 1000, 40, 70, 50), [1000, 1000]),\n  ('shrinking stops at the minimum heap', ([13, 10, 10], 400, 150, 1000, 40, 70, 50), [275, 213, 182]),\n  ('shrink moves part of the way', ([33], 600, 100, 1000, 40, 70, 25), [478]),\n  ('free ratio exactly at the minimum', ([120, 183], 200, 100, 1000, 40, 70, 50), [200, 305]),\n  ('control: within the band', ([103], 200, 100, 1000, 40, 70, 50), [200])],\n [('regression: grow, hold and shrink',\n   ([150, 150, 64, 20], 200, 100, 1000, 40, 70, 50),\n   [250, 250, 232, 166]),\n  ('growth target rounds up', ([105], 150, 100, 1000, 40, 70, 50), [175]),\n  ('growth clamped at the maximum heap', ([704, 900], 800, 100, 1000, 40, 70, 50), [1000, 1000]),\n  ('shrinking stops at the minimum heap', ([14, 10, 10], 400, 150, 1000, 40, 70, 50), [275, 213, 182]),\n  ('shrink moves part of the way', ([34], 600, 100, 1000, 40, 70, 25), [479]),\n  ('free ratio exactly at the minimum', ([120, 184], 200, 100, 1000, 40, 70, 50), [200, 307]),\n  ('control: within the band', ([104], 200, 100, 1000, 40, 70, 50), [200])],\n [('regression: grow, hold and shrink',\n   ([150, 150, 65, 20], 200, 100, 1000, 40, 70, 50),\n   [250, 250, 234, 167]),\n  ('growth target rounds up', ([106], 150, 100, 1000, 40, 70, 50), [177]),\n  ('growth clamped at the maximum heap', ([705, 900], 800, 100, 1000, 40, 70, 50), [1000, 1000]),\n  ('shrinking stops at the minimum heap', ([15, 10, 10], 400, 150, 1000, 40, 70, 50), [275, 213, 182]),\n  ('shrink moves part of the way', ([35], 600, 100, 1000, 40, 70, 25), [480]),\n  ('free ratio exactly at the minimum', ([120, 185], 200, 100, 1000, 40, 70, 50), [200, 309]),\n  ('control: within the band', ([105], 200, 100, 1000, 40, 70, 50), [200])]]\nfor label, args, expected in cases[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":"eec7348bea52aed59ad4330cbf688723c44726d09abec69d67b2c2dfdb72d16e","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(lives, cap0, min_heap, max_heap, min_free, max_free, shrink_pct):\n    cap = cap0\n    out = []\n    for live in lives:\n        free = cap - live\n        if free // cap * 100 < min_free:\n            want = -(-live * 100 // (100 - min_free))\n            cap = min(max(want, cap), max_heap)\n        elif free * 100 > max_free * cap:\n            want = -(-live * 100 // (100 - max_free))\n            want = max(want, min_heap)\n            cap = cap - (cap - want) * shrink_pct // 100\n        out.append(cap)\n    return out\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\ncases = [[('regression: grow, hold and shrink',\n   ([150, 150, 61, 20], 200, 100, 1000, 40, 70, 50),\n   [250, 250, 227, 164]),\n  ('growth target rounds up', ([102], 150, 100, 1000, 40, 70, 50), [170]),\n  ('growth clamped at the maximum heap', ([701, 900], 800, 100, 1000, 40, 70, 50), [1000, 1000]),\n  ('shrinking stops at the minimum heap', ([11, 10, 10], 400, 150, 1000, 40, 70, 50), [275, 213, 182]),\n  ('shrink moves part of the way', ([31], 600, 100, 1000, 40, 70, 25), [476]),\n  ('free ratio exactly at the minimum', ([120, 181], 200, 100, 1000, 40, 70, 50), [200, 302]),\n  ('control: within the band', ([101], 200, 100, 1000, 40, 70, 50), [200])],\n [('regression: grow, hold and shrink',\n   ([150, 150, 62, 20], 200, 100, 1000, 40, 70, 50),\n   [250, 250, 229, 165]),\n  ('growth target rounds up', ([103], 150, 100, 1000, 40, 70, 50), [172]),\n  ('growth clamped at the maximum heap', ([702, 900], 800, 100, 1000, 40, 70, 50), [1000, 1000]),\n  ('shrinking stops at the minimum heap', ([12, 10, 10], 400, 150, 1000, 40, 70, 50), [275, 213, 182]),\n  ('shrink moves part of the way', ([32], 600, 100, 1000, 40, 70, 25), [477]),\n  ('free ratio exactly at the minimum', ([120, 182], 200, 100, 1000, 40, 70, 50), [200, 304]),\n  ('control: within the band', ([102], 200, 100, 1000, 40, 70, 50), [200])],\n [('regression: grow, hold and shrink',\n   ([150, 150, 63, 20], 200, 100, 1000, 40, 70, 50),\n   [250, 250, 230, 165]),\n  ('growth target rounds up', ([104], 150, 100, 1000, 40, 70, 50), [174]),\n  ('growth clamped at the maximum heap', ([703, 900], 800, 100, 1000, 40, 70, 50), [1000, 1000]),\n  ('shrinking stops at the minimum heap', ([13, 10, 10], 400, 150, 1000, 40, 70, 50), [275, 213, 182]),\n  ('shrink moves part of the way', ([33], 600, 100, 1000, 40, 70, 25), [478]),\n  ('free ratio exactly at the minimum', ([120, 183], 200, 100, 1000, 40, 70, 50), [200, 305]),\n  ('control: within the band', ([103], 200, 100, 1000, 40, 70, 50), [200])],\n [('regression: grow, hold and shrink',\n   ([150, 150, 64, 20], 200, 100, 1000, 40, 70, 50),\n   [250, 250, 232, 166]),\n  ('growth target rounds up', ([105], 150, 100, 1000, 40, 70, 50), [175]),\n  ('growth clamped at the maximum heap', ([704, 900], 800, 100, 1000, 40, 70, 50), [1000, 1000]),\n  ('shrinking stops at the minimum heap', ([14, 10, 10], 400, 150, 1000, 40, 70, 50), [275, 213, 182]),\n  ('shrink moves part of the way', ([34], 600, 100, 1000, 40, 70, 25), [479]),\n  ('free ratio exactly at the minimum', ([120, 184], 200, 100, 1000, 40, 70, 50), [200, 307]),\n  ('control: within the band', ([104], 200, 100, 1000, 40, 70, 50), [200])],\n [('regression: grow, hold and shrink',\n   ([150, 150, 65, 20], 200, 100, 1000, 40, 70, 50),\n   [250, 250, 234, 167]),\n  ('growth target rounds up', ([106], 150, 100, 1000, 40, 70, 50), [177]),\n  ('growth clamped at the maximum heap', ([705, 900], 800, 100, 1000, 40, 70, 50), [1000, 1000]),\n  ('shrinking stops at the minimum heap', ([15, 10, 10], 400, 150, 1000, 40, 70, 50), [275, 213, 182]),\n  ('shrink moves part of the way', ([35], 600, 100, 1000, 40, 70, 25), [480]),\n  ('free ratio exactly at the minimum', ([120, 185], 200, 100, 1000, 40, 70, 50), [200, 309]),\n  ('control: within the band', ([105], 200, 100, 1000, 40, 70, 50), [200])]]\nfor label, args, expected in cases[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":"fd89ff53c5c2b06e6a4b623cc9dcce1577997d25a8f653da92d09555431b27ee","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(lives, cap0, min_heap, max_heap, min_free, max_free, shrink_pct):\n    cap = cap0\n    out = []\n    for live in lives:\n        free = cap - live\n        if free * 100 < min_free * cap:\n            want = -(-live * 100 // (100 - min_free))\n            cap = min(max(want, cap), max_heap)\n        elif free * 100 > max_free * cap:\n            want = -(-live * 100 // (100 - max_free))\n            want = max(want, min_heap)\n            cap = cap - (cap - want) * shrink_pct // 100\n        out.append(cap)\n    return out\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\ncases = [[('regression: grow, hold and shrink',\n   ([150, 150, 61, 20], 200, 100, 1000, 40, 70, 50),\n   [250, 250, 227, 164]),\n  ('growth target rounds up', ([102], 150, 100, 1000, 40, 70, 50), [170]),\n  ('growth clamped at the maximum heap', ([701, 900], 800, 100, 1000, 40, 70, 50), [1000, 1000]),\n  ('shrinking stops at the minimum heap', ([11, 10, 10], 400, 150, 1000, 40, 70, 50), [275, 213, 182]),\n  ('shrink moves part of the way', ([31], 600, 100, 1000, 40, 70, 25), [476]),\n  ('free ratio exactly at the minimum', ([120, 181], 200, 100, 1000, 40, 70, 50), [200, 302]),\n  ('control: within the band', ([101], 200, 100, 1000, 40, 70, 50), [200])],\n [('regression: grow, hold and shrink',\n   ([150, 150, 62, 20], 200, 100, 1000, 40, 70, 50),\n   [250, 250, 229, 165]),\n  ('growth target rounds up', ([103], 150, 100, 1000, 40, 70, 50), [172]),\n  ('growth clamped at the maximum heap', ([702, 900], 800, 100, 1000, 40, 70, 50), [1000, 1000]),\n  ('shrinking stops at the minimum heap', ([12, 10, 10], 400, 150, 1000, 40, 70, 50), [275, 213, 182]),\n  ('shrink moves part of the way', ([32], 600, 100, 1000, 40, 70, 25), [477]),\n  ('free ratio exactly at the minimum', ([120, 182], 200, 100, 1000, 40, 70, 50), [200, 304]),\n  ('control: within the band', ([102], 200, 100, 1000, 40, 70, 50), [200])],\n [('regression: grow, hold and shrink',\n   ([150, 150, 63, 20], 200, 100, 1000, 40, 70, 50),\n   [250, 250, 230, 165]),\n  ('growth target rounds up', ([104], 150, 100, 1000, 40, 70, 50), [174]),\n  ('growth clamped at the maximum heap', ([703, 900], 800, 100, 1000, 40, 70, 50), [1000, 1000]),\n  ('shrinking stops at the minimum heap', ([13, 10, 10], 400, 150, 1000, 40, 70, 50), [275, 213, 182]),\n  ('shrink moves part of the way', ([33], 600, 100, 1000, 40, 70, 25), [478]),\n  ('free ratio exactly at the minimum', ([120, 183], 200, 100, 1000, 40, 70, 50), [200, 305]),\n  ('control: within the band', ([103], 200, 100, 1000, 40, 70, 50), [200])],\n [('regression: grow, hold and shrink',\n   ([150, 150, 64, 20], 200, 100, 1000, 40, 70, 50),\n   [250, 250, 232, 166]),\n  ('growth target rounds up', ([105], 150, 100, 1000, 40, 70, 50), [175]),\n  ('growth clamped at the maximum heap', ([704, 900], 800, 100, 1000, 40, 70, 50), [1000, 1000]),\n  ('shrinking stops at the minimum heap', ([14, 10, 10], 400, 150, 1000, 40, 70, 50), [275, 213, 182]),\n  ('shrink moves part of the way', ([34], 600, 100, 1000, 40, 70, 25), [479]),\n  ('free ratio exactly at the minimum', ([120, 184], 200, 100, 1000, 40, 70, 50), [200, 307]),\n  ('control: within the band', ([104], 200, 100, 1000, 40, 70, 50), [200])],\n [('regression: grow, hold and shrink',\n   ([150, 150, 65, 20], 200, 100, 1000, 40, 70, 50),\n   [250, 250, 234, 167]),\n  ('growth target rounds up', ([106], 150, 100, 1000, 40, 70, 50), [177]),\n  ('growth clamped at the maximum heap', ([705, 900], 800, 100, 1000, 40, 70, 50), [1000, 1000]),\n  ('shrinking stops at the minimum heap', ([15, 10, 10], 400, 150, 1000, 40, 70, 50), [275, 213, 182]),\n  ('shrink moves part of the way', ([35], 600, 100, 1000, 40, 70, 25), [480]),\n  ('free ratio exactly at the minimum', ([120, 185], 200, 100, 1000, 40, 70, 50), [200, 309]),\n  ('control: within the band', ([105], 200, 100, 1000, 40, 70, 50), [200])]]\nfor label, args, expected in cases[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":"A deterministic, bounded teaching model of one garbage-collector mechanism with stipulated rules; it is not a production collector and claims no conformance to any particular runtime. 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-garbage-collector-invariants-heap-resizing-policy-free-share-comparison","generated_at":"2026-09-29T14:51:30.374533+00:00","license":"CC0-1.0","python":"3.12.14","seed":1,"split":"open-access"},"relevance":"Heap sizing policies decide footprint and GC frequency; rounding and clamping errors oscillate or overshoot.","repair":"Compare free * 100 with min_free * cap.","root_cause":"free // cap is evaluated first and is 0 whenever free < cap.","sha256":"2e7d0ecefa69ef298f204d5333820aed828bacd3befd2da0411b9cb936a4a775","title":"Heap resizing: free share truncated to zero · case 01","variant":1,"variant_policy":"Five numbered records share a model and may reuse boundary fixtures.","verification":{"attempt":{"elapsed_ms":38.82,"exit_code":1,"observations":[{"actual":[250,250,227,164],"check":"regression: grow, hold and shrink","expected":[250,250,227,164],"passed":true},{"actual":[150],"check":"growth target rounds up","expected":[170],"passed":false},{"actual":[1000,1000],"check":"growth clamped at the maximum heap","expected":[1000,1000],"passed":true},{"actual":[275,213,182],"check":"shrinking stops at the minimum heap","expected":[275,213,182],"passed":true},{"actual":[476],"check":"shrink moves part of the way","expected":[476],"passed":true},{"actual":[200,302],"check":"free ratio exactly at the minimum","expected":[200,302],"passed":true},{"actual":[200],"check":"control: within the band","expected":[200],"passed":true}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"regression: grow, hold and shrink\", \"actual\": [250, 250, 227, 164], \"expected\": [250, 250, 227, 164], \"passed\": true}, {\"check\": \"growth target rounds up\", \"actual\": [150], \"expected\": [170], \"passed\": false}, {\"check\": \"growth clamped at the maximum heap\", \"actual\": [1000, 1000], \"expected\": [1000, 1000], \"passed\": true}, {\"check\": \"shrinking stops at the minimum heap\", \"actual\": [275, 213, 182], \"expected\": [275, 213, 182], \"passed\": true}, {\"check\": \"shrink moves part of the way\", \"actual\": [476], \"expected\": [476], \"passed\": true}, {\"check\": \"free ratio exactly at the minimum\", \"actual\": [200, 302], \"expected\": [200, 302], \"passed\": true}, {\"check\": \"control: within the band\", \"actual\": [200], \"expected\": [200], \"passed\": true}], \"passed\": false}\n"},"broken":{"elapsed_ms":38.447,"exit_code":1,"observations":[{"actual":[250,250,250,250],"check":"regression: grow, hold and shrink","expected":[250,250,227,164],"passed":false},{"actual":[170],"check":"growth target rounds up","expected":[170],"passed":true},{"actual":[1000,1000],"check":"growth clamped at the maximum heap","expected":[1000,1000],"passed":true},{"actual":[400,400,400],"check":"shrinking stops at the minimum heap","expected":[275,213,182],"passed":false},{"actual":[600],"check":"shrink moves part of the way","expected":[476],"passed":false},{"actual":[200,302],"check":"free ratio exactly at the minimum","expected":[200,302],"passed":true},{"actual":[200],"check":"control: within the band","expected":[200],"passed":true}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"regression: grow, hold and shrink\", \"actual\": [250, 250, 250, 250], \"expected\": [250, 250, 227, 164], \"passed\": false}, {\"check\": \"growth target rounds up\", \"actual\": [170], \"expected\": [170], \"passed\": true}, {\"check\": \"growth clamped at the maximum heap\", \"actual\": [1000, 1000], \"expected\": [1000, 1000], \"passed\": true}, {\"check\": \"shrinking stops at the minimum heap\", \"actual\": [400, 400, 400], \"expected\": [275, 213, 182], \"passed\": false}, {\"check\": \"shrink moves part of the way\", \"actual\": [600], \"expected\": [476], \"passed\": false}, {\"check\": \"free ratio exactly at the minimum\", \"actual\": [200, 302], \"expected\": [200, 302], \"passed\": true}, {\"check\": \"control: within the band\", \"actual\": [200], \"expected\": [200], \"passed\": true}], \"passed\": false}\n"},"fixed":{"elapsed_ms":37.277,"exit_code":0,"observations":[{"actual":[250,250,227,164],"check":"regression: grow, hold and shrink","expected":[250,250,227,164],"passed":true},{"actual":[170],"check":"growth target rounds up","expected":[170],"passed":true},{"actual":[1000,1000],"check":"growth clamped at the maximum heap","expected":[1000,1000],"passed":true},{"actual":[275,213,182],"check":"shrinking stops at the minimum heap","expected":[275,213,182],"passed":true},{"actual":[476],"check":"shrink moves part of the way","expected":[476],"passed":true},{"actual":[200,302],"check":"free ratio exactly at the minimum","expected":[200,302],"passed":true},{"actual":[200],"check":"control: within the band","expected":[200],"passed":true}],"passed":true,"stderr":"","stdout":"{\"observations\": [{\"check\": \"regression: grow, hold and shrink\", \"actual\": [250, 250, 227, 164], \"expected\": [250, 250, 227, 164], \"passed\": true}, {\"check\": \"growth target rounds up\", \"actual\": [170], \"expected\": [170], \"passed\": true}, {\"check\": \"growth clamped at the maximum heap\", \"actual\": [1000, 1000], \"expected\": [1000, 1000], \"passed\": true}, {\"check\": \"shrinking stops at the minimum heap\", \"actual\": [275, 213, 182], \"expected\": [275, 213, 182], \"passed\": true}, {\"check\": \"shrink moves part of the way\", \"actual\": [476], \"expected\": [476], \"passed\": true}, {\"check\": \"free ratio exactly at the minimum\", \"actual\": [200, 302], \"expected\": [200, 302], \"passed\": true}, {\"check\": \"control: within the band\", \"actual\": [200], \"expected\": [200], \"passed\": true}], \"passed\": true}\n"}},"verified":true,"visibility":"public"}