{
  "schema_version": 1,
  "skill": "posterly",
  "timestamp": "2026-07-20T04:51:38Z",
  "poster_html": "/tmp/repro_hector/poster.html",
  "canvas": {
    "source": "page-rule",
    "width_cm": 152.4,
    "height_cm": 91.44,
    "orientation": "landscape",
    "source_url": null
  },
  "overall": "PASS",
  "hard_failures": 0,
  "warnings": 0,
  "soft_advisories": 7,
  "gates": [
    {
      "name": "preflight",
      "severity": "hard",
      "status": "PASS",
      "command": [
        "/usr/bin/python3",
        "/tmp/posterly/tools/poster_check.py",
        "preflight",
        "/tmp/repro_hector/poster.html"
      ],
      "summary": {
        "exit_code": 0,
        "tail": "[preflight] /tmp/repro_hector/poster.html\n  problems: 0   warnings: 0\n[preflight] PASS"
      },
      "artifacts": []
    },
    {
      "name": "style",
      "severity": "hard",
      "status": "PASS",
      "command": [
        "/usr/bin/python3",
        "/tmp/posterly/tools/style_check.py",
        "/tmp/repro_hector/poster.html",
        "--disable",
        "4,5",
        "--json",
        "/tmp/repro_hector/style_check.json"
      ],
      "summary": {
        "gate": "style",
        "status": "PASS",
        "rules": [
          {
            "id": 1,
            "severity": "hard",
            "status": "PASS",
            "detail": "ok"
          },
          {
            "id": 2,
            "severity": "hard",
            "status": "PASS",
            "detail": "ok"
          },
          {
            "id": 3,
            "severity": "hard",
            "status": "PASS",
            "detail": "ok"
          },
          {
            "id": 4,
            "severity": "hard",
            "status": "SKIPPED",
            "detail": "disabled via --disable (rule 4)"
          },
          {
            "id": 5,
            "severity": "hard",
            "status": "SKIPPED",
            "detail": "disabled via --disable (rule 5)"
          },
          {
            "id": 6,
            "severity": "hard",
            "status": "PASS",
            "detail": "ok"
          },
          {
            "id": 7,
            "severity": "hard",
            "status": "PASS",
            "detail": "ok"
          },
          {
            "id": 8,
            "severity": "hard",
            "status": "PASS",
            "detail": "ok"
          },
          {
            "id": 9,
            "severity": "warn",
            "status": "PASS",
            "detail": "9 --fs-* token(s) defined"
          },
          {
            "id": 10,
            "severity": "hard",
            "status": "PASS",
            "detail": "ok"
          },
          {
            "id": 11,
            "severity": "hard",
            "status": "PASS",
            "detail": "ok"
          },
          {
            "id": 12,
            "severity": "warn",
            "status": "PASS",
            "detail": "dark area = 0.0% of poster (<= 8%)"
          },
          {
            "id": 13,
            "severity": "hard",
            "status": "PASS",
            "detail": "ok"
          },
          {
            "id": 14,
            "severity": "hard",
            "status": "PASS",
            "detail": "ok"
          }
        ]
      },
      "artifacts": [
        "/tmp/repro_hector/style_check.json"
      ]
    },
    {
      "name": "asset",
      "severity": "hard",
      "status": "NOT_RUN",
      "command": [],
      "summary": {
        "not_run": "no --manifest: real-figure provenance gate opted out (NOT verified)"
      },
      "artifacts": []
    },
    {
      "name": "measure",
      "severity": "hard",
      "status": "PASS",
      "command": [
        "/usr/bin/python3",
        "/tmp/posterly/tools/poster_check.py",
        "measure",
        "/tmp/repro_hector/poster.html"
      ],
      "summary": {
        "exit_code": 0,
        "tail": "  col0    last-card-bottom =   758.06 px\n  col1    last-card-bottom =   758.06 px\n  col2    last-card-bottom =   758.06 px\n  col3    last-card-bottom =   758.06 px\n  spread = 0.00 px   (target < 5.0 px)\n  intercard gap in [15.11 (col3), 15.11 (col3)] px   (target [12.0, 50.0])\n  gap -> footer-strip in [30.22, 30.22] px   (target [30.0, 50.0])\n[measure] PASS"
      },
      "artifacts": []
    },
    {
      "name": "polish",
      "severity": "soft",
      "status": "PASS",
      "command": [
        "/usr/bin/python3",
        "/tmp/posterly/tools/poster_check.py",
        "polish",
        "/tmp/repro_hector/poster.html"
      ],
      "summary": {
        "exit_code": 0,
        "tail": "  WARN: WIDOW: <p class='body-text'> wraps to a stranded last line that fills only 17% of the typeset width ('gradient flow.'), a runt (SKILL.md Gate B). Fix by REWORDING first: expand or trim a few words so the break lands on a phrase boundary and the last line carries more of the measure (if alignment is already tuned, swap a word for a longer synonym to keep the line count). On a CENTERED heading/title use text-wrap: balance instead. &nbsp;-glue is a LAST RESORT for a leading marker or a tight stat cell only -- glue at most two tokens; never chain more (a fused multi-word unit wraps early and tears a hole in the line above -- the GLUE-CHAIN gate flags it). Context: '...vs 18.4. 4-channel additive bias preserves gradient flow.'.\n  WARN: WIDOW: <p class='body-text'> wraps to a stranded last line that fills only 25% of the typeset width ('non-rigid deformation.'), a runt (SKILL.md Gate B). Fix by REWORDING first: expand or trim a few words so the break lands on a phrase boundary and the last line carries more of the measure (if alignment is already tuned, swap a word for a longer synonym to keep the line count). On a CENTERED heading/title use text-wrap: balance instead. &nbsp;-glue is a LAST RESORT for a leading marker or a tight stat cell only -- glue at most two tokens; never chain more (a fused multi-word unit wraps early and tears a hole in the line above -- the GLUE-CHAIN gate flags it). Context: '...ches paper's 0.192\\u21920.167. Captures non-rigid deformation.'.\n  WARN: CARD/TRAILING: card 0 fills only 89% of its height -- 34 px (11%) blank below the last line. A card stretched to align (flex:1) but padded with whitespace clears the bottom-edge gate yet reads as unfinished. Fill with real content, grow a figure, or shrink the canvas. See Gate C in SKILL.md.\n  WARN: CARD/TRAILING: card 1 fills only 75% of its height -- 80 px (25%) blank below the last line. A card stretched to align (flex:1) but padded with whitespace clears the bottom-edge gate yet reads as unfinished. Fill with real content, grow a figure, or shrink the canvas. See Gate C in SKILL.md.\n  WARN: CARD/TRAILING: card 2 fills only 75% of its height -- 80 px (25%) blank below the last line. A card stretched to align (flex:1) but padded with whitespace clears the bottom-edge gate yet reads as unfinished. Fill with real content, grow a figure, or shrink the canvas. See Gate C in SKILL.md.\n  WARN: CONTRAST: <span class='key-mark'> '\\u2605 PASS' renders #d4943a on #e6f2ef = 2.26:1 (floor 3.0:1) (+3 more run(s) of this class/color pair). The usual cause: an inline emphasis/highlight class sets a background but INHERITS its text color from a different ground -- any class that paints a background must declare its own `color`. Fix the token pairing (use the matching *-ink token), then re-render and look.\n  WARN: IDENTITY/WOVEN: no woven identity mark (data-ps-mark=\"woven\") -- add one registration-mark glyph riding EXISTING content (a best/target marker, a terminal period, an inline bullet, ...); it is the second identity layer beyond the always-on corner signature. Never let it solely carry a scientific claim (Ours/Best/target must stay readable from text or table styling).\n[polish] OK (warnings only)"
      },
      "artifacts": [],
      "advisories": 7,
      "advisory_lines": [
        "WARN: WIDOW: <p class='body-text'> wraps to a stranded last line that fills only 17% of the typeset width ('gradient flow.'), a runt (SKILL.md Gate B). Fix by REWORDING first: expand or trim a few words so the break lands on a phrase boundary and the last line carries more of the measure (if alignment is already tuned, swap a word for a longer synonym to keep the line count). On a CENTERED heading/title use text-wrap: balance instead. &nbsp;-glue is a LAST RESORT for a leading marker or a tight stat cell only -- glue at most two tokens; never chain more (a fused multi-word unit wraps early and tears a hole in the line above -- the GLUE-CHAIN gate flags it). Context: '...vs 18.4. 4-channel additive bias preserves gradient flow.'.",
        "WARN: WIDOW: <p class='body-text'> wraps to a stranded last line that fills only 25% of the typeset width ('non-rigid deformation.'), a runt (SKILL.md Gate B). Fix by REWORDING first: expand or trim a few words so the break lands on a phrase boundary and the last line carries more of the measure (if alignment is already tuned, swap a word for a longer synonym to keep the line count). On a CENTERED heading/title use text-wrap: balance instead. &nbsp;-glue is a LAST RESORT for a leading marker or a tight stat cell only -- glue at most two tokens; never chain more (a fused multi-word unit wraps early and tears a hole in the line above -- the GLUE-CHAIN gate flags it). Context: '...ches paper's 0.192\\u21920.167. Captures non-rigid deformation.'.",
        "WARN: CARD/TRAILING: card 0 fills only 89% of its height -- 34 px (11%) blank below the last line. A card stretched to align (flex:1) but padded with whitespace clears the bottom-edge gate yet reads as unfinished. Fill with real content, grow a figure, or shrink the canvas. See Gate C in SKILL.md.",
        "WARN: CARD/TRAILING: card 1 fills only 75% of its height -- 80 px (25%) blank below the last line. A card stretched to align (flex:1) but padded with whitespace clears the bottom-edge gate yet reads as unfinished. Fill with real content, grow a figure, or shrink the canvas. See Gate C in SKILL.md.",
        "WARN: CARD/TRAILING: card 2 fills only 75% of its height -- 80 px (25%) blank below the last line. A card stretched to align (flex:1) but padded with whitespace clears the bottom-edge gate yet reads as unfinished. Fill with real content, grow a figure, or shrink the canvas. See Gate C in SKILL.md.",
        "WARN: CONTRAST: <span class='key-mark'> '\\u2605 PASS' renders #d4943a on #e6f2ef = 2.26:1 (floor 3.0:1) (+3 more run(s) of this class/color pair). The usual cause: an inline emphasis/highlight class sets a background but INHERITS its text color from a different ground -- any class that paints a background must declare its own `color`. Fix the token pairing (use the matching *-ink token), then re-render and look.",
        "WARN: IDENTITY/WOVEN: no woven identity mark (data-ps-mark=\"woven\") -- add one registration-mark glyph riding EXISTING content (a best/target marker, a terminal period, an inline bullet, ...); it is the second identity layer beyond the always-on corner signature. Never let it solely carry a scientific claim (Ours/Best/target must stay readable from text or table styling)."
      ]
    }
  ]
}
