Closer/seed/questions/QUESTION_QUALITY_CHECKLIST.md

466 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Closer Question Quality Checklist v11 — Importer-Aligned, Human-Voice
**See also:** [QUESTION_CONTENT_GUIDE.md](QUESTION_CONTENT_GUIDE.md) | [QUESTION_SCHEMA.md](QUESTION_SCHEMA.md) | [QUESTION_REWRITE_PLAN.md](QUESTION_REWRITE_PLAN.md)
## Purpose
This checklist prevents technically valid but boring questions from reaching the app.
Passing JSON validation is not enough.
Every question must also feel human, useful, fun, and worth answering.
## Automatic Rejects
Reject any question that contains or strongly resembles:
* Describe...
* Reflect on...
* Discuss...
* Evaluate...
* In what ways...
* How satisfied are you...
* What boundary around...
* Explore your feelings...
* Identify the ways...
* Rate the effectiveness...
* Communication style
* Emotional processing
* Conflict framework
* Relationship dynamic
These are therapy worksheet patterns.
Also reject any question where (see `QUESTION_CONTENT_GUIDE.md` section 8A):
* an AI-tell phrase appears (`spice things up`, `level up`, `unleash`, `elevate`, `epic`, `ultimate`,
`game-changer`, `adventure awaits`, `whimsical`, `a dash of`, `sprinkle`, and the rest of the 8A list)
* "silly", "hilarious", "ridiculous", or "funny" is doing the humor work instead of a specific detail
* a prompt contains an exclamation mark, or a prompt/option contains emoji
* options are in Title Case
* all options in one set share a single grammatical template
* a guide example noun ("two-song kitchen dance", "dessert walk", "snack board") ships verbatim
These are machine-voice patterns.
## Production File Hard Checks
Run these before tone or content review.
Reject the file immediately if any item fails:
- top-level `category` object is missing
- top-level `questions` array is missing
- category is missing `id`, `display_name`, `description`, `access`, or `icon_name`
- any question is missing `id`, `category_id`, `type`, `text`, `depth`, `access`, or `tags`
- any `category_id` does not exactly match `category.id`
- any production `depth` is not the integer `1`, `2`, or `3`
- any `tags` value is missing or is not an array
- the file uses the old simple-pack shape
- the file is a partial batch
- the file is a patch manifest
- the production filename was overwritten by a work artifact
- the filename is being used as a substitute for a missing category
`sex` is optional and nullable for ordinary packs. Do not reject a normal pack merely because `sex` is absent. Require it only when a documented feature actually uses it for targeting.
## Type-specific importer checks
Reject the question if:
- a `scale` stores its settings outside `answer_config`
- a `written` question stores its settings outside `answer_config`
- a `this_or_that` question has no options
- a `this_or_that` question has anything other than two options
- a choice questions top-level options do not match `answer_config.options`
- a production question uses string depth
- a content note says “fix the importer later” while the production JSON remains incompatible
String depth is a future migration only. Until the code migration lands, valid production depth is integer `1`, `2`, or `3`.
## Normal Pack Hard Checks
For every normal category pack, confirm before content review:
* total question count is 150 or fewer
* the planned count is treated as a ceiling, not a quota
* metadata counts match the actual questions
* written questions total 0 to 5 unless a documented exception exists
* no questions were added only to reach 150
* free and premium counts match the documented pack plan
* all IDs and question texts are unique
* no exact or near-duplicate blocks remain
* old count, new count, and net catalog change are reported when replacing a legacy pack
## Daily Pack Hard Checks
For the daily single choice weekday pack, confirm before content review:
* 500 frozen weekday questions
* 11 free wildcard questions
* 511 total questions
* 86 free questions
* 425 premium questions
* every question is single_choice
* every weekday question has exactly one weekday tag
* every wildcard question has `mode_wildcard` and `daily_wildcard` and no weekday tag
* every question has 4 to 6 options
* 4 options preferred
* no duplicate IDs
* no duplicate question text
* no duplicate exact option lists
* the production file contains the full `category` object and all 511 questions
* the production file is not a patch manifest containing only changed IDs
* the category object exists and its id matches every `category_id`
* the production category id remains `daily_fun_mc` unless app code and data are migrated
* logical pack id `daily_single_choice_weekly_v1` belongs in metadata, not in place of the category object
* every daily question uses integer depth and includes category_id, access, and tags
## Daily Fun Gate
For daily questions, reject anything that is merely useful but not fun.
A daily question must feel like one of these:
* a game moment
* a tiny date choice
* a sweet choice
* a flirt
* a silly prompt
* a playful debate
* a low-pressure couple moment
Reject daily questions with answer sets built around:
* clean counters
* dishes
* laundry
* bills
* appointments
* errands
* bedtime planning
* household maintenance
* saved blankets
* clinical reassurance phrasing
These can exist in the real relationship. They should not dominate the daily fun pack.
Bad:
```text
Before phones win, what would make the night nicer?
```
Bad options:
* A clean counter
* A quick shoulder rub
* A simple bedtime plan
* The good blanket saved
Better:
```text
Before phones win, what should we do for fun?
```
Better options:
* Pick a ridiculous snack
* Watch one guilty-pleasure clip
* Trade dramatic compliments
* Choose tomorrow's tiny date
## Research-Informed Daily Fun Checks
A daily question must feel playable, not merely pleasant.
Pass only if the question uses at least one of these:
* a tiny mission
* a funny choice
* a playful debate
* a flirty pick
* a cute mini date
* a snack or treat choice
* a memory prompt
* a silly award
* a low-pressure dare
* a small surprise
Reject if the question mainly feels like:
* relationship maintenance
* emotional homework
* household management
* responsible adult planning
* generic wellness advice
* a cute phrase with no actual game inside it
Ask this out loud:
```text
Would two tired people still want to tap this for fun tonight?
```
If not, mark it as `not_fun` or `filler_question` and rewrite it.
## Research-Informed Option Checks
Options must feel like choices in a game.
Reject options that are:
* vague, like "something sweet"
* clinical, like "more reassurance"
* logistical, like "a bedtime plan"
* chore-coded, like "a clean counter"
* oddly phrased, like "the good blanket saved"
* too similar to each other
* too different in effort or intimacy
At least 3 out of 4 options should be visibly fun, sweet, flirty, silly, or date-like. If only 1 or 2 options feel fun, rewrite the whole answer set.
## Daily Pack Rejects
Reject daily prompts that feel like:
* therapy homework
* self-help content
* HR wellness surveys
* communication worksheets
* abstract emotional processing
* generic AI relationship advice
* household admin
* bedtime logistics
* chore planning
Reject daily questions using these words or phrases:
* reset
* process
* mental load
* emotional load
* autopilot
* pressure
* soft landing
* relationship dynamic
* name the mood
* emotional processing
* communication style
* conflict framework
## Daily Option Checks
Every daily option must:
* answer the exact prompt
* be a complete answer
* sound natural
* be similar in weight to the other options
* be fun, sweet, playful, flirty, silly, date-like, or warmly specific
Reject options that are:
* fragments
* too abstract
* weirdly specific
* chore-heavy
* clinical
* not connected to the prompt
* much better or worse than the other options
Bad fragment:
```text
When I need reassurance
```
Better:
```text
Tell me one thing you liked about today
```
Bad weird option:
```text
The good blanket saved
```
Better:
```text
Save me the best couch spot
```
## Catalog-Wide Hard Gate
Per-file checks are not enough.
Before rebuilding `app.db` or shipping any question change, scan every production pack together.
Reject the entire content build if any of these remain:
- duplicate question ID across files
- duplicate exact question text across files
- duplicate question text after case and whitespace normalization
- blocked near-duplicate prompts across related categories
- a category resolving to `unknown`
- a production filename containing a patch, partial batch, validation report, or other work artifact
- a depth value that would be coerced or read as `0`
- a question missing `category_id`
- a question missing its tags array
A duplicate across two otherwise valid packs still fails the whole catalog.
When two categories need similar ideas, rewrite each prompt around its own category purpose instead of copying identical text.
## Patch Discipline Checks
Before updating a daily pack, confirm the workflow is patch mode.
Required:
* every failed question has a marked ID
* every mark has a reason
* every mark has a fix scope
* only marked IDs are edited
* passing IDs are left unchanged
* metadata is preserved unless metadata failed
* the patch manifest is stored outside importer-scanned production files
* the complete source pack remains available
* the patch is applied to the complete source pack before shipping
* the result is a complete production pack, not a patch-only deliverable
* the report lists marked count, patched count, and remaining flag count
Reject the update if it rewrites passing questions without a mass rewrite exception.
Also reject the update if a patch manifest or partial batch replaces the production JSON, even when the patch itself is valid JSON.
Mass rewrite exception requires:
* more than 60 percent of the weekday or pack fails
* one shared root cause is named
* the report explains why patching is worse
* preserved fields are listed
## Fun But Grounded Checks
Reject daily questions that are fun only because they are random.
Mark as `too_random` or `mechanic_overuse` when the pack overuses:
* snack drafts
* fake awards
* mascot jokes
* couch games
* dramatic bits
* random object picks
* silly phrases that do not fit the prompt
A good daily question should feel playful and usable by adults.
It should not feel like a children's party game, a meme prompt, or a slot machine full of snacks.
## Option Answer Test
For every single-choice question, read the prompt followed by each option.
Each option must sound like a direct answer.
If one option fails, fix that option.
If two or more options fail, rewrite the answer set.
Mark failures as `option_mismatch` or `weird_option`.
Examples that fail:
* Prompt asks for a date move, option is an object.
* Prompt asks what to do tonight, option is a vague feeling.
* Prompt asks for a playful choice, option is a chore.
* Prompt asks for a flirty pick, option is a household task.
## Repetition Checks
Reject or rewrite if:
* too many questions start the same way
* the same option text appears too often
* the same situation repeats with different nouns
* the same answer pattern repeats
* the weekday starts to feel like wallpaper
* mechanic counts are implausibly even (exactly N of each mechanic is a machine fingerprint, not balance)
The pack can pass duplicate checks and still fail repetition review.
## Daily Sample Gate
Before approving the full daily pack:
1. Read 10 random questions from each weekday and all 11 wildcard questions.
2. Mark anything therapy-coded, boring, weird, logistical, or not fun.
3. Fix the marked items.
4. Run a second random sample from each weekday.
5. Fix only the sampled items that fail.
6. Run another sample if any sampled item changed.
7. Ship only when the second clean sample passes and the remaining hard flag count is 0.
The sample must include no chore-heavy answer sets, no weird domestic options, and no random silliness that does not fit the prompt.
## General Question Checks
Every question must pass:
* Would a real couple answer this willingly?
* Is it easy to understand on the first read?
* Does it create a conversation, laugh, flirt, memory, plan, or useful preference?
* Are the answer options balanced?
* Is the wording natural out loud?
* Would this feel premium in the app?
## Marking Reasons
Use these reasons when marking weak questions:
* therapy_voice
* wellness_voice
* household_admin
* not_fun
* abstract_prompt
* awkward_split_phrase
* repeated_stem
* option_mismatch
* fragment_options
* too_generic
* weird_option
* weak_weekday_fit
* filler_question
* too_random
* mechanic_overuse
* patch_scope_violation
* duplicate_text
* duplicate_options
* schema_issue
* ai_voice
* labeled_joke
* uniform_option_grammar
* guide_example_parrot
* brand_caption_voice
## Final Verdict Labels
Use one of these labels when reviewing a pack:
* production_ready
* production_candidate
* staging_only
* needs_rewrite
* reject
Do not call a pack production ready just because the JSON validates. Do not call it production ready while known hard content flags remain.