Publishing & Deployment Issues May 24, 2026

BUILD_RECEIPT channel_label_match False When itch HTML5 Added as Third Channel - How to Fix

Fix BUILD_RECEIPT channel_label_match false for itch plus GX.games plus Steam HTML5. VERSION file, itch_html5_upload_receipt_v1.json, triple_channel_label_receipt_v1.json, playtest scope map surfaces, July 2026 multi-channel gates.

By GamineAI Team

BUILD_RECEIPT channel_label_match False When itch HTML5 Added as Third Channel — How to Fix

Problem: CI is green for Steam + GX.gamesgx_html5_upload_receipt_v1.json and build_label_smoke_receipt_v1.json both show matching labels. You add itch.io HTML5 as a third public surface and channel_label_match flips to false on BUILD_RECEIPT even though each channel “looks fine” in isolation.

Who is affected now: July 2026 HTML5-first teams running itch + GX + Steam per the HTML5 second storefront analysis. You fixed GX receipt vs Steam build_label and itch CDN WASM MIME—this article is triple-channel normalization, not MIME-only or pairwise Steam/GX drift alone.

Fastest safe fix: One repo-root VERSION string → map itch build_label from that file (not raw itch game ID) → add itch_html5 row to playtest_scope_map_v1.json → upload all three from same git_sha → file triple_channel_label_receipt_v1.json with normalized compare → set BUILD_RECEIPT channel_label_match: true only when Steam, GX, and itch rows pass → include itch column in Wednesday smoke.

Direct answer

channel_label_match is a cross-channel boolean—it fails when any surface’s logged label differs from VERSION after normalization (trim, case fold for compare only, never change player-visible casing). itch often logs 1234567 (numeric game id) or MyGame slug while Steam shows fest-demo-2026-05-24-rc2—pairwise GX+Steam scripts never compared itch, so the third row exposes the gap.

Why this issue spikes in July 2026

  1. Triple HTML5 surfaces — itch for jam/fest links, GX for discovery, Steam for wishlist—three upload rituals, one tired producer.
  2. Pairwise CI — Pipelines written when only Steam+GX existed; itch job added without extending diff gate.
  3. itch field names — Dashboard “Version” ≠ BUILD_RECEIPT build_label; facilitators paste game URL slug.
  4. Case sensitivityFest-Demo-RC2 vs fest-demo-2026-05-24-rc2 fails strict string compare.
  5. Missing scope map rowplaytest_scope_map lists gx_public + fest_public but no itch_public → receipt aggregator marks mismatch.

Symptoms and search phrases

  • BUILD_RECEIPT: channel_label_match: false after itch upload job added.
  • Steam overlay + GX overlay match; itch page shows different build string or none.
  • itch_html5_upload_receipt missing from release-evidence/itch/.
  • CI: Steam job + GX job green; itch job green but no label diff step.
  • itch URL uses ?v=2 cache bust; Steam still rc1.
  • Facilitator README lists GX + Steam only.
  • wasm_mime_receipt pass but channel row still false.

Root causes (check in order)

  1. itch receipt logs game ID, not build_label — numeric id ≠ VERSION string.
  2. No itch_public surface in scope map — aggregator defaults fail.
  3. Case / whitespace driftFest-Demo vs fest-demo.
  4. itch uploaded from different commit — MIME pass, label stale.
  5. Separate ITCH_VERSION define — HTML5 export preset not reading root VERSION.
  6. GX+Steam normalized compare; itch raw string — inconsistent CI function.
  7. itch custom domain — live URL differs from *.itch.io job artifact path (label still must match).

Beginner path (first 50 minutes)

Prerequisites: Repo VERSION file, three live URLs (itch tab, GX, installed Steam), last three upload receipts from CI.

  1. Read VERSION → write expected string E.
  2. Open itch game in private window → note HUD build_label (add overlay if missing).
  3. Open GX live URL → note overlay.
  4. Install Steam fest build → note overlay.
  5. If any ≠ E after trim → fix before re-sharing itch link.
  6. Open BUILD_RECEIPT JSON → find channel_label_match and per-channel rows.

Common mistake: Treating itch WASM MIME pass as proof all HTML5 channels align.

Fastest safe fix path

Step 1 — Single VERSION source (all three channels)

fest-demo-2026-05-24-rc2
Surface Must read VERSION
Steam NW.js / desktop Title-screen Label / version.txt
GX.games HTML5 Export inject + upload metadata
itch.io HTML5 Same artifact folder as GX when possible; itch “Version” field = VERSION

Wire Godot/Construct/GameMaker per GX receipt helpsame injection into itch zip.

Step 2 — itch_html5_upload_receipt_v1.json

After itch upload (butler / web UI / CI):

{
  "schema": "itch_html5_upload_receipt_v1",
  "uploaded_at_utc": "2026-05-24T23:40:00Z",
  "git_sha": "a1b2c3d4",
  "itch_game_id": "1234567",
  "itch_slug": "your-game-slug",
  "build_label": "fest-demo-2026-05-24-rc2",
  "live_url": "https://your-team.itch.io/your-game",
  "post_upload_mime_ok": true,
  "wasm_mime_receipt_ref": "wasm_mime_receipt_v1.json",
  "pass": true
}

Critical: build_label must equal VERSION—log itch_game_id separately; never compare game id to VERSION in CI.

Store: release-evidence/itch/itch_html5_upload_receipt_v1.json.

Step 3 — Extend GX + Steam receipts (pairwise baseline)

Ensure existing receipts from same pipeline run:

  • release-evidence/gx/gx_html5_upload_receipt_v1.jsonbuild_id = VERSION
  • release-evidence/steam/build_label_smoke_receipt_v1.jsonsteam_fest channel pass

See 14 Free GX multi-channel HTML5 tools.

Step 4 — triple_channel_label_receipt_v1.json

{
  "schema": "triple_channel_label_receipt_v1",
  "checked_at_utc": "2026-05-24T23:45:00Z",
  "version_file_sha256": "sha256:...",
  "expected_build_label": "fest-demo-2026-05-24-rc2",
  "normalize": { "trim": true, "compare_case_fold": true },
  "channels": [
    {
      "channel": "steam_fest",
      "surface": "fest_public",
      "logged_label": "fest-demo-2026-05-24-rc2",
      "normalized_match": true,
      "pass": true
    },
    {
      "channel": "gx_html5",
      "surface": "gx_public",
      "logged_label": "fest-demo-2026-05-24-rc2",
      "normalized_match": true,
      "pass": true
    },
    {
      "channel": "itch_html5",
      "surface": "itch_public",
      "logged_label": "fest-demo-2026-05-24-rc2",
      "normalized_match": true,
      "pass": true
    }
  ],
  "channel_label_match": true,
  "git_sha": "a1b2c3d4",
  "pass": true
}

Rule: channel_label_match on this receipt must equal BUILD_RECEIPT column—single aggregator script writes both.

Step 5 — Normalize function (CI)

def norm_label(s: str) -> str:
    return s.strip().casefold()

def channel_label_match(version: str, *labels: str) -> bool:
    v = norm_label(version)
    return all(norm_label(x) == v for x in labels)

# Usage after loading three receipts
ok = channel_label_match(
    open("VERSION").read(),
    gx_receipt["build_id"],
    steam_receipt["channels"][0]["installed_build_label"],
    itch_receipt["build_label"],
)
if not ok:
    raise SystemExit("channel_label_match false")
Pitfall Fix
Compare itch_game_id to VERSION Use build_label field only
Case-sensitive compare Use casefold() for gate; display original casing in HUD
itch job on old artifact Pin same git_sha artifact path for all HTML5 uploads

Step 6 — playtest_scope_map_v1.json surface tags

{
  "surfaces": [
    {
      "surface_id": "fest_public",
      "channel": "steam",
      "build_label": "fest-demo-2026-05-24-rc2",
      "demo_scope": "fest_hour_one"
    },
    {
      "surface_id": "gx_public",
      "channel": "gx_html5",
      "build_label": "fest-demo-2026-05-24-rc2",
      "demo_scope": "fest_hour_one"
    },
    {
      "surface_id": "itch_public",
      "channel": "itch_html5",
      "build_label": "fest-demo-2026-05-24-rc2",
      "demo_scope": "fest_hour_one"
    }
  ]
}

Missing itch_public is the #1 scope-map cause of false channel_label_match when itch is live but unmapped.

Step 7 — BUILD_RECEIPT columns

Column Example
build_label fest-demo-2026-05-24-rc2
git_sha a1b2c3d4
steam_depot_upload_ok true
gx_upload_ok true
itch_upload_ok true
wasm_mime_receipt pass
channel_label_match true
triple_channel_label_receipt pass

Attach paths: upload_log[] entries for steam, gx, itch receipts.

Block fest / public itch link when channel_label_match: false.

Working dev path — proof table

Check Steam GX itch
Overlay shows VERSION Photo Private-window photo Private-window photo
Receipt build_label / build_id smoke receipt gx receipt itch receipt
Same git_sha Yes Yes Yes
post_upload_mime_ok N/A optional required for Godot
Scope map row fest_public gx_public itch_public

Run 12 Free itch HTML5 WASM MIME cross-check tools before declaring HTML5 stack green.

Verification checklist

  • [ ] VERSION matches all three overlays (photos in CI artifacts)
  • [ ] triple_channel_label_receipt_v1.json channel_label_match: true
  • [ ] BUILD_RECEIPT channel_label_match: true
  • [ ] itch_public present in scope map with same build_label
  • [ ] itch receipt uses build_label, not game id, for compare
  • [ ] All uploads from same git_sha
  • [ ] Wednesday smoke spreadsheet has itch column
  • [ ] WASM MIME receipt pass for itch (Godot/Construct)

Prevention

  1. One pipeline, three upload jobs—same artifact directory.
  2. Never add itch to README without extending CI diff script.
  3. Template triple_channel_label_receipt_v1.json in repo schemas/.
  4. Ban manual itch “Version” edits outside VERSION file generation.
  5. Pair facilitators with GX multi-channel resource checklist.

Troubleshooting

Symptom Fix
Steam+GX pass, itch fail itch build_label field + scope map row
itch pass after lowercase-only fix Document compare uses casefold; HUD keeps display case
All receipts pass, BUILD_RECEIPT false Aggregator reads stale itch path or wrong JSON key
itch numeric id in receipt Add build_label; stop comparing itch_game_id
MIME fail, label match Fix itch CDN MIME first
Custom domain itch Label gate unchanged; CORS may need Construct CORS help

FAQ

Can channel_label_match be true if demo scopes differ per channel?
Labels must match when scopes match. If itch is a jam slice and Steam is fest hour-one, use different intentional build_label values and set channel_label_match: false with documented reason—do not silently drift.

Do I need three separate HTML5 builds?
Prefer one export artifact uploaded to itch and GX; Steam may be NW.js wrapper around same VERSION—still log three channel receipts.

GX+Steam was green before itch—what changed?
The aggregator now includes a third label; pairwise scripts were incomplete.

Is this the same as Steam depot promotion mismatch?
No—Steam depot build_label is wrong binary on Steam. This article is cross-surface label on HTML5 triple upload.

Related links

Add the itch column when you add the itch URL—pairwise green on Steam+GX is not triple-channel proof.