{"abstract":"Inline images of a message without an HTML body are silently dropped.","category":"Email MIME structure","checks":7,"contract":"The body is multipart/alternative(text, html) when both versions exist, the html alone when only html exists, else text. Inline images go into multipart/related with the html root first; without html they become attachments. When there are attachments the result is multipart/mixed(body, attachments...). Output is a compact string such as \"mixed(alternative(text,related(html,img)),att)\".","evaluation_group":"w2-email_mime_structure-compose-skeleton","failed_approach":"Adding a single attachment for any number of images still loses images. The attempted `atts += 1 if inline_images else 0` still disagrees with a fixture.","family":"w2-email_mime_structure-compose-skeleton-orphan-inline-images","id":"FA-76556","implementations":{"attempt":{"sha256":"31ad79c0f86ba0d3a114c436369a36c715808c22b7e3799f8c56799276b03e08","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(has_text, has_html, inline_images, attachments):\n    atts = attachments\n    html = None\n    if has_html:\n        html = 'html' if inline_images == 0 else 'related(' + ','.join(['html'] + ['img'] * inline_images) + ')'\n    else:\n        atts += 1 if inline_images else 0\n    if has_text and html:\n        body = 'alternative(text,' + html + ')'\n    elif html:\n        body = html\n    else:\n        body = 'text'\n    if atts:\n        return 'mixed(' + ','.join([body] + ['att'] * atts) + ')'\n    return body\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\n_CASES = {1: [('images without html', (False, False, 2, 0), 'mixed(text,att,att)'), ('text and html', (True, True, 0, 0), 'alternative(text,html)'), ('text html and images', (True, True, 2, 0), 'alternative(text,related(html,img,img))'), ('html images and attachment', (False, True, 1, 1), 'mixed(related(html,img),att)'), ('text and attachments', (True, False, 0, 1), 'mixed(text,att)'), ('plain text only', (True, False, 0, 0), 'text'), ('everything', (True, True, 2, 1), 'mixed(alternative(text,related(html,img,img)),att)')], 2: [('images without html', (False, False, 3, 0), 'mixed(text,att,att,att)'), ('text and html', (True, True, 0, 0), 'alternative(text,html)'), ('text html and images', (True, True, 3, 0), 'alternative(text,related(html,img,img,img))'), ('html images and attachment', (False, True, 2, 1), 'mixed(related(html,img,img),att)'), ('text and attachments', (True, False, 0, 2), 'mixed(text,att,att)'), ('plain text only', (True, False, 0, 0), 'text'), ('everything', (True, True, 2, 2), 'mixed(alternative(text,related(html,img,img)),att,att)')], 3: [('images without html', (False, False, 4, 0), 'mixed(text,att,att,att,att)'), ('text and html', (True, True, 0, 0), 'alternative(text,html)'), ('text html and images', (True, True, 4, 0), 'alternative(text,related(html,img,img,img,img))'), ('html images and attachment', (False, True, 3, 1), 'mixed(related(html,img,img,img),att)'), ('text and attachments', (True, False, 0, 3), 'mixed(text,att,att,att)'), ('plain text only', (True, False, 0, 0), 'text'), ('everything', (True, True, 2, 3), 'mixed(alternative(text,related(html,img,img)),att,att,att)')], 4: [('images without html', (False, False, 5, 0), 'mixed(text,att,att,att,att,att)'), ('text and html', (True, True, 0, 0), 'alternative(text,html)'), ('text html and images', (True, True, 5, 0), 'alternative(text,related(html,img,img,img,img,img))'), ('html images and attachment', (False, True, 4, 1), 'mixed(related(html,img,img,img,img),att)'), ('text and attachments', (True, False, 0, 4), 'mixed(text,att,att,att,att)'), ('plain text only', (True, False, 0, 0), 'text'), ('everything', (True, True, 2, 4), 'mixed(alternative(text,related(html,img,img)),att,att,att,att)')], 5: [('images without html', (False, False, 6, 0), 'mixed(text,att,att,att,att,att,att)'), ('text and html', (True, True, 0, 0), 'alternative(text,html)'), ('text html and images', (True, True, 6, 0), 'alternative(text,related(html,img,img,img,img,img,img))'), ('html images and attachment', (False, True, 5, 1), 'mixed(related(html,img,img,img,img,img),att)'), ('text and attachments', (True, False, 0, 5), 'mixed(text,att,att,att,att,att)'), ('plain text only', (True, False, 0, 0), 'text'), ('everything', (True, True, 2, 5), 'mixed(alternative(text,related(html,img,img)),att,att,att,att,att)')]}\nfor _label, _args, _expected in _CASES[N]:\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":"1d91c87266bcaefdc7f4d4771e47e72ecb8fc5d6ef3a5971b122af08fe2ddf17","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(has_text, has_html, inline_images, attachments):\n    atts = attachments\n    html = None\n    if has_html:\n        html = 'html' if inline_images == 0 else 'related(' + ','.join(['html'] + ['img'] * inline_images) + ')'\n    else:\n        atts = atts\n    if has_text and html:\n        body = 'alternative(text,' + html + ')'\n    elif html:\n        body = html\n    else:\n        body = 'text'\n    if atts:\n        return 'mixed(' + ','.join([body] + ['att'] * atts) + ')'\n    return body\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\n_CASES = {1: [('images without html', (False, False, 2, 0), 'mixed(text,att,att)'), ('text and html', (True, True, 0, 0), 'alternative(text,html)'), ('text html and images', (True, True, 2, 0), 'alternative(text,related(html,img,img))'), ('html images and attachment', (False, True, 1, 1), 'mixed(related(html,img),att)'), ('text and attachments', (True, False, 0, 1), 'mixed(text,att)'), ('plain text only', (True, False, 0, 0), 'text'), ('everything', (True, True, 2, 1), 'mixed(alternative(text,related(html,img,img)),att)')], 2: [('images without html', (False, False, 3, 0), 'mixed(text,att,att,att)'), ('text and html', (True, True, 0, 0), 'alternative(text,html)'), ('text html and images', (True, True, 3, 0), 'alternative(text,related(html,img,img,img))'), ('html images and attachment', (False, True, 2, 1), 'mixed(related(html,img,img),att)'), ('text and attachments', (True, False, 0, 2), 'mixed(text,att,att)'), ('plain text only', (True, False, 0, 0), 'text'), ('everything', (True, True, 2, 2), 'mixed(alternative(text,related(html,img,img)),att,att)')], 3: [('images without html', (False, False, 4, 0), 'mixed(text,att,att,att,att)'), ('text and html', (True, True, 0, 0), 'alternative(text,html)'), ('text html and images', (True, True, 4, 0), 'alternative(text,related(html,img,img,img,img))'), ('html images and attachment', (False, True, 3, 1), 'mixed(related(html,img,img,img),att)'), ('text and attachments', (True, False, 0, 3), 'mixed(text,att,att,att)'), ('plain text only', (True, False, 0, 0), 'text'), ('everything', (True, True, 2, 3), 'mixed(alternative(text,related(html,img,img)),att,att,att)')], 4: [('images without html', (False, False, 5, 0), 'mixed(text,att,att,att,att,att)'), ('text and html', (True, True, 0, 0), 'alternative(text,html)'), ('text html and images', (True, True, 5, 0), 'alternative(text,related(html,img,img,img,img,img))'), ('html images and attachment', (False, True, 4, 1), 'mixed(related(html,img,img,img,img),att)'), ('text and attachments', (True, False, 0, 4), 'mixed(text,att,att,att,att)'), ('plain text only', (True, False, 0, 0), 'text'), ('everything', (True, True, 2, 4), 'mixed(alternative(text,related(html,img,img)),att,att,att,att)')], 5: [('images without html', (False, False, 6, 0), 'mixed(text,att,att,att,att,att,att)'), ('text and html', (True, True, 0, 0), 'alternative(text,html)'), ('text html and images', (True, True, 6, 0), 'alternative(text,related(html,img,img,img,img,img,img))'), ('html images and attachment', (False, True, 5, 1), 'mixed(related(html,img,img,img,img,img),att)'), ('text and attachments', (True, False, 0, 5), 'mixed(text,att,att,att,att,att)'), ('plain text only', (True, False, 0, 0), 'text'), ('everything', (True, True, 2, 5), 'mixed(alternative(text,related(html,img,img)),att,att,att,att,att)')]}\nfor _label, _args, _expected in _CASES[N]:\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":"ec74f87d73b4fa1010c8151d39edf169ac8f01d74a67260bb62559e9e13dab15","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(has_text, has_html, inline_images, attachments):\n    atts = attachments\n    html = None\n    if has_html:\n        html = 'html' if inline_images == 0 else 'related(' + ','.join(['html'] + ['img'] * inline_images) + ')'\n    else:\n        atts += inline_images\n    if has_text and html:\n        body = 'alternative(text,' + html + ')'\n    elif html:\n        body = html\n    else:\n        body = 'text'\n    if atts:\n        return 'mixed(' + ','.join([body] + ['att'] * atts) + ')'\n    return body\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\n_CASES = {1: [('images without html', (False, False, 2, 0), 'mixed(text,att,att)'), ('text and html', (True, True, 0, 0), 'alternative(text,html)'), ('text html and images', (True, True, 2, 0), 'alternative(text,related(html,img,img))'), ('html images and attachment', (False, True, 1, 1), 'mixed(related(html,img),att)'), ('text and attachments', (True, False, 0, 1), 'mixed(text,att)'), ('plain text only', (True, False, 0, 0), 'text'), ('everything', (True, True, 2, 1), 'mixed(alternative(text,related(html,img,img)),att)')], 2: [('images without html', (False, False, 3, 0), 'mixed(text,att,att,att)'), ('text and html', (True, True, 0, 0), 'alternative(text,html)'), ('text html and images', (True, True, 3, 0), 'alternative(text,related(html,img,img,img))'), ('html images and attachment', (False, True, 2, 1), 'mixed(related(html,img,img),att)'), ('text and attachments', (True, False, 0, 2), 'mixed(text,att,att)'), ('plain text only', (True, False, 0, 0), 'text'), ('everything', (True, True, 2, 2), 'mixed(alternative(text,related(html,img,img)),att,att)')], 3: [('images without html', (False, False, 4, 0), 'mixed(text,att,att,att,att)'), ('text and html', (True, True, 0, 0), 'alternative(text,html)'), ('text html and images', (True, True, 4, 0), 'alternative(text,related(html,img,img,img,img))'), ('html images and attachment', (False, True, 3, 1), 'mixed(related(html,img,img,img),att)'), ('text and attachments', (True, False, 0, 3), 'mixed(text,att,att,att)'), ('plain text only', (True, False, 0, 0), 'text'), ('everything', (True, True, 2, 3), 'mixed(alternative(text,related(html,img,img)),att,att,att)')], 4: [('images without html', (False, False, 5, 0), 'mixed(text,att,att,att,att,att)'), ('text and html', (True, True, 0, 0), 'alternative(text,html)'), ('text html and images', (True, True, 5, 0), 'alternative(text,related(html,img,img,img,img,img))'), ('html images and attachment', (False, True, 4, 1), 'mixed(related(html,img,img,img,img),att)'), ('text and attachments', (True, False, 0, 4), 'mixed(text,att,att,att,att)'), ('plain text only', (True, False, 0, 0), 'text'), ('everything', (True, True, 2, 4), 'mixed(alternative(text,related(html,img,img)),att,att,att,att)')], 5: [('images without html', (False, False, 6, 0), 'mixed(text,att,att,att,att,att,att)'), ('text and html', (True, True, 0, 0), 'alternative(text,html)'), ('text html and images', (True, True, 6, 0), 'alternative(text,related(html,img,img,img,img,img,img))'), ('html images and attachment', (False, True, 5, 1), 'mixed(related(html,img,img,img,img,img),att)'), ('text and attachments', (True, False, 0, 5), 'mixed(text,att,att,att,att,att)'), ('plain text only', (True, False, 0, 0), 'text'), ('everything', (True, True, 2, 5), 'mixed(alternative(text,related(html,img,img)),att,att,att,att,att)')]}\nfor _label, _args, _expected in _CASES[N]:\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 offline model over pre-parsed MIME dictionaries; not a conforming MIME parser, generator or mail client. 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-email_mime_structure-compose-skeleton-orphan-inline-images","generated_at":"2026-09-29T14:49:17.372631+00:00","license":"CC0-1.0","python":"3.12.14","seed":1,"split":"open-access"},"relevance":"Composing the wrong skeleton makes clients show images as attachments, hide the plain-text version or drop parts.","repair":"Use `atts += inline_images` for the orphan inline images decision and keep every other rule of the model unchanged.","root_cause":"The orphan inline images decision evaluates `atts = atts` where the contract requires `atts += inline_images`.","sha256":"a7fb50299fe5730089e208156e5d360c940f5051fce251d9f12e161ca46f011c","title":"Choose the MIME skeleton for an outgoing message: orphan inline images · case 01","variant":1,"variant_policy":"N selects a different enumerated fixture set (renamed identifiers, part counts and sizes); boundary fixtures recur across variants.","verification":{"attempt":{"elapsed_ms":38.825,"exit_code":1,"observations":[{"actual":"mixed(text,att)","check":"images without html","expected":"mixed(text,att,att)","passed":false},{"actual":"alternative(text,html)","check":"text and html","expected":"alternative(text,html)","passed":true},{"actual":"alternative(text,related(html,img,img))","check":"text html and images","expected":"alternative(text,related(html,img,img))","passed":true},{"actual":"mixed(related(html,img),att)","check":"html images and attachment","expected":"mixed(related(html,img),att)","passed":true},{"actual":"mixed(text,att)","check":"text and attachments","expected":"mixed(text,att)","passed":true},{"actual":"text","check":"plain text only","expected":"text","passed":true},{"actual":"mixed(alternative(text,related(html,img,img)),att)","check":"everything","expected":"mixed(alternative(text,related(html,img,img)),att)","passed":true}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"images without html\", \"actual\": \"mixed(text,att)\", \"expected\": \"mixed(text,att,att)\", \"passed\": false}, {\"check\": \"text and html\", \"actual\": \"alternative(text,html)\", \"expected\": \"alternative(text,html)\", \"passed\": true}, {\"check\": \"text html and images\", \"actual\": \"alternative(text,related(html,img,img))\", \"expected\": \"alternative(text,related(html,img,img))\", \"passed\": true}, {\"check\": \"html images and attachment\", \"actual\": \"mixed(related(html,img),att)\", \"expected\": \"mixed(related(html,img),att)\", \"passed\": true}, {\"check\": \"text and attachments\", \"actual\": \"mixed(text,att)\", \"expected\": \"mixed(text,att)\", \"passed\": true}, {\"check\": \"plain text only\", \"actual\": \"text\", \"expected\": \"text\", \"passed\": true}, {\"check\": \"everything\", \"actual\": \"mixed(alternative(text,related(html,img,img)),att)\", \"expected\": \"mixed(alternative(text,related(html,img,img)),att)\", \"passed\": true}], \"passed\": false}\n"},"broken":{"elapsed_ms":42.099,"exit_code":1,"observations":[{"actual":"text","check":"images without html","expected":"mixed(text,att,att)","passed":false},{"actual":"alternative(text,html)","check":"text and html","expected":"alternative(text,html)","passed":true},{"actual":"alternative(text,related(html,img,img))","check":"text html and images","expected":"alternative(text,related(html,img,img))","passed":true},{"actual":"mixed(related(html,img),att)","check":"html images and attachment","expected":"mixed(related(html,img),att)","passed":true},{"actual":"mixed(text,att)","check":"text and attachments","expected":"mixed(text,att)","passed":true},{"actual":"text","check":"plain text only","expected":"text","passed":true},{"actual":"mixed(alternative(text,related(html,img,img)),att)","check":"everything","expected":"mixed(alternative(text,related(html,img,img)),att)","passed":true}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"images without html\", \"actual\": \"text\", \"expected\": \"mixed(text,att,att)\", \"passed\": false}, {\"check\": \"text and html\", \"actual\": \"alternative(text,html)\", \"expected\": \"alternative(text,html)\", \"passed\": true}, {\"check\": \"text html and images\", \"actual\": \"alternative(text,related(html,img,img))\", \"expected\": \"alternative(text,related(html,img,img))\", \"passed\": true}, {\"check\": \"html images and attachment\", \"actual\": \"mixed(related(html,img),att)\", \"expected\": \"mixed(related(html,img),att)\", \"passed\": true}, {\"check\": \"text and attachments\", \"actual\": \"mixed(text,att)\", \"expected\": \"mixed(text,att)\", \"passed\": true}, {\"check\": \"plain text only\", \"actual\": \"text\", \"expected\": \"text\", \"passed\": true}, {\"check\": \"everything\", \"actual\": \"mixed(alternative(text,related(html,img,img)),att)\", \"expected\": \"mixed(alternative(text,related(html,img,img)),att)\", \"passed\": true}], \"passed\": false}\n"},"fixed":{"elapsed_ms":39.874,"exit_code":0,"observations":[{"actual":"mixed(text,att,att)","check":"images without html","expected":"mixed(text,att,att)","passed":true},{"actual":"alternative(text,html)","check":"text and html","expected":"alternative(text,html)","passed":true},{"actual":"alternative(text,related(html,img,img))","check":"text html and images","expected":"alternative(text,related(html,img,img))","passed":true},{"actual":"mixed(related(html,img),att)","check":"html images and attachment","expected":"mixed(related(html,img),att)","passed":true},{"actual":"mixed(text,att)","check":"text and attachments","expected":"mixed(text,att)","passed":true},{"actual":"text","check":"plain text only","expected":"text","passed":true},{"actual":"mixed(alternative(text,related(html,img,img)),att)","check":"everything","expected":"mixed(alternative(text,related(html,img,img)),att)","passed":true}],"passed":true,"stderr":"","stdout":"{\"observations\": [{\"check\": \"images without html\", \"actual\": \"mixed(text,att,att)\", \"expected\": \"mixed(text,att,att)\", \"passed\": true}, {\"check\": \"text and html\", \"actual\": \"alternative(text,html)\", \"expected\": \"alternative(text,html)\", \"passed\": true}, {\"check\": \"text html and images\", \"actual\": \"alternative(text,related(html,img,img))\", \"expected\": \"alternative(text,related(html,img,img))\", \"passed\": true}, {\"check\": \"html images and attachment\", \"actual\": \"mixed(related(html,img),att)\", \"expected\": \"mixed(related(html,img),att)\", \"passed\": true}, {\"check\": \"text and attachments\", \"actual\": \"mixed(text,att)\", \"expected\": \"mixed(text,att)\", \"passed\": true}, {\"check\": \"plain text only\", \"actual\": \"text\", \"expected\": \"text\", \"passed\": true}, {\"check\": \"everything\", \"actual\": \"mixed(alternative(text,related(html,img,img)),att)\", \"expected\": \"mixed(alternative(text,related(html,img,img)),att)\", \"passed\": true}], \"passed\": true}\n"}},"verified":true,"visibility":"public"}