Prototype Constraints
Non-obvious rules that aren't visible from screenshots. Same content lives in README.md.
Generator: Upload flow
- Accepted file types: .docx, .pdf, .txt. Max 10 MB.
- Paste textarea: max 50,000 characters. TODO: confirm with stakeholder.
- Empty submit rejected with copy: "Upload a file or paste BIP text to continue."
- The prototype ignores the file/paste content and returns the same canned schema payload (Jamie's BIP) — per §6 the AI is mocked.
Generator: Wizard flow
- 11 steps. Step 11 ("About the learner") is optional — every other step is required and gates rail-reachability of later steps.
- Per-step char limits (enforced server-side, surfaced in the UI):
- Step 1 (cover): child name 50 chars, subtitle 80 chars.
- Step 2 (behavior): target behavior + baseline data, each 500 chars.
- Step 3 (triggers): 500 chars.
- Step 4 (function): four checkboxes; any combination allowed.
- Step 5 (replacement skill): radio + optional "Other" textarea (200 chars).
- Step 6 (teaching strategies): checkbox group, no cap.
- Step 7 (proactive supports): 300 chars.
- Step 8 (rewards): 400 chars.
- Step 9 (optional): 4 textareas about the learner, 200 chars each. Skippable via "Skip this step".
- Step 10 (response plan): checkbox group, max 2 selected (`group_max: 2`).
- Answers persist in session across steps. Refreshing mid-wizard keeps prior answers.
- Wizard answers are assembled into a structured prompt and fed to OpenAI
AiClient.generate_bip; seeapp.rb#assemble_wizard_input.
Generator: Suggestions screen
- The AI's suggestion stream surfaces strategies the BIP is missing — BCBA accepts (Add to BIP) or rejects (Skip) each.
- Each suggestion has an editable title (max 60 chars), editable description (max 225 chars), and editable section (single-select from 4 BIP sections).
- BCBA's edited title + description fully replace the library defaults when accepted.
- Section caps (server-side enforced, defined in
SUGGESTION_SECTIONS):teach_what_and_how.what_to_teach: max 1teach_what_and_how.how_to_teach: max 3prevent.how_to_prevent: max 6teach_reward.how_to_reward: max 3reward_and_respond.how_to_reward: max 3reward_and_respond.how_to_respond: max 2
- Overflow (accepted into a full section) silently rolls into the next available section; the swap is logged via
warn. - If the AI returns zero suggestions, the screen redirects directly to handoff (no empty-state visible).
Schema-enforced caps (from bip_ai_generation_schema.md)
cover.title≤ 50 chars;cover.subtitle≤ 80 chars (optional).about_the_learner.*≤ 100 chars each, all 10 fields optional.target_behavior.target_behavior≤ 500 chars.target_behavior.baseline_data≤ 500 chars.target_behavior.replacement_behavior_goalsandbehavior_reduction_goals: max 4 items each, ≤ 200 chars.target_behavior.function: all 4 keys (attention/escape/access/sensory) always present.teach_what_and_how.what_to_teach: max 6 strategies.teach_what_and_how.how_to_teach: max 3 strategies.teach_reward.when_to_reward≤ 800 chars.teach_reward.how_to_reward: max 3 strategies.teach_reward.how_to_respond_to_withdrawal_of_assent: max 3 strategies.prevent.when_to_prevent≤ 200 chars.prevent.how_to_prevent: max 9 strategies.reward_and_respond.how_to_reward: max 6 strategies.reward_and_respond.how_to_respond: max 3 strategies.resources_and_courses: max 12 IDs.- Strategy custom
title≤ 60 chars;description≤ 225 chars.
AI behavior contract
- All Strategy IDs returned by the AI must reference
strategies.json. Unknown IDs →api_errorstate. Currently: TODO confirm production-side error handling. - All Resource IDs must reference the resource library (currently mocked at
data/resource-cards.js). - Array ordering is significant. The seed loader preserves the order received.
- TODO: confirm with stakeholder — what happens when the AI returns invalid JSON?
- TODO: confirm with stakeholder — AI proposes a custom
title/descriptionthat exceeds 60/225 chars: truncate, reject, or surface a form error?
Plan gating
- Free users can generate 1 BIP per time frame. After they've used their credit, the Generator routes show the permission-denied state with an upgrade CTA.
- TODO: confirm time frame (per day/week/month) and credit-refresh model.
- TODO: confirm credit-based future model — do Pro users get unlimited or a higher cap?
- Toggle
?plan=free+?state=permissionin the banner above to preview the gate.
Generator → Builder handoff
- Sinatra writes the schema-conformant JSON payload to
sessionStorageunder keybip-seed, then redirects to/builder(the existing Vite Builder served at the same origin). - The Vite Builder reads
sessionStorage.bip-seedon init viadata/seed-loader.js, maps the schema fields to the existingappStateshape, and clears the seed so reloads don't re-apply. - Same-origin requirement: Sinatra mounts
index.html,script.js,style.css,data/*.js, andviews/*.jsatlocalhost:9292. The Vite dev server is not used at runtime.
Required-state coverage matrix
Per prototyping_CLAUDE.md §8, every screen supports six required states: default, loading, empty, form_errors, api_error, permission. Toggle via the prototype banner or by appending ?state=<name> to the URL.
Cells: ✓ = implemented, n/a = not applicable for the screen (no form / no list / no data fetch), — = not yet implemented.
| Screen | default | loading | empty | form_errors | api_error | permission |
|---|---|---|---|---|---|---|
/ (entry) |
✓ | n/a | n/a | n/a | ✓ | ✓ |
/generator/import |
✓ | ✓ | n/a | ✓ | ✓ | ✓ |
/generator/wizard/1..11 |
✓ | ✓ | n/a | ✓ | ✓ | ✓ |
/generator/generating |
✓ | is loading | n/a | n/a | ✓ | n/a |
/generator/suggestions |
✓ | ✓ | n/a* | ✓ | ✓ | ✓ |
/generator/handoff |
✓ | n/a | n/a | n/a | ✓ | n/a |
| Mini BIP Page 1 (Vite Builder) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Mini BIP Page 2 (Vite Builder) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
* Suggestions empty: when the AI returns zero demoted entries, the route redirects directly to /generator/handoff rather than rendering an empty list. Effectively the empty state is "no screen rendered" — the user never sees the suggestions page.
Vite Builder mini-BIP pages: the Vite Builder has no prototype banner; state is URL-driven only — append ?state=loading, ?state=empty, etc. directly to /builder?state=<name>. The state applies to whichever page is currently shown in the page viewer (state is read on every render). form_errors on these read-only pages renders an explanatory banner above the chrome; the pages don't accept form input in reality.
Other Vite Builder pages (Cover, About the Learner, Behavior Overview, Teach: What & How, Teach: Reward, Prevent, Reward & Respond, Resources & Courses) inherit the legacy "default-only" pattern — they have no required-state branches today. Not in scope for this audit pass; tracked as follow-up.