448 lines
12 KiB
Markdown
448 lines
12 KiB
Markdown
# Closer Question Quality Checklist v10 — Importer-Aligned
|
||
|
||
**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.
|
||
|
||
## 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 question’s 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
|
||
|
||
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
|
||
|
||
## 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.
|