jq Gate Sketch for localization_freeze_receipt_v1.json Weekly Locale Row Diff - 2026

Week three after localization string freeze evening: localization_freeze_ok: true, Weblate pin hash recorded, Supported languages match the selector. Tuesday someone merges a “tiny” Spanish store blurb hotfix. Thursday a contractor opens Catalan “for soft-launch only.” Monday stand-up asks “did freeze locales drift since last week?” Someone pastes April catalog weekly jq—wrong schema: April diffs Addressables catalog_sha256. March sprint weekly diffs BUILD_RECEIPT sprint columns. Freeze weeks need locale identity—locale IDs, string counts, PO/Weblate pins—week-over-week.
August–October 2026 punish teams that treat the freeze evening L1–L6 latch as forever-honest without a weekly locale row ritual. Silent locale adds and string-count bumps reopen the freeze while BUILD_RECEIPT still says green.
This Programming & Technical sketch ships a weekly instance of localization freeze honesty: localization_freeze_weekly_log.jsonl, weekly receipt fields on localization_freeze_receipt_v1 (or a dated weekly sibling documenting the same freeze pin), verify_localization_freeze_weekly.sh, gates J1–J6 on the locale schema (same letter prefix as April/March; different columns).
Non-repetition note: April catalog jq owns Addressables catalog hashes. March sprint jq owns post-fest BUILD_RECEIPT sprint rows. Freeze evening owns one-evening L1–L6 latch. Freeze challenge owns five-day habit closes. Forward #11 owns Friday capstone row review. This URL owns Monday weekly locale count / hash / ID set diff after freeze.
Pair freeze evening #1, freeze challenge #4, April catalog jq (cousin cadence), Guide #52 / Course 290 / Help #58 forward; forward blog #11.
Why this matters now (August–October 2026)
- Freeze evening is a point latch — L6 proves one night; weeks silently add locales without a new freeze.
- Soft-launch pressure — Marketing wants “one more language” without reopening L1 (soft-launch windows).
- CJK art and string drift travel together — Capsule typography Z passes can land while PO counts change (multilingual capsule).
- October upload queues — Discovery of an extra store language on upload week is too late for honest receipts.
- Wrong jq cousin ruins CI — Catalog and sprint scripts pass while locale sets lie.
Direct answer: Each ISO week after freeze, append localization_freeze_weekly_log.jsonl, file a weekly receipt with locale_row_diff[], run verify_localization_freeze_weekly.sh, clear J1–J6, set BUILD_RECEIPT localization_freeze_weekly_ok: true. Any locale ID add/remove or unexplained string-count delta requires a documented exception or a new freeze evening.
Who this sketch is for
| Audience | You will… |
|---|---|
| Beginner | Run Monday locale count / hash one-liners |
| Facilitator | Paste weekly locale diff into #loc-freeze |
| Engineer | Cron Monday 09:00 from freeze through October upload |
| Producer | Block store language edits until J5 honesty clears |
Time: ~40 minutes first weekly template; ~5–8 minutes per Monday after scripts pin.
Prerequisites: Freeze evening L6 GREEN; locale_manifest_v1.json path known; jq on CI or facilitator laptop; optional Weblate API/export folder.
Beginner path — Monday checklist (5–10 minutes)
- Open last week’s freeze pin path from BUILD_RECEIPT.
- Count locales in
locale_manifest_v1.json(jq '.locales | length'). - Compare to last Monday’s jsonl line—same count?
- Hash the manifest file (
sha256sum/Get-FileHash). - If count or hash changed without a receipt note → stop shipping store claims; reopen freeze or file exception.
- Paste results into stand-up.
Memorize one sentence: April weekly = catalog identity; freeze weekly = locale identity.
| Question | April catalog jq | This freeze locale jq |
|---|---|---|
| When? | ISO weeks after april_content_update_allowed |
ISO weeks after localization_freeze_ok |
| Log file | april_content_update_weekly_log.jsonl |
localization_freeze_weekly_log.jsonl |
| Anchor | Warm catalog / capstone pointer | Freeze receipt + Weblate pin |
| Diff fields | catalog_sha256, content hash, RemoteLoadPath |
locale_ids[], locale_count, strings_per_locale, weblate_pin, manifest_sha256 |
| Prereq | Capstone + warm | Freeze evening L1–L6 |
| Wrong reuse | March sprint schema | April catalog schema |
Beginner mistake: Appending April catalog lines into a localization folder—use a new jsonl and locale columns once freeze is latched.
Format ladder
| Artifact | Role |
|---|---|
| Freeze evening | One-evening L1–L6 latch |
| Freeze challenge | Five-day habit closes F1–F5 |
| This jq sketch | Weekly locale row diff J1–J6 |
| Forward #11 Friday localization freeze capstone row review | Ten-minute promote ritual |
| April catalog jq | Cousin cadence, different columns |
| Guide #52 forward | One tool step |
Order: Freeze evening → (optional challenge week) → weekly locale jq through soft-launch/October → Friday #11 capstone review.
Developer path — gates J1–J6 (locale schema)
These J gates belong to localization freeze weekly—not April catalog J1–J6 and not March sprint J1–J6.
| Gate | Pass criterion |
|---|---|
| J1 | Weekly receipt schema is localization freeze weekly (schema string documents localization_freeze_weekly_v1 or nested weekly block on freeze receipt) and iso_week set |
| J2 | Freeze pointer resolves (localization_freeze_ok true; freeze receipt path present) |
| J3 | Prior ISO week jsonl line exists (or week-1 bootstrap note referencing freeze night) |
| J4 | locale_ids sorted, locale_count matches length, manifest_sha256 non-empty |
| J5 | locale_row_diff[] honest for ID set, counts, pin, and per-locale string totals (no silent adds) |
| J6 | Receipt filed; BUILD_RECEIPT localization_freeze_weekly_ok: true |
Weekly receipt template
File as release-evidence/localization/weekly/2026-W36.json (example):
{
"schema": "localization_freeze_weekly_v1",
"iso_week": "2026-W36",
"freeze_pointer": {
"path": "release-evidence/localization/2026-08-25/localization_freeze_receipt_v1.json",
"localization_freeze_ok": true,
"weblate_pin_at_freeze": "a1b2c3d4e5f6789012345678abcdef01"
},
"snapshot": {
"manifest_path": "release-evidence/localization/2026-08-25/locale_manifest_v1.json",
"manifest_sha256": "sha256:1111111111111111111111111111111111111111111111111111111111111111",
"locale_ids": ["de", "en", "es", "fr", "ja", "ko"],
"locale_count": 6,
"weblate_pin": "a1b2c3d4e5f6789012345678abcdef01",
"strings_per_locale": {
"en": 1840,
"de": 1840,
"es": 1840,
"fr": 1838,
"ja": 1840,
"ko": 1840
},
"fuzzy_nonzero_locales": []
},
"locale_row_diff": [
{
"field": "locale_ids",
"before": ["de", "en", "es", "fr", "ja", "ko"],
"after": ["de", "en", "es", "fr", "ja", "ko"],
"delta": "unchanged"
},
{
"field": "locale_count",
"before": 6,
"after": 6,
"delta": "0"
},
{
"field": "manifest_sha256",
"before": "sha256:1111111111111111111111111111111111111111111111111111111111111111",
"after": "sha256:1111111111111111111111111111111111111111111111111111111111111111",
"delta": "unchanged"
},
{
"field": "weblate_pin",
"before": "a1b2c3d4e5f6789012345678abcdef01",
"after": "a1b2c3d4e5f6789012345678abcdef01",
"delta": "unchanged"
},
{
"field": "strings_per_locale.fr",
"before": 1840,
"after": 1838,
"delta": "-2",
"note": "EXCEPTION-LOC-004: retired two debug strings; freeze amendment logged"
}
],
"gates": {
"J1": "GREEN",
"J2": "GREEN",
"J3": "GREEN",
"J4": "GREEN",
"J5": "GREEN",
"J6": "GREEN"
},
"localization_freeze_weekly_ok": true,
"notes": "FR -2 with numbered exception; no ID set change"
}
Weekly log (jsonl)
release-evidence/localization/localization_freeze_weekly_log.jsonl — one line per ISO week:
{"iso_week":"2026-W35","locale_count":6,"manifest_sha256":"sha256:1111…","weblate_pin":"a1b2c3d4…","locale_ids":["de","en","es","fr","ja","ko"],"receipt":"release-evidence/localization/weekly/2026-W35.json"}
{"iso_week":"2026-W36","locale_count":6,"manifest_sha256":"sha256:1111…","weblate_pin":"a1b2c3d4…","locale_ids":["de","en","es","fr","ja","ko"],"receipt":"release-evidence/localization/weekly/2026-W36.json"}
BUILD_RECEIPT latch fields:
{
"localization_freeze_ok": true,
"localization_freeze_weekly_ok": true,
"localization_freeze_weekly_receipt": "release-evidence/localization/weekly/2026-W36.json"
}
Keep localization_freeze_ok as the night of freeze latch. Weekly OK is ongoing honesty—orthogonal columns.
Copy-paste jq one-liners
Schema + latch
jq -e '.schema == "localization_freeze_weekly_v1"
and .localization_freeze_weekly_ok == true' \
release-evidence/localization/weekly/2026-W36.json
Freeze pointer
jq -e '.freeze_pointer.localization_freeze_ok == true' \
release-evidence/localization/weekly/2026-W36.json
Locale count matches ID array
jq -e '
(.snapshot.locale_count == (.snapshot.locale_ids | length))
and (.snapshot.locale_ids | sort == .snapshot.locale_ids)
' release-evidence/localization/weekly/2026-W36.json
Diff vs prior jsonl week (locale set)
PREV=$(jq -s -c '.[-2].locale_ids' release-evidence/localization/localization_freeze_weekly_log.jsonl)
CUR=$(jq -s -c '.[-1].locale_ids' release-evidence/localization/localization_freeze_weekly_log.jsonl)
echo "prev=$PREV"
echo "cur=$CUR"
test "$PREV" = "$CUR"
Manifest hash drift alert
PREV=$(jq -s -r '.[-2].manifest_sha256' release-evidence/localization/localization_freeze_weekly_log.jsonl)
CUR=$(jq -s -r '.[-1].manifest_sha256' release-evidence/localization/localization_freeze_weekly_log.jsonl)
if [ "$PREV" != "$CUR" ]; then
echo "FAIL: manifest_sha256 changed — require locale_row_diff note or new freeze"
exit 1
fi
Honest exception for string count only
jq -e '
any(.locale_row_diff[];
(.field | startswith("strings_per_locale."))
and (.note | type == "string")
and (.note | startswith("EXCEPTION-LOC-"))
)
or (all(.locale_row_diff[];
(.field | startswith("strings_per_locale.") | not)
or .delta == "unchanged" or .delta == "0"
))
' release-evidence/localization/weekly/2026-W36.json
(Adjust the last expression to your studio rule: every string delta needs an EXCEPTION-LOC-### note.)
PowerShell twin (Windows facilitators)
$Weekly = "release-evidence/localization/weekly/2026-W36.json"
$Log = "release-evidence/localization/localization_freeze_weekly_log.jsonl"
$ok = jq -e '.schema == "localization_freeze_weekly_v1" and .localization_freeze_weekly_ok == true' $Weekly
if ($LASTEXITCODE -ne 0) { throw "J1/J6 latch failed" }
$prev = jq -s -c '.[-2].locale_ids' $Log
$cur = jq -s -c '.[-1].locale_ids' $Log
if ($prev -ne $cur) { throw "locale_ids drifted vs prior week" }
Write-Host "localization_freeze_weekly_ok"
verify_localization_freeze_weekly.sh
#!/usr/bin/env bash
set -euo pipefail
WEEKLY="${1:-release-evidence/localization/weekly/latest.json}"
LOG="${2:-release-evidence/localization/localization_freeze_weekly_log.jsonl}"
jq -e '.schema == "localization_freeze_weekly_v1"' "$WEEKLY" >/dev/null
jq -e '.freeze_pointer.localization_freeze_ok == true' "$WEEKLY" >/dev/null
jq -e '.snapshot.locale_count == (.snapshot.locale_ids | length)' "$WEEKLY" >/dev/null
jq -e '.localization_freeze_weekly_ok == true' "$WEEKLY" >/dev/null
for g in J1 J2 J3 J4 J5 J6; do
test "$(jq -r --arg g "$g" '.gates[$g]' "$WEEKLY")" = "GREEN"
done
MANIFEST=$(jq -r .snapshot.manifest_path "$WEEKLY")
test -f "$MANIFEST"
test -f "$LOG"
# Prior week bootstrap: allow single-line log on first Monday after freeze
LINES=$(wc -l < "$LOG" | tr -d ' ')
if [ "$LINES" -ge 2 ]; then
PREV=$(jq -s -c '.[-2].locale_ids' "$LOG")
CUR=$(jq -s -c '.[-1].locale_ids' "$LOG")
if [ "$PREV" != "$CUR" ]; then
# Allow only if weekly receipt documents locale_ids delta
jq -e 'any(.locale_row_diff[]; .field == "locale_ids" and .delta != "unchanged")' "$WEEKLY" >/dev/null \
|| { echo "locale_ids changed without locale_row_diff"; exit 1; }
fi
fi
echo "localization_freeze_weekly_ok"
Wire to CI as a Monday job:
# example GitHub Actions fragment
- name: localization freeze weekly
run: |
bash scripts/verify_localization_freeze_weekly.sh \
"release-evidence/localization/weekly/${{ env.ISO_WEEK }}.json"
Proof table
| Artifact | Proves | Does not prove |
|---|---|---|
| Freeze evening L6 | Night-of string + parity latch | Week-three honesty |
| Weekly jsonl | Locale set / hash history | Translation quality |
locale_row_diff |
Honest deltas | Capsule typography |
| Weekly OK latch | CI may continue soft ads | Dual-SKU depot readiness |
| Exception notes | Documented string retirements | Legal / font licenses |
Scenarios A–H
A — New locale ID appears in manifest
Fail J5 unless locale_row_diff records add and producer reopens freeze evening (new L1 list). Prefer: new freeze over silent weekly “exception.”
B — Locale removed “because soft-launch dropped KR”
Store claim and in-game selector must match. Diff must show remove; update store Supported languages same day—or fail soft honesty (soft-launch).
C — Weblate pin advanced without string count change
Still a freeze breach if pin was locked. File exception or re-freeze. Weekly jq must show pin delta in locale_row_diff.
D — April catalog jq GREEN, freeze weekly RED
Expected when CDN catalogs move but locale sets drift—different schemas. Do not merge verify scripts.
E — FR string count −2 with EXCEPTION-LOC-004
J5 can GREEN if note present and producer accepted retire. Document msgid list in exception file.
F — Freeze challenge week overlaps Monday ritual
Challenge F gates keep habits; weekly jq still appends jsonl. Do not skip Monday because challenge stand-up happened Tuesday.
G — Multilingual capsule Z6 while weekly locale drift
Art can be GREEN and freeze weekly RED—block JP/KR soft creatives until weekly OK (capsule typography).
H — First Monday after freeze (bootstrap)
J3 accepts a bootstrap note: prior = freeze-night snapshot written as week-0 line in jsonl. Do not invent fake prior hashes.
Common mistakes
- Copying April
catalog_row_difffield names into localization folders. - Sorting locale IDs inconsistently (
jabeforeenone week)—always sort for stable diffs. - Updating Weblate pin in chat only—jsonl must change.
- Letting contractors add “preview locales” outside manifest.
- Treating fuzzy-zero as weekly proof without recounting strings.
- Clearing
localization_freeze_okto false just because weekly failed—weekly is separate; reopen with a new freeze if IDs change. - Skipping weeks during vacation—append
skipped: truewith owner, or fail closed next Monday.
Troubleshooting
“jq not found on Windows laptop.” Install jq via scoop/choco, or run CI-only and paste artifacts. PowerShell twin still shells out to jq for JSON honesty.
“String counts disagree between Weblate and PO export.” Pick one source of truth in freeze evening notes; weekly must use the same path.
“Manifest path moved.” Update freeze pointer and note path migration in weekly notes; hash the new file—don’t edit old weekly lines.
“Producer wants Catalan for press only.” Either add to manifest + re-freeze, or refuse store claim. Weekly jq exists to catch the middle ground.
Schedule pairing
| When | Action |
|---|---|
| Freeze L6 night | Write week-0 jsonl snapshot |
| Each Monday to October | Weekly receipt + verify script |
| Soft-launch weeks | Block language claim edits without J5 |
| Before October upload | Confirm last weekly OK + freeze pin unchanged |
| Friday #11 capstone | Row-review weekly trail |
Evidence folder layout
release-evidence/localization/
2026-08-25/
locale_manifest_v1.json
localization_freeze_receipt_v1.json
weekly/
2026-W35.json
2026-W36.json
latest.json # copy or symlink to current ISO week
localization_freeze_weekly_log.jsonl
exceptions/
EXCEPTION-LOC-004.md
CI severity matrix
| Failure | Severity | Action |
|---|---|---|
| Schema wrong / latch false | Block merge | Fix receipt |
| locale_ids drift no diff | Block release | Re-freeze or document |
| manifest hash drift unexplained | Block store publish | Diff review |
| string count delta with exception | Warn + require LQA sign | Continue if signed |
| Skip week without note | Block following Monday | Backfill jsonl |
Micro-studio capacity
| Team | Approach |
|---|---|
| Solo | 8-minute Monday terminal ritual + jsonl append |
| 2–3 | Eng owns verify; producer owns exceptions |
| With LQA | LQA signs string-count deltas; eng owns ID set |
Generating Monday snapshots from locale_manifest_v1.json
Assume freeze locked a manifest shaped like:
{
"schema": "locale_manifest_v1",
"locales": [
{"id": "en", "store_claim": true, "string_count": 1840},
{"id": "ja", "store_claim": true, "string_count": 1840}
]
}
Extract weekly snapshot columns:
MANIFEST=release-evidence/localization/2026-08-25/locale_manifest_v1.json
jq -c '{
locale_ids: [.locales[].id] | sort,
locale_count: (.locales | length),
strings_per_locale: (reduce .locales[] as $l ({}; .[$l.id] = $l.string_count))
}' "$MANIFEST"
Hash for jsonl:
# Linux/macOS
sha256sum "$MANIFEST" | awk '{print "sha256:" $1}'
# PowerShell
(Get-FileHash $MANIFEST -Algorithm SHA256).Hash.ToLower() | ForEach-Object { "sha256:$_" }
Write week-0 on freeze night using the same commands so Monday-1 has an honest prior line. Facilitators who only copy screenshot chat into stand-up skip the hash—and fail closed when someone edits store names inside the manifest without adding locales.
Freeze night → Monday handoff card
Paste into the freeze PR description:
## Localization freeze weekly handoff
- Freeze receipt: …
- Manifest path: …
- Week-0 jsonl appended: yes/no
- First Monday owner: …
- Exception series prefix: EXCEPTION-LOC-
- Do not open Weblate writes without new freeze or numbered exception
Producers who skip the handoff card rediscover “which folder is truth?” every Soft-launch panic week.
Pair next — contractor burn-down (#9 published)
Weekly locale jq catches identity drift. It does not catch cash drift: LQA invoices and emergency translator nights that appear while engineering still pays patch contractors. When Monday shows stable locale_ids but finance asks why localization burn doubled, run the localization contractor burn-down worksheet—cash caps sit beside this receipt, not inside it.
FAQ
Is this the same as freeze evening?
No. Evening latches once. Weekly proves the latch still matches disk and exports.
Same as freeze challenge?
Challenge is a five-day social/habit close. Weekly is calendar CI through October.
Can we reuse April verify script?
No. Different schema, fields, and failure modes.
What if we only claim English?
Weekly still trivial-passes with locale_ids: ["en"]—cheap insurance against accidental adds.
Does weekly OK replace typography Z6?
No. Glyph geometry is art; this is locale identity.
How do exceptions work?
Numbered EXCEPTION-LOC-### files; reference in locale_row_diff[].note. Capstone #11 should list open exceptions.
When do we stop Monday runs?
After October fest upload closeout—or when a new freeze night starts a new series (new jsonl recommended).
What about Crowdin instead of Weblate?
Same columns: replace weblate_pin with crowdin_pin consistently in schema notes.
Key takeaways
- After freeze, run a weekly locale row diff—not April catalog jq.
- Gates J1–J6 here mean locale schema, not catalog or sprint.
- Append
localization_freeze_weekly_log.jsonlevery ISO week. - Latch
localization_freeze_weekly_okseparately fromlocalization_freeze_ok. - Silent locale ID adds fail J5—prefer a new freeze evening.
- String-count deltas need numbered EXCEPTION-LOC notes.
- Pair freeze evening #1 and challenge #4; forward Friday #11.
- Soft-launch must not invent preview languages outside the manifest.
- Sort
locale_idsfor stable diffs. - Guide #52 / Course 290 / Help #58 continue the format ladder.
- Bootstrap week-0 from freeze night—don’t invent prior hashes.
- Wrong cousin jq (April/March) is a class of CI false greens—keep scripts separated.
Related reads
- Your First Localization String Freeze Receipt Before October PO Import
- 5-Day Localization Freeze Gate Challenge Before October Next Fest
- jq Gate Sketch for april_content_update Weekly Catalog Row Diff — cousin cadence; different columns
- jq Gate Sketch for march_post_fest_sprint Weekly BUILD_RECEIPT Row Diff
- August 2026 Soft-Launch Windows Before October Next Fest
- Multilingual Capsule Typography Safe-Zone Pass JP KR
- Weblate Merge Conflicts Block October Fest String Freeze
- 18 Free Localization QA Tools for Indie Teams
- Localization Contractor Burn-Down Cap Worksheet Before October String Freeze — LQA/vendor cash beside weekly identity
Closing
Freeze night without Monday honesty is how Catalan appears in Supported languages three weeks later with no receipt. File the weekly locale row diff, keep April catalog jq in its lane, and let localization_freeze_weekly_ok be the boring green light soft-launch and October upload both respect.
When someone asks for one more language “just for soft ads,” the jsonl has an answer: same set, new freeze, or no.