174 lines
7.4 KiB
Markdown
174 lines
7.4 KiB
Markdown
# Question Authoring Guide (for AI agents)
|
|
|
|
How to create or extend a question set for the calm family quiz **without
|
|
touching code, state, or UI**. Question sets are pure data files.
|
|
|
|
> You are a bounded worker. Read [AGENTS.md](../../../AGENTS.md) and
|
|
> [autonomous-agent-harness.md](autonomous-agent-harness.md) first. This guide
|
|
> covers **content data only**. Do not change UI components, the game store, the
|
|
> types (beyond what content needs — usually nothing), or add backend / auth /
|
|
> editor / multiplayer unless your task explicitly asks.
|
|
|
|
## TL;DR workflow
|
|
|
|
1. Create `src/lib/question-sets/<name>.ts` exporting a `QuestionSet`.
|
|
2. Register it in `src/lib/question-sets/index.ts` (import + add to the
|
|
`questionSets` array).
|
|
3. Run `npm run check` to confirm types compile.
|
|
4. (Only if your task asks) smoke-test in the browser with `npm run dev`.
|
|
|
|
The selector screen lists sets from `questionSets` automatically — no UI edit
|
|
needed.
|
|
|
|
## Hard structure rules (non-negotiable)
|
|
|
|
Every set must match this shape **exactly**:
|
|
|
|
- **Exactly 5 categories** per set (`set.categories.length === 5`).
|
|
- **Exactly 5 questions** per category.
|
|
- **Fixed point values per category, in order:** `100, 200, 300, 500, 1000`.
|
|
- These values come from `POINT_VALUES` in `src/lib/types.ts`. Never invent
|
|
other numbers (no 400, no 750).
|
|
|
|
## Exact data shape
|
|
|
|
Mirror of `Question` / `Category` / `QuestionSet` in `src/lib/types.ts`:
|
|
|
|
```ts
|
|
import type { QuestionSet } from '$lib/types';
|
|
|
|
export const mySet: QuestionSet = {
|
|
id: 'my-set', // globally unique, kebab-case, stable forever
|
|
title: 'Моя тема',
|
|
description: 'Короткое тёплое описание.',
|
|
ageRange: '6+ лет',
|
|
categories: [
|
|
{
|
|
id: 'cat-1', // unique WITHIN this set, stable
|
|
title: 'Категория',
|
|
questions: [
|
|
{ id: 'q1', points: 100, question: '…', answer: '…', type: 'strict' },
|
|
{ id: 'q2', points: 200, question: '…', answer: '…', optionalHint: '…', type: 'strict' },
|
|
{ id: 'q3', points: 300, question: '…', answer: '…', type: 'strict' },
|
|
{ id: 'q4', points: 500, question: '…', answer: '…', type: 'creative' },
|
|
{ id: 'q5', points: 1000, question: '…', answer: '…', type: 'strict' }
|
|
]
|
|
}
|
|
// …4 more categories (5 total)
|
|
]
|
|
};
|
|
```
|
|
|
|
## Unique ids (stability matters)
|
|
|
|
- `set.id` — unique across **all** sets (e.g. `animals`, `cozy`, `space`).
|
|
Lowercase kebab-case. It is persisted in `localStorage`, so never rename it
|
|
after release.
|
|
- `category.id` — unique **within the set**. Stable. Used in the played-question
|
|
key `categoryId:questionId`.
|
|
- `question.id` — unique **within the category** (typically `q1..q5`). Stable.
|
|
|
|
Changing any id after release breaks saved progress for players mid-game. Treat
|
|
ids as immutable once shipped.
|
|
|
|
## Difficulty progression (100 → 1000)
|
|
|
|
Within each category, questions run simple → hard. The number only labels it;
|
|
the **wording** carries the difficulty:
|
|
|
|
- **100** — obvious warm-up; most answer instantly.
|
|
- **200** — easy; may need a second's thought.
|
|
- **300** — solid mid-level.
|
|
- **500** — needs real knowledge or reasoning.
|
|
- **1000** — the hard capstone; satisfying to land.
|
|
|
|
## Question type: `strict` vs `creative`
|
|
|
|
From `QuestionType` in `src/lib/types.ts`:
|
|
|
|
- `strict` — there is one correct answer. Host button reads «Засчитать».
|
|
Use for facts: «Какое животное…?», «Где живут белые медведи?».
|
|
- `creative` — open-ended, many acceptable answers. Host button reads
|
|
«Засчитать творческий ответ» (softer framing, no "wrong" feeling). Use for
|
|
imagination prompts: «Придумай…», «Опиши…».
|
|
|
|
A category of facts is mostly/entirely `strict`; a category of imagination is
|
|
mostly/entirely `creative`. A set can mix freely. The example sets
|
|
(`animals.ts`, `cozy.ts`) keep roughly one `creative` category per set for
|
|
balance.
|
|
|
|
## `optionalHint` — scaffold, don't reveal
|
|
|
|
`optionalHint?: string` is an optional nudge the host can show on demand.
|
|
|
|
- **Why it costs points:** showing a hint means the answer can then only be
|
|
awarded at **half** value (see Boundaries). So it's a fair, pressure-free
|
|
trade — omit it whenever no scaffold genuinely helps.
|
|
- **Do** point at a category, sense, rhyme, or well-known association:
|
|
- «Его часто называют царём зверей.» (for «Лев»)
|
|
- «Мама у него — кобыла, а папа — жеребец.» (for «Жеребёнок»)
|
|
- **Don't** restate or obviously give away the answer:
|
|
- ❌ «Это лев.»
|
|
- ❌ «Ответ начинается на букву „Л“.»
|
|
- **For `creative` questions**, the hint can loosen imagination instead of
|
|
narrowing it («Чем нелепее и добрее — тем лучше.»).
|
|
- Keep it to **one short sentence**. Omit the field entirely when no scaffold
|
|
helps — it is genuinely optional.
|
|
|
|
## Tone: calm, warm, Russian, family-friendly
|
|
|
|
All user-facing text (`title`, `description`, `question`, `answer`,
|
|
`optionalHint`) is in **Russian** and must stay calm and family-safe:
|
|
|
|
- Soft, friendly phrasing; no words implying timers, pressure, or rush.
|
|
- No scary, crude, political, or adult content.
|
|
- Friendly to kids and grandparents together; avoid slang that ages badly.
|
|
- Match the cozy register of the existing sets (`animals.ts`, `cozy.ts`).
|
|
|
|
When unsure, read the existing sets and mirror their voice. Aim for a warm
|
|
bedtime-evening mood.
|
|
|
|
## Register the set
|
|
|
|
In `src/lib/question-sets/index.ts`:
|
|
|
|
```ts
|
|
import { mySet } from './my-set';
|
|
export const questionSets = [animalsSet, cozySet, mySet];
|
|
```
|
|
|
|
Order in the array is the order on the selector screen — new sets usually go
|
|
last.
|
|
|
|
## Validation checklist (run before reporting done)
|
|
|
|
- [ ] File is `src/lib/question-sets/<name>.ts`; its export is a `QuestionSet`.
|
|
- [ ] `set.id` is unique across all sets and kebab-case.
|
|
- [ ] Exactly 5 categories; each `category.id` unique within the set.
|
|
- [ ] Exactly 5 questions per category; each `question.id` unique within its category.
|
|
- [ ] Each category's points are exactly `100, 200, 300, 500, 1000` in order.
|
|
- [ ] Every question has `type` of `strict` or `creative`.
|
|
- [ ] `optionalHint` (if present) scaffolds without revealing the answer; ≤ 1 sentence.
|
|
- [ ] All copy is Russian, calm, family-friendly; matches the existing sets' tone.
|
|
- [ ] Set is imported and added to `questionSets` in `index.ts`.
|
|
- [ ] `npm run check` passes (types + svelte-check).
|
|
|
|
## Boundaries — do NOT (unless your task explicitly says so)
|
|
|
|
- Add backend, database, auth, accounts, or multiplayer.
|
|
- Add a question editor UI or any new component / route.
|
|
- Edit the game store (`src/lib/stores/game.ts`) or the `GameState` shape.
|
|
- Change scoring, hint, or partial-credit mechanics — they already exist and are
|
|
fixed by the UI/state contract:
|
|
- Full points: host «Засчитать +N».
|
|
- Half points: host «Засчитать частично +N/2» (shown only when the hint was
|
|
**not** revealed; `halfPoints = Math.round(points / 2)`).
|
|
- Hint revealed → the answer can only be awarded at half value, and the
|
|
partial-credit button is hidden.
|
|
- Refactor `src/lib/types.ts` beyond what content needs (usually nothing).
|
|
- Commit, push, deploy, or edit `AGENTS.md` and other files under
|
|
`development/_reference/ai/`.
|
|
|
|
If a needed change falls outside these boundaries, stop and report it; do not
|
|
expand scope on your own.
|