Compare commits
No commits in common. "ee88a94750971735e669f55699016a0720b913cd" and "5e7ef19b8f6d542ec13a9c77ac381e518a35884a" have entirely different histories.
ee88a94750
...
5e7ef19b8f
|
|
@ -44,29 +44,12 @@ reveal/results), not just launched.** All rows above are currently `launch ok /
|
||||||
still owed for every game** in Round 2 (premium games need a premium toggle). A launch-only row counts as `partial`, not `pass`.
|
still owed for every game** in Round 2 (premium games need a premium toggle). A launch-only row counts as `partial`, not `pass`.
|
||||||
|
|
||||||
## Pass C — Visual (light + dark), all ~50 routes
|
## Pass C — Visual (light + dark), all ~50 routes
|
||||||
**R3 (2026-06-25):** ~14 screen-types swept in Dark (5554), several in Light (5556 during A/B) — all render clean,
|
_todo — enumerate from AppRoute.kt; 5554=Dark, 5556=Light. Main tabs pass; deep/stateful screens owed._
|
||||||
readable, no FATAL, no new dark-mode contrast issues; **0 `enc:v1:` leaked to conversation UI**. Covered: Home, Play
|
**Also owed:** navigation from EVERY entry point (each screen via all its links) + back-stack / "double-back"
|
||||||
hub, all 7 game screens (setup/play/reveal), Paywall, Settings (+Subscription +Appearance), Today/daily-question
|
(system back + in-app back to correct place from each entry; no dead-ends, no exit surprise, no two-back/duplicate stack).
|
||||||
(+answer detail), Messages inbox, Conversation (image+voice+text+reaction). C-DS-001 dark-contrast fix holds.
|
|
||||||
**Back-stack ✅** deep→hub→Home→launcher clean (no double-back; C-NAV-001 holds). C-OBS resolved (debug menu gated).
|
|
||||||
_Deferred (nav-drift; standard list/detail, lower-risk): Question Packs detail, Bucket List, Past Games, Wheel History,
|
|
||||||
Answer Reveal (sealed), Date Builder/Plan Date, fresh-account auth/onboarding/pairing._
|
|
||||||
|
|
||||||
## Pass D — Security & Encryption (D1–D6)
|
## Pass D — Security & Encryption (D1–D6)
|
||||||
**R3:** D2 deployed rules re-audited ✅ (B-001 sessions + D-001 capsules/challenges fixes present; hasPremium +
|
_todo_
|
||||||
entitlements server-only; ciphertext enforced; no catch-all). D1 at-rest ✅ (chat text + lastMessagePreview =
|
|
||||||
`enc:v1:`; how_well answers + capsules = `enc:v1:`). D4/D5/D6 unchanged since R1 (code identical) → hold.
|
|
||||||
**D3 live non-member: deferred** (needs a 3rd fresh account; only 2 emulators, both couple members; rule logic
|
|
||||||
statically member-scoped). No P0/P1 security findings.
|
|
||||||
|
|
||||||
## Pass E — Notifications (17 types × {foreground, background, killed} + tap-to-open)
|
## Pass E — Notifications (17 types × {foreground, background, killed} + tap-to-open)
|
||||||
**R3 live:** FCM tokens valid for both. **chat_message ✅ full chain** (bg deliver + content-free + tap→exact
|
_todo_
|
||||||
conversation w/ content). **partner_started_game**: bg deliver + content-free ✅; tap→Play hub (not the game) =
|
|
||||||
**E-003 (P2)**. **E-OBS (P3)**: bg pushes use fcm_fallback channel. date_match live-verified R2-B2. E-001/E-002 fixes
|
|
||||||
present in code. Full 17×{fg/bg/killed} matrix not exhaustively run; routing centralized + code-verified for the rest.
|
|
||||||
|
|
||||||
## Pass F — Resilience / lifecycle / concurrency / time
|
|
||||||
**R3:** offline (airplane mode) → Today renders from cache, no crash ✅; rotation/config-change → landscape renders,
|
|
||||||
state preserved, no crash ✅; process-death/restore → ~6 cold restarts all clean to Home (auth persists) ✅;
|
|
||||||
concurrency → both devices played games simultaneously, sessions synced + B-001 auto-complete on concurrent finish ✅.
|
|
||||||
Time-gated content (capsule "Opens in 29 days", challenge day-gating) can't be time-traveled — noted.
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Claude QA Report — Full-App QA (living report)
|
# Claude QA Report — Full-App QA (living report)
|
||||||
|
|
||||||
> **RUN-STATE: Round 3 (full re-QA A–F) COMPLETE — 2026-06-25, build `ce7fc2e`. RESULT: all 12 prior fixes RE-VERIFIED HOLDING LIVE; deeper play-as-user testing surfaced 5 NEW issues — 2×P2 (B-004 intermittent guesser-stuck on WaitingForPartner; E-003 game notifications deep-link to Play hub not the game), 3×P3 (A-OBS paywall raw error copy [env]; E-OBS bg pushes use fallback channel; C-OBS RESOLVED = debug menu IS BuildConfig.DEBUG-gated, not a bug). NO P0/P1, NO security/encryption findings (Pass D clean, E2EE holds at-rest + UI). NOT yet "flawless" (2 open P2 + Pass E has E-003) → NEXT: a FIX PHASE for E-003 (client routeFor + likely server payload gameType, mirrors B-002) + a deterministic B-004 repro before fixing, then Round 4 re-QA. Baseline restored: both free, 0 active sessions. E-003/B-004 are report-only (logged, not fixed mid-round per plan).**
|
> **RUN-STATE: Round 3 (full re-QA, started 2026-06-25) | Build == HEAD `ce7fc2e` (rebuilt+reinstalled on BOTH emulators this session). Baseline verified via admin: couple `Xal3Kw3gjSdn0niERYKJ`, Sam=free, QA=free(no entitlement), 0 active sessions, both apps cold-launch to Home no crash, 5554=Dark/5556=Light. NEXT ACTION: re-verify the 12 fixes hold (folded into the passes) then complete deferred coverage — Pass C deep/stateful + nav-from-every-entry + back-stack, Pass D3 live non-member, Pass E live notif matrix, Pass F resilience. Progress logged per-pass below + in ClaudeQACoverage.md.**
|
||||||
> _Round 2 result (carried): FIX PHASE COMPLETE — P1×2 (B-001 session rules, C-NAV-001 back-stack), P2×4 (A-001, B-002, C-CC-001, C-DS-001), P3×4 (A-003, B-003, E-002, F-OBS) all FIXED; D-001 (P1 rules) + E-001 (P2 routing) fixed earlier. All verified LIVE except E-002/F-OBS (code+build; live-trigger deferred). Rules deployed._
|
> _Round 2 result (carried): FIX PHASE COMPLETE — P1×2 (B-001 session rules, C-NAV-001 back-stack), P2×4 (A-001, B-002, C-CC-001, C-DS-001), P3×4 (A-003, B-003, E-002, F-OBS) all FIXED; D-001 (P1 rules) + E-001 (P2 routing) fixed earlier. All verified LIVE except E-002/F-OBS (code+build; live-trigger deferred). Rules deployed._
|
||||||
> Pass-B note: a finished game keeps its session active until a player exits the results (Back to Play); leaving both on results blocks the next game until "End their game". Exit cleanly between games.
|
> Pass-B note: a finished game keeps its session active until a player exits the results (Back to Play); leaving both on results blocks the next game until "End their game". Exit cleanly between games.
|
||||||
> **Pass-B MINDSET (user, 2026-06-24): PLAY AS THE USER** — navigate only via the real in-app path a person would tap (no deep-links/admin pokes/shortcuts); expect what a user expects. When the natural path fails, **REPORT FIRST** (log issue + severity + the user action that failed & what was expected), **THEN** a minimal workaround to proceed — never silently engineer around breakage; a flow needing a workaround is broken and must be filed.
|
> **Pass-B MINDSET (user, 2026-06-24): PLAY AS THE USER** — navigate only via the real in-app path a person would tap (no deep-links/admin pokes/shortcuts); expect what a user expects. When the natural path fails, **REPORT FIRST** (log issue + severity + the user action that failed & what was expected), **THEN** a minimal workaround to proceed — never silently engineer around breakage; a flow needing a workaround is broken and must be filed.
|
||||||
|
|
@ -15,22 +15,15 @@ _(Prior games/notifications QA from 2026-06-24 was completed + verified; superse
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Severity summary (current — after Round 3 re-QA)
|
## Severity summary (current — R1 fixed + R2 findings)
|
||||||
| Severity | Open (new in R3) | Fixed (verified holding) |
|
| Severity | Open | Fixed |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| P0 | 0 | 0 |
|
| P0 | 0 | 0 |
|
||||||
| P1 | 0 | 4 |
|
| P1 | 0 | 4 |
|
||||||
| P2 | **2** (B-004, E-003) | 4 |
|
| P2 | 0 | 4 |
|
||||||
| P3 | **2** (A-OBS, E-OBS) | 4 |
|
| P3 | 0 | 4 |
|
||||||
|
|
||||||
**Round 3 result:** all **12 prior fixes RE-VERIFIED HOLDING LIVE** (C-NAV-001, C-CC-001, A-001, A-003, B-001 across 4 game types, B-002, B-003, C-DS-001, D-001 + E-001/E-002 code + F-OBS indirect). **No P0/P1, no security/encryption findings** (Pass D clean; E2EE holds at-rest + in UI). Deeper play-as-user testing found **5 new issues: 2×P2 (B-004, E-003), 3×P3 (A-OBS, E-OBS, and C-OBS which RESOLVED to not-a-bug — debug menu is BuildConfig.DEBUG-gated)**. Not yet "flawless" (def: 0 open P0–P2 + Passes D/E clean) — 2 open P2 remain → fix phase + Round 4 re-QA needed.
|
**ALL KNOWN ISSUES FIXED (P0–P3).** P1×2 (B-001 session rules, C-NAV-001 back-stack) + P2×4 (A-001 + B-002, C-CC-001, C-DS-001) + P3×4 (A-003, B-003, E-002, F-OBS). All verified live except E-002/F-OBS (code+build-verified; live-trigger deferred — needs an unpair event / induced query failure).
|
||||||
|
|
||||||
**New R3 issues (report-only — logged, to fix next phase):**
|
|
||||||
- **B-004 (P2, intermittent):** How Well guesser can get stuck on the generic WaitingForPartner screen during a rapid game-to-game transition (screen only exits on session end; needs deterministic repro before fix; escalate to P1 if deterministic).
|
|
||||||
- **E-003 (P2):** game notifications (`partner_started_game`/`game_results_ready`/`partner_completed_part`) deep-link to the generic Play hub, not the specific game/results, despite "Tap to join!" (fix: extend HomeViewModel.gameRouteFor resolver to notification routing; likely needs server payload gameType).
|
|
||||||
- **A-OBS (P3):** paywall plan-load shows raw "credentials issue" error (emulator has no RevenueCat sandbox; copy should be friendlier in prod).
|
|
||||||
- **E-OBS (P3):** backgrounded pushes use `fcm_fallback_notification_channel`, bypassing code-defined channels (CHANNEL_GAMES/chat) — server sends "notification" not data-only messages.
|
|
||||||
- **C-OBS (RESOLVED, not a bug):** Settings "Art preview/Paired home (debug)" entries ARE `BuildConfig.DEBUG`-gated (SettingsScreen.kt:469) — won't ship in release.
|
|
||||||
|
|
||||||
**Round 1: all P0–P2 found were FIXED** (A-001 premium P1, E-001 notif-routing P2).
|
**Round 1: all P0–P2 found were FIXED** (A-001 premium P1, E-001 notif-routing P2).
|
||||||
**Round 2 (Pass B play-as-user restart) new/changed:** **B-001** escalated **P3→P1** (a finished game never closes its
|
**Round 2 (Pass B play-as-user restart) new/changed:** **B-001** escalated **P3→P1** (a finished game never closes its
|
||||||
|
|
@ -89,15 +82,7 @@ Verified render cleanly, readable, **no FATAL, no new dark-mode contrast issues*
|
||||||
- D4 (wrapped couple key / KDF), D5 (App Check, gitignored SA JSONs, allowBackup=false), D6 (analytics metadata-only) unchanged since Round 1 — code identical, still hold.
|
- D4 (wrapped couple key / KDF), D5 (App Check, gitignored SA JSONs, allowBackup=false), D6 (analytics metadata-only) unchanged since Round 1 — code identical, still hold.
|
||||||
- **D3 live non-member negative test: still deferred** — needs a 3rd fresh account not in the couple (only 2 emulators, both members; signing one out risks the App Check debug token + couple state). Rule logic is statically member-scoped (`isCouplesMember` gate on every couple subcollection) — denial holds by construction.
|
- **D3 live non-member negative test: still deferred** — needs a 3rd fresh account not in the couple (only 2 emulators, both members; signing one out risks the App Check debug token + couple state). Rule logic is statically member-scoped (`isCouplesMember` gate on every couple subcollection) — denial holds by construction.
|
||||||
|
|
||||||
**Pass E (R3) — live notification tests (both FCM tokens valid, len=142):**
|
_Still to verify this round: edges (re-open completed / leave mid-game), Pass E live notif matrix, Pass F._
|
||||||
- **chat_message ✅ FULL CHAIN** — Sam backgrounded; QA sent a message → Sam received push **title "QA sent a message" / body "Tap to read and reply."** (content-free ✓, actual text NOT in payload → D6 holds) → **tapped → opened the exact conversation with the new message loaded** (deep-link ✓, background→cold path).
|
|
||||||
- **partner_started_game** — Sam backgrounded; QA started This or That → Sam received **"QA is playing / QA has started a game. Tap to join!"** (delivery ✓, content-free ✓). **BUT tap → landed on the generic Play hub, NOT the game.**
|
|
||||||
- **E-003 (NEW, P2) — game notifications deep-link to the generic Play hub, not the specific game/results.** Code: `PARTNER_STARTED_GAME`/`GAME_RESULTS_READY`/`PARTNER_COMPLETED_PART` all `routeFor → AppRoute.PLAY` (PartnerNotificationManager L270-272). The body says "Tap to **join**!" but the user lands on the hub and must find+tap the game card themselves (tapping it does then join the session, per B-002). Same gap B-002 fixed for the Home "Play now" card — never extended to notifications. Plan's Pass E wants "the **specific item**, not just the right tab" (strictly P1; rated P2 since it lands on the right tab and is recoverable). **Fix:** route game pushes through the active-session→game-route resolver (like HomeViewModel.gameRouteFor) so the deep-link joins the game. Report-only.
|
|
||||||
- **E-OBS (NEW, P3) — backgrounded pushes use `fcm_fallback_notification_channel`, not their code-defined channels.** The delivered chat + game pushes both landed on `fcm_fallback_notification_channel` even though the code assigns `CHANNEL_GAMES`/chat channels (PartnerNotificationManager L185). Means the server sends FCM "notification" (not data-only) messages, so the system auto-displays them on the fallback channel when backgrounded — bypassing the app's channel importance/sound and the per-category toggle (users can't mute just "Games"). **Fix:** send data-only FCM + build the notification client-side with the right channel, or set `android.notification.channel_id` in the FCM payload. Report-only.
|
|
||||||
- Foundations ✅ — both users registered FCM tokens; routing centralized in `PartnerNotificationType`; E-001 (daily_question/challenge_day_ready) + E-002 (partner_left→HOME) fixes present in code. date_match push live-verified R2-B2.
|
|
||||||
- _Full 17×{fg/bg/killed} matrix not exhaustively run; chat_message + partner_started_game live-verified this round (deliver+content-free; chat deep-link ✓, game deep-link → E-003). Remaining types: routing code-verified._
|
|
||||||
|
|
||||||
_Still to verify this round: edges (re-open completed / leave mid-game), Pass F._
|
|
||||||
|
|
||||||
## Pass A — Couple-shared premium ✅ pass complete
|
## Pass A — Couple-shared premium ✅ pass complete
|
||||||
**Target:** if either partner is premium, all premium features unlock for both.
|
**Target:** if either partner is premium, all premium features unlock for both.
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,139 +0,0 @@
|
||||||
# Closer Question Pack Rewrite Plan
|
|
||||||
|
|
||||||
## Purpose
|
|
||||||
|
|
||||||
This document defines the active rewrite plan: what needs to happen, in what order, and how to validate each pack.
|
|
||||||
|
|
||||||
For writing philosophy and tone, see `QUESTION_CONTENT_GUIDE.md`.
|
|
||||||
For JSON schema and validation rules, see `QUESTION_SCHEMA.md`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# 1. Product Goal
|
|
||||||
|
|
||||||
Closer is a relationship app, not a survey or therapy worksheet.
|
|
||||||
|
|
||||||
Every question should make couples smile, laugh, learn something new, remember something, plan something together, or have a meaningful conversation.
|
|
||||||
|
|
||||||
The app should feel like a game you accidentally spend an hour playing.
|
|
||||||
|
|
||||||
If a question feels like homework, rewrite it.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# 2. Consumer First Philosophy
|
|
||||||
|
|
||||||
People are opening Closer while sitting on the couch, riding in the car, eating dinner, or lying in bed.
|
|
||||||
|
|
||||||
They are not looking to complete an emotional worksheet.
|
|
||||||
|
|
||||||
Questions should be quick, conversational, and rewarding.
|
|
||||||
|
|
||||||
A couple should naturally answer dozens of questions in one session.
|
|
||||||
|
|
||||||
Every category should create moments like:
|
|
||||||
|
|
||||||
- "I didn't know that."
|
|
||||||
- "Really?"
|
|
||||||
- "That's adorable."
|
|
||||||
- "We should do that."
|
|
||||||
- laughter
|
|
||||||
- flirting
|
|
||||||
- nostalgia
|
|
||||||
- future plans
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# 3. Emotional Mix
|
|
||||||
|
|
||||||
Every pack should roughly contain:
|
|
||||||
|
|
||||||
- 35% fun and playful
|
|
||||||
- 25% everyday relationship
|
|
||||||
- 20% meaningful conversations
|
|
||||||
- 10% future dreams and planning
|
|
||||||
- 10% deeper vulnerability
|
|
||||||
|
|
||||||
Never group heavy questions together.
|
|
||||||
|
|
||||||
Every category must contain moments of humor and curiosity.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# 4. Rewrite Rules
|
|
||||||
|
|
||||||
For every category:
|
|
||||||
|
|
||||||
- Rewrite every question from scratch.
|
|
||||||
- Follow the content guide.
|
|
||||||
- Keep category ids.
|
|
||||||
- Use conversational language.
|
|
||||||
- Avoid therapy language.
|
|
||||||
- Avoid corporate wording.
|
|
||||||
- Avoid repetitive templates.
|
|
||||||
- Keep answers short.
|
|
||||||
- Use 4 to 6 options for choice questions.
|
|
||||||
- Make multi_choice clearly allow multiple answers.
|
|
||||||
- Make scale neutral.
|
|
||||||
- Keep written questions rare.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# 5. Fun Injection
|
|
||||||
|
|
||||||
Every category must include:
|
|
||||||
|
|
||||||
- at least 10 playful questions
|
|
||||||
- at least 5 questions that create laughter
|
|
||||||
- at least 5 questions that inspire a future date, memory, or shared activity
|
|
||||||
|
|
||||||
Even serious categories should contain lighter moments.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# 6. Rewrite Order
|
|
||||||
|
|
||||||
1. fun
|
|
||||||
2. date_night
|
|
||||||
3. quality_time
|
|
||||||
4. communication
|
|
||||||
5. gratitude
|
|
||||||
6. future
|
|
||||||
7. home_life
|
|
||||||
8. values
|
|
||||||
9. stress
|
|
||||||
10. money
|
|
||||||
11. boundaries
|
|
||||||
12. conflict
|
|
||||||
13. conflict_repair
|
|
||||||
14. trust
|
|
||||||
15. rebuilding_trust
|
|
||||||
16. difficult_conversations
|
|
||||||
17. emotional_intimacy
|
|
||||||
18. physical_intimacy
|
|
||||||
19. couple_intimacy
|
|
||||||
20. sex_and_desire
|
|
||||||
21. sexual_preferences
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# 7. Validation
|
|
||||||
|
|
||||||
Every rewritten pack must pass:
|
|
||||||
|
|
||||||
- Valid JSON
|
|
||||||
- 250 questions
|
|
||||||
- 75 free
|
|
||||||
- 175 premium
|
|
||||||
- 140 multi_choice
|
|
||||||
- 50 choice
|
|
||||||
- 35 scale
|
|
||||||
- 15 either_or
|
|
||||||
- 10 written
|
|
||||||
- Valid depth values only
|
|
||||||
- No duplicate ids
|
|
||||||
- No duplicate questions
|
|
||||||
- No malformed keys
|
|
||||||
- No placeholder text
|
|
||||||
- No therapy worksheet tone
|
|
||||||
- Every category contains fun, curiosity, and meaningful conversations
|
|
||||||
|
|
@ -1,425 +0,0 @@
|
||||||
# Closer Question Schema
|
|
||||||
|
|
||||||
## Purpose
|
|
||||||
|
|
||||||
This document defines the JSON schema, question types, validation rules, and required counts for Closer question packs.
|
|
||||||
|
|
||||||
For writing philosophy and tone, see `QUESTION_CONTENT_GUIDE.md`.
|
|
||||||
For the active rewrite checklist and category order, see `QUESTION_REWRITE_PLAN.md`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# 1. Question Types
|
|
||||||
|
|
||||||
## multi_choice
|
|
||||||
|
|
||||||
Select every option that applies.
|
|
||||||
|
|
||||||
Primary question type. At least 75% of all questions must be choice-based (multi_choice + choice).
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"type": "multi_choice",
|
|
||||||
"text": "What helps you feel relaxed on a date with me?",
|
|
||||||
"options": [
|
|
||||||
{ "id": "no_rushing", "text": "Not feeling rushed" },
|
|
||||||
{ "id": "phones_away", "text": "Putting phones away" },
|
|
||||||
{ "id": "good_food", "text": "Good food" },
|
|
||||||
{ "id": "easy_conversation", "text": "Easy conversation" },
|
|
||||||
{ "id": "physical_affection", "text": "Physical affection" },
|
|
||||||
{ "id": "clear_plan", "text": "Having a plan" }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Rules:
|
|
||||||
|
|
||||||
- Prompt should clearly allow multiple answers.
|
|
||||||
- Options should not shame either partner.
|
|
||||||
- Include practical and emotional options when possible.
|
|
||||||
|
|
||||||
## choice
|
|
||||||
|
|
||||||
Pick the single best answer.
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"type": "choice",
|
|
||||||
"text": "Which kind of date sounds best this week?",
|
|
||||||
"options": [
|
|
||||||
{ "id": "cozy_at_home", "text": "Cozy at home" },
|
|
||||||
{ "id": "dinner_out", "text": "Dinner out" },
|
|
||||||
{ "id": "something_playful", "text": "Something playful" },
|
|
||||||
{ "id": "something_outside", "text": "Something outside" },
|
|
||||||
{ "id": "surprise_me", "text": "Surprise me" }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Rules:
|
|
||||||
|
|
||||||
- Options should be short.
|
|
||||||
- Options should not overlap too much.
|
|
||||||
- Options should sound like real choices.
|
|
||||||
- Use 4 to 6 options.
|
|
||||||
|
|
||||||
## scale
|
|
||||||
|
|
||||||
Rate agreement, comfort, importance, confidence, or frequency.
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"type": "scale",
|
|
||||||
"text": "How much do you feel like we need a real date soon?",
|
|
||||||
"scale": {
|
|
||||||
"min": 1,
|
|
||||||
"max": 5,
|
|
||||||
"min_label": "Not much",
|
|
||||||
"max_label": "Very much"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Rules:
|
|
||||||
|
|
||||||
- Scale labels should be gentle and neutral.
|
|
||||||
- Do not make the low end sound bad or shameful.
|
|
||||||
- Scale questions should measure one thing only.
|
|
||||||
|
|
||||||
Bad:
|
|
||||||
|
|
||||||
```
|
|
||||||
How badly are we failing at making time for each other?
|
|
||||||
```
|
|
||||||
|
|
||||||
Better:
|
|
||||||
|
|
||||||
```
|
|
||||||
How much would some intentional time together help us right now?
|
|
||||||
```
|
|
||||||
|
|
||||||
## either_or
|
|
||||||
|
|
||||||
Very fast playful questions. Should take under three seconds.
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"type": "either_or",
|
|
||||||
"text": "Planned date or spontaneous date?"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Rules:
|
|
||||||
|
|
||||||
- Prompts should be quick.
|
|
||||||
- Avoid choices that imply one partner is wrong.
|
|
||||||
- Best used in fun, date, intimacy, home, and lifestyle packs.
|
|
||||||
|
|
||||||
## written
|
|
||||||
|
|
||||||
Reserved for questions where a short written response adds meaningful value.
|
|
||||||
|
|
||||||
Never use written questions for basic preferences.
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"type": "written",
|
|
||||||
"text": "What is one small thing I do that makes you feel cared for?"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Good written examples:
|
|
||||||
|
|
||||||
```
|
|
||||||
What is one small thing I do that makes you feel cared for?
|
|
||||||
What is a memory of us that still makes you smile?
|
|
||||||
What is something you wish we made more time for?
|
|
||||||
```
|
|
||||||
|
|
||||||
Avoid written questions that are too vague:
|
|
||||||
|
|
||||||
```
|
|
||||||
How can we deepen our connection?
|
|
||||||
```
|
|
||||||
|
|
||||||
Better:
|
|
||||||
|
|
||||||
```
|
|
||||||
What is one thing we could do this week that would make us feel more like a team?
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# 2. Required Counts
|
|
||||||
|
|
||||||
Every 250-question pack must contain:
|
|
||||||
|
|
||||||
| Type | Count | Percent |
|
|
||||||
|---|---|---|
|
|
||||||
| multi_choice | 140 | 56% |
|
|
||||||
| choice | 50 | 20% |
|
|
||||||
| scale | 35 | 14% |
|
|
||||||
| either_or | 15 | 6% |
|
|
||||||
| written | 10 | 4% |
|
|
||||||
|
|
||||||
At least 75% of all questions must be choice-based (multi_choice + choice).
|
|
||||||
|
|
||||||
Written questions should be rare and only used when typing creates a better conversation.
|
|
||||||
|
|
||||||
## Free vs Premium
|
|
||||||
|
|
||||||
| Access | Count |
|
|
||||||
|---|---|
|
|
||||||
| free | 75 |
|
|
||||||
| premium | 175 |
|
|
||||||
|
|
||||||
## Depth
|
|
||||||
|
|
||||||
Valid depth values:
|
|
||||||
|
|
||||||
- light
|
|
||||||
- medium
|
|
||||||
- deep
|
|
||||||
|
|
||||||
## Access
|
|
||||||
|
|
||||||
Valid access values:
|
|
||||||
|
|
||||||
- free
|
|
||||||
- premium
|
|
||||||
|
|
||||||
## Category Access
|
|
||||||
|
|
||||||
Valid category access values:
|
|
||||||
|
|
||||||
- free
|
|
||||||
- premium
|
|
||||||
- mixed
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# 3. JSON Structure
|
|
||||||
|
|
||||||
## Category metadata
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"id": "date_night",
|
|
||||||
"title": "Date Night",
|
|
||||||
"access": "mixed",
|
|
||||||
"description": "Plan, enjoy, and remember time together.",
|
|
||||||
"count": 250,
|
|
||||||
"free_count": 75,
|
|
||||||
"premium_count": 175,
|
|
||||||
"questions": []
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Question object
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"id": "dn_001",
|
|
||||||
"type": "multi_choice",
|
|
||||||
"text": "What helps you feel relaxed on a date with me?",
|
|
||||||
"depth": "medium",
|
|
||||||
"access": "free",
|
|
||||||
"sex": "neutral",
|
|
||||||
"options": [
|
|
||||||
{ "id": "no_rushing", "text": "Not feeling rushed" },
|
|
||||||
{ "id": "phones_away", "text": "Putting phones away" },
|
|
||||||
{ "id": "good_food", "text": "Good food" },
|
|
||||||
{ "id": "easy_conversation", "text": "Easy conversation" },
|
|
||||||
{ "id": "physical_affection", "text": "Physical affection" },
|
|
||||||
{ "id": "clear_plan", "text": "Having a plan" }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Scale question object
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"id": "dn_042",
|
|
||||||
"type": "scale",
|
|
||||||
"text": "How much do you feel like we need a real date soon?",
|
|
||||||
"depth": "medium",
|
|
||||||
"access": "free",
|
|
||||||
"sex": "neutral",
|
|
||||||
"scale": {
|
|
||||||
"min": 1,
|
|
||||||
"max": 5,
|
|
||||||
"min_label": "Not much",
|
|
||||||
"max_label": "Very much"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Either/or question object
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"id": "dn_089",
|
|
||||||
"type": "either_or",
|
|
||||||
"text": "Planned date or spontaneous date?",
|
|
||||||
"depth": "light",
|
|
||||||
"access": "free",
|
|
||||||
"sex": "neutral"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Written question object
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"id": "dn_113",
|
|
||||||
"type": "written",
|
|
||||||
"text": "What is one date we should bring back?",
|
|
||||||
"depth": "medium",
|
|
||||||
"access": "premium",
|
|
||||||
"sex": "neutral"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# 4. Validation Rules
|
|
||||||
|
|
||||||
Every rewritten pack must pass:
|
|
||||||
|
|
||||||
- Valid JSON
|
|
||||||
- 250 questions
|
|
||||||
- 75 free
|
|
||||||
- 175 premium
|
|
||||||
- 140 multi_choice
|
|
||||||
- 50 choice
|
|
||||||
- 35 scale
|
|
||||||
- 15 either_or
|
|
||||||
- 10 written
|
|
||||||
- Valid depth values only (light, medium, deep)
|
|
||||||
- Valid access values only (free, premium)
|
|
||||||
- Valid type values only (multi_choice, choice, scale, either_or, written)
|
|
||||||
- Valid sex values only (neutral, female, male)
|
|
||||||
- No duplicate question IDs
|
|
||||||
- No duplicate question texts
|
|
||||||
- No near-duplicate blocks
|
|
||||||
- No malformed keys
|
|
||||||
- No placeholder text
|
|
||||||
- No therapy worksheet tone
|
|
||||||
- Options have unique IDs inside each question
|
|
||||||
- Option IDs are neutral and clean
|
|
||||||
- Scale labels are present when needed
|
|
||||||
- Every category contains fun, curiosity, and meaningful conversations
|
|
||||||
|
|
||||||
## JSON Quality Checklist
|
|
||||||
|
|
||||||
- [ ] Valid JSON.
|
|
||||||
- [ ] Category id matches file purpose.
|
|
||||||
- [ ] Category title sounds user-facing.
|
|
||||||
- [ ] Category access matches actual free/premium strategy.
|
|
||||||
- [ ] Metadata counts match actual question counts.
|
|
||||||
- [ ] All question IDs are unique.
|
|
||||||
- [ ] All question texts are unique.
|
|
||||||
- [ ] No near-duplicate blocks.
|
|
||||||
- [ ] Type counts match metadata.
|
|
||||||
- [ ] Free/premium counts match metadata.
|
|
||||||
- [ ] Depth values are valid.
|
|
||||||
- [ ] Access values are valid.
|
|
||||||
- [ ] Options have unique IDs inside each question.
|
|
||||||
- [ ] Option IDs are neutral and clean.
|
|
||||||
- [ ] Scale labels are present when needed.
|
|
||||||
- [ ] No malformed keys like m a x _ l e n g t h.
|
|
||||||
- [ ] No placeholder text.
|
|
||||||
- [ ] No accidental old gendered IDs unless intentionally used.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# 5. Subtopic Planning
|
|
||||||
|
|
||||||
Each pack should have subtopics to prevent repetition.
|
|
||||||
|
|
||||||
Example for Date Night:
|
|
||||||
|
|
||||||
- easy dates
|
|
||||||
- low-cost dates
|
|
||||||
- at-home dates
|
|
||||||
- going out
|
|
||||||
- planning preferences
|
|
||||||
- romance style
|
|
||||||
- fun and play
|
|
||||||
- food and drinks
|
|
||||||
- music and movies
|
|
||||||
- seasonal dates
|
|
||||||
- surprises
|
|
||||||
- feeling wanted
|
|
||||||
- getting out of a rut
|
|
||||||
- after-kids / busy life
|
|
||||||
- date-night stress
|
|
||||||
- memories
|
|
||||||
- future date dreams
|
|
||||||
|
|
||||||
Example for Boundaries:
|
|
||||||
|
|
||||||
- alone time
|
|
||||||
- phone privacy
|
|
||||||
- social media
|
|
||||||
- family involvement
|
|
||||||
- friendships
|
|
||||||
- money
|
|
||||||
- work time
|
|
||||||
- rest
|
|
||||||
- chores
|
|
||||||
- home space
|
|
||||||
- conflict
|
|
||||||
- tone of voice
|
|
||||||
- physical affection
|
|
||||||
- private conversations
|
|
||||||
- parenting/family roles
|
|
||||||
- emotional bandwidth
|
|
||||||
- plans and scheduling
|
|
||||||
- personal belongings
|
|
||||||
- sleep
|
|
||||||
- stress
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# 6. Repetition Check
|
|
||||||
|
|
||||||
A pack fails if it has blocks like this:
|
|
||||||
|
|
||||||
```
|
|
||||||
What boundary around alone time would help you feel respected?
|
|
||||||
What boundary around phone privacy would help you feel respected?
|
|
||||||
What boundary around family involvement would help you feel respected?
|
|
||||||
What boundary around friendships would help you feel respected?
|
|
||||||
```
|
|
||||||
|
|
||||||
Instead, each question should have its own angle.
|
|
||||||
|
|
||||||
Better:
|
|
||||||
|
|
||||||
```
|
|
||||||
When you need alone time, how should I respond so it does not feel personal?
|
|
||||||
What phone privacy boundary would help us feel trusted instead of watched?
|
|
||||||
How involved should family be in decisions that affect just the two of us?
|
|
||||||
What helps friendships feel healthy without making our relationship feel pushed aside?
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# 7. Content Batching Process
|
|
||||||
|
|
||||||
Do not write all 250 questions in one creative pass.
|
|
||||||
|
|
||||||
Use this process:
|
|
||||||
|
|
||||||
1. Define pack purpose.
|
|
||||||
2. Define subtopics.
|
|
||||||
3. Write 40-50 high-quality questions.
|
|
||||||
4. Review tone and repetition.
|
|
||||||
5. Write the next batch.
|
|
||||||
6. Add choice, scale, and this-or-that questions.
|
|
||||||
7. Assign free/premium.
|
|
||||||
8. Assign depth.
|
|
||||||
9. Validate JSON.
|
|
||||||
10. Read the full file like a user.
|
|
||||||
Loading…
Reference in New Issue