Tuesday Discord Playtest Thread CSV Receipt Ingest - Twelve-Minute Ritual Before Wednesday Smoke - 2026

Tuesday stand-up opens with: “Any blockers?” Someone says “a few in Discord.” Nobody counted them. Wednesday you promote nextfest-oct-2026-rc5. Thursday a player soft-locks on a boss door your facilitator flagged P0 in a spreadsheet cell buried under a filter.
October 2026 async playtest volume exceeds stand-up time. 18 playtest feedback tools generate Discord threads, Sheets exports, and VODs faster than producers can read them. Wednesday demo smoke proves the binary golden path—it does not read facilitator spreadsheets. Without a Tuesday CSV ingest ritual, P0 rows live in Slack reactions, not BUILD_RECEIPT.
This Process & Workflow post defines a twelve-minute Tuesday ritual: export Discord thread → three-column minimum CSV → jq normalize → P0/P1 blocker counts → playtest_csv_ingest_receipt_v1.json → set Wednesday smoke scope. The ninety-second jq checklist lives in Discord CSV jq preflight (Guide); this article owns facilitator rhythm, time-box, and promotion policy.
Non-repetition note: Whisper→GitHub tag extraction owns VOD quote-only issues; Weblate UTF-8 preflight owns encoding bytes; Wednesday smoke owns binary S4–S6. This URL owns Tuesday async CSV triage counts—not another metadata checklist, not Whisper transcripts.
Who this is for and what you get
| Audience | You will be able to… |
|---|---|
| Solo founder | Export Discord feedback into a three-column CSV in five minutes |
| Facilitator | Pin column map + jq script so Tuesday ingest takes twelve minutes |
| Producer | Block Wednesday promotion when P0 > 0 without documented waiver |
| Engineer | Read playtest_csv_p0 / playtest_csv_p1 on BUILD_RECEIPT before merge |
Time: 12 minutes every Tuesday (default before Wednesday smoke week).
Prerequisites: Discord thread or Google Sheet export; jq on PATH; BUILD_RECEIPT row for target build_label; playtest-feedback/README.md with column map.
Why this matters now (October 2026)
- Discord thread volume — Fest weeks produce 30–80 CSV rows; stand-ups cannot enumerate them.
- Promotion without scope — Teams promote while four P0 rows still reference last week's
build_id. - Receipt culture gap — Thursday row review cannot answer “how many P0?” without Tuesday counts on BUILD_RECEIPT.
- Founder time-box — Fest week capacity worksheet sets ingest budget; this ritual is the default twelve-minute block.
- Multi-channel facilitators — Lesson 206 SOW assumes CSV rows carry honest
build_id—not Discord pin memory.
Direct answer: Archive raw CSV, jq-normalize to playtest_feedback_normalized.json, compute P0/P1 counts, crosswalk build_id to BUILD_RECEIPT, file playtest_csv_ingest_receipt_v1.json, set wednesday_smoke_allowed only when D5 policy passes.
Weekly ritual map (Tuesday → Wednesday → Thursday)
| Day | Ritual | Layer | Receipt |
|---|---|---|---|
| Tuesday | CSV ingest (this article) | Async feedback scope | playtest_csv_ingest_receipt_v1.json |
| Tuesday PM | Whisper tag extract (optional) | VOD quote-only issues | whisper_issue_tag_receipt_v1.json |
| Wednesday AM | Metadata diff | Store copy | metadata diff log |
| Wednesday PM | Demo smoke | Installed binary | demo_smoke_receipt_v1.json |
| Thursday | BUILD_RECEIPT row review | Machine-readable claims | build_receipt_row_diff_receipt_v1.json |
Rule: Tuesday CSV GREEN does not replace Wednesday smoke RED—they are different gates. CSV answers “should we promote given open blockers?” Smoke answers “does the binary boot?”
Mental model — triage vs encoding vs binary
| Stage | Owner | Proves |
|---|---|---|
| Tuesday jq ingest | P0/P1 counts + build_id crosswalk |
Blocker scope before promote |
| UTF-8 Weblate preflight | BOM / encoding | Weblate-safe bytes (cousin lane) |
| Lesson 256 | BUILD_RECEIPT | Weblate handoff promotion |
| Wednesday smoke | S4–S6 golden path | Installed demo boots |
Order: jq ingest (Tuesday) → UTF-8 handoff (when localization path) → Wednesday smoke. Do not skip Tuesday because “smoke passed last week.”
Beginner path — three-column CSV export
You do not need jq on day one to start the habit—pin this minimum schema in playtest-feedback/README.md:
| Column | Example | Required |
|---|---|---|
build_id |
2026-11-04-playtest-rc4 |
yes |
severity |
P0, P1, P2 |
yes |
summary |
Soft-lock after boss door |
yes |
Optional but valuable: area, discord_message_url, tester_handle (no PII beyond what players already posted publicly).
Step 1 — Export Discord thread (4 minutes)
| Source | Export path |
|---|---|
| Google Sheet facilitator log | File → Download → CSV |
| Discord + manual Sheet | Copy messages into Sheet; export CSV |
| Playtest tool with CSV export | Use tool's Discord integration per 18 playtest tools |
Save as playtest-feedback/raw/discord_thread_YYYY-MM-DD.csv.
Success check: File opens in a text editor; first line is headers; at least one data row exists.
Step 2 — Hand-count P0 (3 minutes)
Before jq automation, facilitator manually counts rows where severity is P0 or Blocker. Write count on sticky note or README roster.
Red flag: P0 > 0 and producer has not read summaries—block promotion until triaged.
Step 3 — Crosswalk build_id (2 minutes)
Open BUILD_RECEIPT and confirm every CSV row uses the same build_id as tonight's playtest night. Visible build label on the demo helps facilitators copy the correct string.
Fail-closed: mixed build_id values in one export—split CSV by build before continuing.
Step 4 — File receipt stub (3 minutes)
Even before jq, create minimal receipt:
{
"schema": "playtest_csv_ingest_receipt_v1",
"build_label": "2026-11-04-playtest-rc4",
"source_csv_path": "playtest-feedback/raw/discord_thread_2026-11-04.csv",
"counts_manual": { "P0": 1, "P1": 3, "P2": 8 },
"csv_ingest_ok": false,
"note": "manual Tuesday pass — jq normalize pending"
}
Graduate to full D1–D6 when jq script is pinned (developer path below).
Developer path — twelve-minute D1–D6 gates
Align with Discord CSV jq preflight (Guide). Blog = rhythm; guide = checklist.
| Minute block | Gate | Action |
|---|---|---|
| 0–2 | D1 | Archive CSV + sha256 |
| 2–4 | D2 | Validate column map vs headers |
| 4–7 | D3 | jq normalize → playtest_feedback_normalized.json |
| 7–9 | D4 | build_id crosswalk BUILD_RECEIPT |
| 9–11 | D5 | Compute P0/P1; apply promotion policy |
| 11–12 | D6 | Write playtest_csv_ingest_receipt_v1.json |
D2 — playtest_csv_column_map_v1.json
Pin column aliases so facilitator header drift does not silently empty jq output:
{
"schema": "playtest_csv_column_map_v1",
"source_headers": ["Build", "P-level", "Category", "Issue", "Link"],
"canonical_map": {
"build_id": "Build",
"severity": "P-level",
"area": "Category",
"summary": "Issue",
"discord_message_url": "Link"
},
"severity_normalize": {
"P0": ["P0", "p0", "Blocker", "Critical"],
"P1": ["P1", "p1", "High"],
"P2": ["P2", "p2", "Medium"]
}
}
Facilitator rule: new column mid-week → update map before Tuesday ingest (D2 fail if skipped).
D3 — jq normalize (bash)
sha256sum playtest-feedback/raw/discord_thread_2026-11-04.csv | tee /tmp/csv_sha.txt
jq -n --slurpfile rows playtest-feedback/raw/discord_thread_2026-11-04.csv \
--argfile map playtest-feedback/playtest_csv_column_map_v1.json \
-f scripts/normalize_playtest_csv.jq \
> playtest-feedback/normalized/playtest_feedback_normalized.json
Normalized output shape:
{
"schema": "playtest_feedback_normalized_v1",
"build_label": "2026-11-04-playtest-rc4",
"rows": [
{
"build_id": "2026-11-04-playtest-rc4",
"severity": "P0",
"area": "progression",
"summary": "Soft-lock after boss door",
"discord_message_url": "https://discord.com/channels/…"
}
],
"counts": { "P0": 1, "P1": 3, "P2": 8, "total": 12 }
}
Fail-closed: jq exit non-zero → no Wednesday promotion; fix column map (D2) before retry.
D4 — build_id crosswalk
jq -r '.build_id' release-evidence/BUILD_RECEIPT.json
jq -r '.rows[].build_id' playtest-feedback/normalized/playtest_feedback_normalized.json | sort -u
Pass: exactly one unique build_id matching BUILD_RECEIPT.
Fail: split CSV by build; re-run D3 per file.
D5 — blocker promotion policy
| Count | wednesday_smoke_allowed |
Promotion rule |
|---|---|---|
| P0 > 0 | false unless waiver |
Block fest branch promotion until triaged or producer waiver |
| P1 > 5 | true with p1_overflow: true |
YELLOW—document in receipt notes |
| P2 only | true |
GREEN for smoke scope (still file receipt) |
P0 waiver (when you must promote anyway):
## P0 waiver roster
| build_id | P0 summary | approver | UTC | waiver_id |
|----------|------------|----------|-----|-----------|
| 2026-11-04-playtest-rc4 | progression soft-lock | producer@studio | 2026-11-05T08:00:00Z | WAIVER-2026-11-04-01 |
Receipt field: "p0_waiver_id": "WAIVER-2026-11-04-01" — Thursday row review must show waiver Y/N.
D6 — playtest_csv_ingest_receipt_v1.json
{
"schema": "playtest_csv_ingest_receipt_v1",
"build_label": "2026-11-04-playtest-rc4",
"source_csv_path": "playtest-feedback/raw/discord_thread_2026-11-04.csv",
"source_csv_sha256": "cc99a435…",
"normalized_path": "playtest-feedback/normalized/playtest_feedback_normalized.json",
"column_map_path": "playtest-feedback/playtest_csv_column_map_v1.json",
"counts": { "P0": 1, "P1": 3, "P2": 8, "total": 12 },
"p0_blockers": ["progression: Soft-lock after boss door"],
"cousin_receipts": {
"weblate_utf8_handoff": "release-evidence/localization/WEBLATE_CSV_UTF8_HANDOFF_RECEIPT.json",
"whisper_issue_tag": "release-evidence/playtest/whisper-tags/WHISPER_ISSUE_TAG_RECEIPT_fragment_03.json"
},
"gates": {
"D1_csv_archived": "pass",
"D2_column_map": "pass",
"D3_jq_normalize": "pass",
"D4_build_id_crosswalk": "pass",
"D5_blocker_counts": "pass",
"D6_receipt": "pass"
},
"csv_ingest_ok": true,
"wednesday_smoke_allowed": true
}
Pin under release-evidence/playtest/PLAYTEST_CSV_INGEST_RECEIPT.json.
BUILD_RECEIPT columns (wire on D5 pass)
| Column | Example |
|---|---|
playtest_csv_p0 |
1 |
playtest_csv_p1 |
3 |
csv_ingest_ok |
true |
csv_ingest_receipt_path |
release-evidence/playtest/PLAYTEST_CSV_INGEST_RECEIPT.json |
Lesson 267 forward wires these columns into BUILD_RECEIPT promotion gates.
Twelve-minute timer script (facilitator README)
Copy into playtest-feedback/README.md:
# Tuesday CSV ingest (12 min)
| Min | Task | Owner |
|-----|------|-------|
| 0-2 | Export Discord/Sheet → raw CSV | Facilitator |
| 2-4 | Verify headers vs column_map_v1.json | Facilitator |
| 4-7 | Run jq normalize script | Engineer or facilitator |
| 7-9 | build_id crosswalk BUILD_RECEIPT | Producer |
| 9-11 | P0/P1 policy + waiver if needed | Producer |
| 11-12 | File PLAYTEST_CSV_INGEST_RECEIPT.json | Facilitator |
| Post | Post P0 count in #release (one line) | Producer |
One-line Discord post template:
Tuesday CSV ingest:
build_id=2026-11-04-playtest-rc4P0=1 P1=3 — smoke scope Wednesday PM.
Folder layout
playtest-feedback/
README.md # column map + Tuesday timer + waiver roster
playtest_csv_column_map_v1.json
raw/
discord_thread_2026-11-04.csv
normalized/
playtest_feedback_normalized.json
scripts/
normalize_playtest_csv.jq
release-evidence/playtest/
PLAYTEST_CSV_INGEST_RECEIPT.json
Pair Resource #12 facilitator README refresh when published—this folder is the source of truth for column map pins.
Relationship to Whisper and VOD triage
| Lane | Input | Output | Day |
|---|---|---|---|
| Tuesday CSV (this) | Discord text / Sheet rows | P0/P1 counts | Tuesday |
| Whisper→GitHub | VOD transcripts | Quote-only issues | Tuesday PM |
| Local Whisper pipeline | OBS clips | playtest_vod_triage_receipt_v1.json |
Nightly |
Do not double-count: A P0 in CSV and a Whisper issue for the same bug should share build_id + area—link URLs in receipt cousin_receipts, do not inflate P0 twice without noting duplicate.
Proof table (producer audit)
| Row | Evidence | Pass |
|---|---|---|
| Raw CSV archived | D1 path + sha256 | File exists |
| Column map current | D2 diff vs headers | jq not empty |
| Normalized JSON | D3 output | counts.total > 0 |
| Single build_id | D4 uniq output | Matches BUILD_RECEIPT |
| P0 policy | D5 waiver or block | Documented |
| Receipt filed | D6 csv_ingest_ok |
true |
Export release-evidence/playtest/PROOF_PACK_CSV_INGEST_YYYY-MM-DD/ for Q4 diligence triage integrity questions.
Seven scenarios (A–G)
| ID | Situation | Correct response |
|---|---|---|
| A | jq returns empty rows |
D2 column map vs export headers |
| B | Mixed build_id in one file |
Split CSV; re-run D3 per build |
| C | P0 > 0, must promote | Producer waiver row + p0_waiver_id |
| D | CSV GREEN, smoke RED | Fix binary—separate gates |
| E | Mojibake on Weblate import | UTF-8 preflight—not Tuesday jq |
| F | Facilitator counts P0 from emoji | Use normalized JSON counts only (D5) |
| G | No Tuesday ingest, Wednesday promote | Fail-closed—run ritual or document skip reason on BUILD_RECEIPT |
Common mistakes
- Promoting with undocumented P0 — refund screenshots follow.
- Hard-coded English jq headers — facilitator adds
優先度without map update (D2). - Skipping D4 — CSV still lists last week's
build_id. - Jumping to Weblate before jq GREEN — encoding cousin cannot fix wrong blocker scope.
- Treating CSV ingest as smoke substitute — Wednesday S4–S6 still required.
- Merging ingest receipt into Weblate handoff — use
cousin_receiptsonly (Lesson 256). - No
build_labelcolumn — visible label opinion requires facilitators can copy honest build strings.
CI optional gate (jq before promote)
#!/usr/bin/env bash
set -euo pipefail
REC="release-evidence/playtest/PLAYTEST_CSV_INGEST_RECEIPT.json"
jq -e '.csv_ingest_ok == true' "$REC"
jq -e '.counts.P0 == 0 or .p0_waiver_id != null' "$REC"
echo "Tuesday CSV ingest OK for promotion"
Wire as optional GitHub Actions job Tuesday 18:00 UTC before Wednesday smoke workflow triggers.
Facilitator contract and capacity
Multi-channel facilitator contract defines who exports CSV. Fest week time-box allocates twelve minutes engineering-adjacent ingest—not zero because “async means free.”
Resource #12 README refresh should include: column map template, waiver roster, Tuesday timer, jq script path.
Tools and sibling reads
- 18 free async playtest tools
- Discord CSV jq preflight (Guide)
- Playtest analytics event schema preflight
- OBS MKV concat help (Help #5 forward)
- 14 Free Weblate string-freeze tools
- Community playtest ops resource
- Official: jq manual
Key takeaways
- Twelve minutes every Tuesday — export, normalize, count, receipt—before Wednesday smoke.
- P0 > 0 blocks promotion unless documented producer waiver (D5).
build_idonly from BUILD_RECEIPT (D4)—visible label helps facilitators.- Column map JSON prevents silent jq empty output (D2).
- CSV ingest ≠ binary smoke — different gates, same week.
- Encoding is cousin UTF-8 preflight — run jq ingest first on triage scope.
- BUILD_RECEIPT columns
playtest_csv_p0/playtest_csv_p1wire blocker truth. - Thursday row review checks Tuesday P0 count Y/N.
- Guide preflight holds D1–D6 checklist; this post holds facilitator rhythm.
playtest_csv_ingest_receipt_v1.jsonproves Tuesday ran—not Slack vibes.
FAQ
Can we skip Tuesday if smoke passed last week?
No—new Discord rows arrive daily. File skip reason on BUILD_RECEIPT if ritual genuinely N/A (no playtest that week).
Google Sheet vs raw Discord export?
Sheet is fine—D1 archives whatever facilitator exports; column map must match headers.
What if we have zero rows?
File receipt with counts: { "P0": 0, "P1": 0, "P2": 0, "total": 0 } — proves empty week, not forgotten ingest.
Does this replace playtest analytics?
No—analytics preflight owns GA4 allowlist; CSV owns human facilitator blockers.
How does this pair with refund correlation?
Refund playbook tags build_id; Tuesday P0 rows explain known blockers before refunds spike.
Construct-only?
No—jq ingest is engine-agnostic; Construct guide chapter is the pinned checklist for HTML5 teams.
Where does Lesson 267 fit?
Lesson 267 wires playtest_csv_ingest_receipt into BUILD_RECEIPT promotion—pairs this ritual with receipt culture.
Conclusion
Promoting with undocumented P0 rows is how refund screenshots happen. Tuesday twelve minutes—normalize Discord CSV, crosswalk build_id, file blocker counts, pin receipt—buys honest Wednesday smoke scope.
Next reads: Wednesday demo smoke, Discord CSV jq preflight, Whisper tag extraction, Thursday row review, BUILD_RECEIPT beginner pipeline.
Found this useful? Pin the twelve-minute timer in playtest-feedback/README.md before your next fest week—not after the first undocumented P0 promotion.