Lesson 257: Unity Addressables jq Audit Receipt on BUILD_RECEIPT (2026)
Direct answer: Before October fest Addressables strip PRs merge, promote addressables_audit_jq_receipt_v1.json proving address_inventory_v1.json includes an optional groups[] array (even when empty), CI jq -e 'has("groups")' passes, and inventory keys crosswalk to 7-day key audit K1—distinct from Lesson 219 (addressables_fest_string_table_receipt after strip) and blog addressables_key_audit_receipt_v1 (seven-day calendar). Pair the Addressables jq optional groups preflight (Guide #20).

Why this matters now (October fest content-update CI)
October 2026 teams pass K1 inventory Monday then merge strip PRs Tuesday—GitHub Actions runs jq on address_inventory_v1.json and fails when the file has keys[] only with no groups field. Engineers “fix” CI by deleting the jq step instead of adding schema—257 files addressables_audit_jq_receipt_v1.json so BUILD_RECEIPT addressables_audit_jq_ok blocks promotion when optional groups is omitted. Invalid Key help is reactive triage; this lesson is inventory schema + CI guard before strip.
The Addressables jq preflight is the ninety-second gate—257 is the BUILD_RECEIPT milestone.
Beginner path (inventory schema → jq → receipt)
| Step | Action | Success check |
|---|---|---|
| 1 | Complete challenge K1 address_inventory_v1.json |
Keys listed |
| 2 | Add groups[] array (can be empty) |
J2 jq pass |
| 3 | Document group membership per key | J3 crosswalk |
| 4 | Wire CI jq -e 'has("groups")' |
J4 fail-closed |
| 5 | File receipt + BUILD_RECEIPT | addressables_audit_jq_ok: true |
Time: ~50 minutes first October strip week; ~10 minutes when CI template exists.
Developer path (gates J1–J6)
| Gate | Check | Fail when |
|---|---|---|
| J1 | address_inventory_v1.json exists |
K1 skipped |
| J2 | has("groups") jq guard |
Field omitted entirely |
| J3 | groups[] schema note committed |
Undocumented optional array |
| J4 | Each key maps to a group name | Orphan keys without group |
| J5 | CI fails if groups removed |
jq step deleted to green CI |
| J6 | Receipt + BUILD_RECEIPT | Promote before J4 GREEN |
J1 — cousin receipt crosswalk
| Field | Cousin (blog K7) | Cousin (219) | This lesson (257) |
|---|---|---|---|
| Schema | addressables_key_audit_receipt_v1 |
addressables_fest_string_table_receipt_v1 |
addressables_audit_jq_receipt_v1 |
| Scope | Seven-day audit calendar | Post-strip String Tables | Inventory JSON + jq CI guard |
| Path | release-evidence/unity/addressables-audit-week/ |
release-evidence/localization/ |
release-evidence/unity/addressables-jq/ |
Do not merge schemas—reference paths in cousin_receipts only.
address_inventory_v1.json (groups required)
{
"schema": "address_inventory_v1",
"build_label": "october-fest-2026-rc2",
"groups": [
{ "name": "Localization_Local", "strip_candidate": false },
{ "name": "fest_optional", "strip_candidate": true }
],
"keys": [
{
"key": "UI/MainMenu",
"source": "MenuController.cs:42",
"type": "address",
"group": "Localization_Local"
}
],
"orphan_literals": []
}
Schema note: groups is required key, may be empty array []—CI distinguishes “no optional groups field” from “zero groups listed.”
J2 — jq guards (CI)
# Fail closed if groups key missing (J2)
jq -e 'has("groups")' address_inventory_v1.json
# Optional: enforce array type (J3)
jq -e '.groups | type == "array"' address_inventory_v1.json
# Optional: every key.group exists in groups[].name (J4)
jq -e '
. as $inv |
($inv.groups | map(.name)) as $names |
all($inv.keys[]; .group == null or (.group | IN($names[])))
' address_inventory_v1.json
GitHub Actions sketch:
- name: Addressables inventory jq guard
run: |
test -f address_inventory_v1.json
jq -e 'has("groups")' address_inventory_v1.json
jq -e '.groups | type == "array"' address_inventory_v1.json
addressables_audit_jq_receipt_v1.json
{
"schema": "addressables_audit_jq_receipt_v1",
"build_label": "october-fest-2026-rc2",
"inventory_path": "release-evidence/unity/addressables-jq/address_inventory_v1.json",
"inventory_sha256": "aa11…",
"jq_guards": [
"has(groups)",
"groups_is_array",
"key_group_crosswalk"
],
"ci_workflow": ".github/workflows/addressables-inventory-jq.yml",
"cousin_receipts": {
"key_audit_week": "release-evidence/unity/addressables-audit-week/addressables_key_audit_receipt_v1.json",
"fest_string_table": "release-evidence/localization/ADDRESSABLES_FEST_STRING_TABLE_RECEIPT.json"
},
"gates": {
"J1_inventory": "pass",
"J2_has_groups": "pass",
"J3_schema_note": "pass",
"J4_key_group_crosswalk": "pass",
"J5_ci_fail_closed": "pass",
"J6_build_receipt": "pass"
},
"addressables_audit_jq_ok": true,
"content_update_promotion_allowed": true
}
Pin under release-evidence/unity/addressables-jq/ADDRESSABLES_AUDIT_JQ_RECEIPT.json.
BUILD_RECEIPT row (J6)
| Column | Pass when |
|---|---|
addressables_audit_jq |
addressables_audit_jq_ok: true |
addressables_key_audit |
Cousin blog K7 independent column |
string_table_receipt |
Cousin Lessons 202/219 independent |
ALTER TABLE release_publish_gate ADD COLUMN IF NOT EXISTS
addressables_audit_jq_blocked BOOLEAN NOT NULL DEFAULT false;
Thursday row review — Addressables jq audit line: has(groups) Y/N.
Key takeaways
groups: []is valid—missinggroupskey is not (J2).- Do not delete jq CI to green builds—fix inventory (J5).
- 7-day challenge K1 feeds J1—run challenge before strip PR.
- Lesson 219 after strip—257 before merge.
- Localization_Local preflight — tables lane.
- Invalid Key help — runtime triage cousin.
- Cousin: Lesson 258 OBS uniform replay—parallel playtest ingest column.
- Lesson 256 — parallel localization ingest column.
- October capstone 265 wires 254–264 including this row.
- Top 20 receipts hub — jq audit row in fest→public map.
Common mistakes
- Omitting
groupsbecause “we have no optional groups”—usegroups: [](J2). - Replacing jq guard with Python script that silently passes missing field (J5).
- Filing 219 while inventory jq still RED—strip vs schema are different gates.
- Merging
addressables_audit_jq_receiptintoaddressables_key_audit_receipt. - Skipping K1 keys—empty
groupswith emptykeysfails J1 purpose.
Troubleshooting
| Symptom | Lane |
|---|---|
CI jq fails on has("groups") |
Add "groups": [] or populate groups |
| jq passes, InvalidKey at runtime | Invalid Key help |
| Tables missing post-strip | Lesson 219 |
| Key/group mismatch | J4 crosswalk jq |
| Weblate strings wrong | Lesson 256 |
Mini exercise (40 minutes)
- Start from K1 inventory without
groups—confirm jq fail. - Add
"groups": []—confirm J2 pass. - Add one group + key crosswalk—run J4 jq.
- File receipt; BUILD_RECEIPT GREEN.
Continuity — October–Q4 2026 fest ops truth (254–265)
| Lesson | Receipt focus |
|---|---|
| 256 | Construct Weblate CSV UTF-8 |
| 257 (this) | Unity Addressables jq inventory audit |
| 258 | OBS uniform replay fragments |
| 265 | October ops capstone (queued) |
Previous: Lesson 256 — Construct Weblate CSV UTF-8 handoff
Next: Lesson 259 — Bevy menu UI flush (queued)
FAQ
Same as the 7-day challenge?
Challenge owns K1–K7 calendar; 257 owns jq has("groups") BUILD_RECEIPT column.
Same as Lesson 219?
219 = String Tables after strip; 257 = inventory schema before strip.
Empty groups array OK?
Yes—missing groups key is not.
Need jq on Windows agents?
Install jq in CI image or use container step—document in receipt ci_workflow.
October strip PRs fail CI for the wrong reason when groups vanishes from inventory—add the field, guard with jq, crosswalk keys, then addressables_audit_jq_ok before content-update promotion.