Railspike Step 2: Feature Description
File: docs/plans/mobile_compose_keyboard_step2_feature_description.md (in the v3 repo, uncommitted)
Debug mode: enabled (corrected from Step 1's provisional "disabled": `.railspike_debug_on` was already present at the repository root when this workflow began, and Step 1 was written without repository access)
Effort study: `v3/mobile_compose_keyboard` · [ledger](./effort_estimation_trial.md#cycle-v3mobile_compose_keyboard)
Extended estimates: enabled
**Cycle estimate: 0.40**
## Problem
On the dedicated `/compose/thread` page on a phone, focusing the text area brings up the keyboard and pushes Post out of view, because the text area has a fixed 7-row height and the tag control sits between it and Post. The homepage's compact composer doesn't have this problem.
## User stories
- As a member writing a new post on a small phone, I want the text area and Post to stay on screen while the keyboard is open so that I can see what I'm typing and send it without scrolling hunts.
- As a member who wants tags, I want the tag control below Post so that it's there when I need it without crowding the main action.
- As a member on a larger screen or with the keyboard closed, I want the text area to use the space available so that the page doesn't feel cramped.
## Core requirements
- With the on-screen keyboard open on `/compose/thread`, the text area shrinks to the space above the keyboard after the title and the Post row, and the caret line and the Post button both stay visible while typing, including long drafts. When the keyboard closes, the layout returns without a jump.
- Order on the dedicated form: title, text area, Post row (with the "..." menu), then tags (and event, when enabled). Field names, values, submit, signing, drafts, anonymous posting, Outbox and attachments behave as today.
- The page looks right on first paint. Without JavaScript, or when no keyboard is detected (desktop, hardware keyboard), the form uses the ordinary flow with the new order and Post reachable.
- Compact composers (homepage/board, QDB add) and reply composers keep their current behavior.
## Delivery scope and completion boundary
**Work type:** application change. Covers the full thread composer on `/compose/thread`, plus the paned new-thread dialog, which renders the same full form (`compact => false`); board, board list and QDB add use the compact form and are unaffected. Excludes the theme overflow issues (separate request below), reply and private-message composers, and deployment.
Completion: from the ordinary New post tab, the member types a post with the keyboard open, presses Post, and gets exactly one thread. Validation or signing errors keep the draft and show the message with Post still reachable for retry. Release needs automated browser checks at phone sizes in all 13 themes and the maintainer's iPhone SE result; device acceptance stays recorded as pending until then.
## Known user and environment
Ilya on an iPhone SE (3rd gen) in Firefox (and Safari to confirm WebKit), opening New post from the bottom tab bar. Failure to handle: the keyboard covers Post. Next action unaided: keep typing; Post stays visible above the keyboard, and tapping it publishes. To verify, he sees the new thread open, or on error sees the message and Post still visible and retries without retyping. Evidence: a note in the Step 4 summary with device, iOS and browser versions and the result. Headless WebKit can't open a keyboard, so it doesn't count as this evidence.
## Risks
- **Keyboard detection on iOS Firefox:** the existing heuristic in `reply_viewport.js` treats the keyboard as open when the visible height drops below 75% of the tallest seen. Earliest check: log visualViewport heights on the SE in Firefox and Safari before Step 3. Mitigation: reuse the reply composer's detection rather than a second implementation, and keep the ordinary-flow fallback.
- **Shared composer partial:** moving tags in `composer.php` changes every full thread composer. Checked: only the compose page and the paned new-thread dialog render the full form; board, board list and QDB add pass `compact => true`. Mitigation: gate the new order on the full composer only.
- **Too little space:** on the SE with a long title or an error message open, the text area may get only a few lines. Mitigation: set a minimum text area height and let the page scroll as a fallback rather than hide controls.
- **First-paint shift:** a script-sized text area could jump after load. Mitigation: size only while the keyboard is up, never on initial render.
## Shared component inventory
- `templates/partials/composer.php`: extend (order of tools and actions for the full thread composer). Canonical composer for every form.
- `templates/partials/thread_compose_form.php`, `templates/pages/compose_thread.php`: reuse; options only if needed.
- `public/assets/reply_viewport.js`: reuse its keyboard detection for the thread composer (extend or factor out the shared part) instead of writing new viewport code. It already docks the reply composer above the keyboard.
- `public/assets/compose.css`: extend for the keyboard-up sizing and the new order.
- No new API, schema or dependency.
## Simple user flow
1. Tap New post in the bottom tab bar.
2. Optionally type a title, then tap the text area; the keyboard opens.
3. The text area shrinks to fit; Post stays visible below it.
4. Type; the caret and Post stay visible as the draft grows.
5. Optionally close the keyboard and open tags below Post.
6. Tap Post; the new thread opens (or an error shows with the draft kept and Post visible).
## Success criteria
- On the iPhone SE in Firefox and Safari with the keyboard open, Post and the caret line are visible while typing a 1-line and a 30-line draft (maintainer check).
- In headless WebKit at 375 x 300 with keyboard-up state applied, Post's bottom edge is inside the visible area in all 13 themes; at 375 x 667, nothing overflows horizontally.
- Tags render below the Post row on `/compose/thread`; compact board, QDB and reply composers render as before.
- Existing compose, signing, Outbox, attachment and image browser tests pass.
## Enhancement Requests
- **Request:** Word 97 / Midnight phone overflow and Sticker / Arena Post padding at 375px. **Disposition and reason:** separate work; different cause (theme chrome vs. keyboard). **Approval status:** pending. **Follow-up:** separate thread or cycle on request.
## Effort snapshot
2026-10-31T06:05Z · Step 2 handoff · cycle `v3/mobile_compose_keyboard` · scope v1 (Option B as above, baseline `63f0849691902e665506ad4f23f374353a32ae78`) · reference R1 (three hashes verified) · protocol P2 · rater Claude, single exposed rater (saw R1 feedback scores and calibration examples, and inspected the composer, `reply_viewport.js` and related plans before rating) · **0.40 projected total**. Reason: the composer is already shared and the reply composer already solves keyboard docking, so this is mostly reuse plus a reorder; the 13-theme check and phone acceptance keep it above the smallest references. Compare `v3/ui_tab_bar_scroll_away` (0.45) and composer decluttering (0.60). Intake and Step 1 missing, not backfilled.
## Approval
Reply "Approved Step 2" (or send changes) and I'll write Step 3.
*— Claude · 2026-10-31 UTC · Model: Claude Opus 5.5*
#meta #bug #railspike
#
File: docs/plans/mobile_compose_keyboard_step2_feature_description.md (in the v3 repo, uncommitted)
Debug mode: enabled (corrected from Step 1's provisional "disabled": `.railspike_debug_on` was already present at the repository root when this workflow began, and Step 1 was written without repository access)
Effort study: `v3/mobile_compose_keyboard` · [ledger](./effort_estimation_trial.md#cycle-v3mobile_compose_keyboard)
Extended estimates: enabled
**Cycle estimate: 0.40**
## Problem
On the dedicated `/compose/thread` page on a phone, focusing the text area brings up the keyboard and pushes Post out of view, because the text area has a fixed 7-row height and the tag control sits between it and Post. The homepage's compact composer doesn't have this problem.
## User stories
- As a member writing a new post on a small phone, I want the text area and Post to stay on screen while the keyboard is open so that I can see what I'm typing and send it without scrolling hunts.
- As a member who wants tags, I want the tag control below Post so that it's there when I need it without crowding the main action.
- As a member on a larger screen or with the keyboard closed, I want the text area to use the space available so that the page doesn't feel cramped.
## Core requirements
- With the on-screen keyboard open on `/compose/thread`, the text area shrinks to the space above the keyboard after the title and the Post row, and the caret line and the Post button both stay visible while typing, including long drafts. When the keyboard closes, the layout returns without a jump.
- Order on the dedicated form: title, text area, Post row (with the "..." menu), then tags (and event, when enabled). Field names, values, submit, signing, drafts, anonymous posting, Outbox and attachments behave as today.
- The page looks right on first paint. Without JavaScript, or when no keyboard is detected (desktop, hardware keyboard), the form uses the ordinary flow with the new order and Post reachable.
- Compact composers (homepage/board, QDB add) and reply composers keep their current behavior.
## Delivery scope and completion boundary
**Work type:** application change. Covers the full thread composer on `/compose/thread`, plus the paned new-thread dialog, which renders the same full form (`compact => false`); board, board list and QDB add use the compact form and are unaffected. Excludes the theme overflow issues (separate request below), reply and private-message composers, and deployment.
Completion: from the ordinary New post tab, the member types a post with the keyboard open, presses Post, and gets exactly one thread. Validation or signing errors keep the draft and show the message with Post still reachable for retry. Release needs automated browser checks at phone sizes in all 13 themes and the maintainer's iPhone SE result; device acceptance stays recorded as pending until then.
## Known user and environment
Ilya on an iPhone SE (3rd gen) in Firefox (and Safari to confirm WebKit), opening New post from the bottom tab bar. Failure to handle: the keyboard covers Post. Next action unaided: keep typing; Post stays visible above the keyboard, and tapping it publishes. To verify, he sees the new thread open, or on error sees the message and Post still visible and retries without retyping. Evidence: a note in the Step 4 summary with device, iOS and browser versions and the result. Headless WebKit can't open a keyboard, so it doesn't count as this evidence.
## Risks
- **Keyboard detection on iOS Firefox:** the existing heuristic in `reply_viewport.js` treats the keyboard as open when the visible height drops below 75% of the tallest seen. Earliest check: log visualViewport heights on the SE in Firefox and Safari before Step 3. Mitigation: reuse the reply composer's detection rather than a second implementation, and keep the ordinary-flow fallback.
- **Shared composer partial:** moving tags in `composer.php` changes every full thread composer. Checked: only the compose page and the paned new-thread dialog render the full form; board, board list and QDB add pass `compact => true`. Mitigation: gate the new order on the full composer only.
- **Too little space:** on the SE with a long title or an error message open, the text area may get only a few lines. Mitigation: set a minimum text area height and let the page scroll as a fallback rather than hide controls.
- **First-paint shift:** a script-sized text area could jump after load. Mitigation: size only while the keyboard is up, never on initial render.
## Shared component inventory
- `templates/partials/composer.php`: extend (order of tools and actions for the full thread composer). Canonical composer for every form.
- `templates/partials/thread_compose_form.php`, `templates/pages/compose_thread.php`: reuse; options only if needed.
- `public/assets/reply_viewport.js`: reuse its keyboard detection for the thread composer (extend or factor out the shared part) instead of writing new viewport code. It already docks the reply composer above the keyboard.
- `public/assets/compose.css`: extend for the keyboard-up sizing and the new order.
- No new API, schema or dependency.
## Simple user flow
1. Tap New post in the bottom tab bar.
2. Optionally type a title, then tap the text area; the keyboard opens.
3. The text area shrinks to fit; Post stays visible below it.
4. Type; the caret and Post stay visible as the draft grows.
5. Optionally close the keyboard and open tags below Post.
6. Tap Post; the new thread opens (or an error shows with the draft kept and Post visible).
## Success criteria
- On the iPhone SE in Firefox and Safari with the keyboard open, Post and the caret line are visible while typing a 1-line and a 30-line draft (maintainer check).
- In headless WebKit at 375 x 300 with keyboard-up state applied, Post's bottom edge is inside the visible area in all 13 themes; at 375 x 667, nothing overflows horizontally.
- Tags render below the Post row on `/compose/thread`; compact board, QDB and reply composers render as before.
- Existing compose, signing, Outbox, attachment and image browser tests pass.
## Enhancement Requests
- **Request:** Word 97 / Midnight phone overflow and Sticker / Arena Post padding at 375px. **Disposition and reason:** separate work; different cause (theme chrome vs. keyboard). **Approval status:** pending. **Follow-up:** separate thread or cycle on request.
## Effort snapshot
2026-10-31T06:05Z · Step 2 handoff · cycle `v3/mobile_compose_keyboard` · scope v1 (Option B as above, baseline `63f0849691902e665506ad4f23f374353a32ae78`) · reference R1 (three hashes verified) · protocol P2 · rater Claude, single exposed rater (saw R1 feedback scores and calibration examples, and inspected the composer, `reply_viewport.js` and related plans before rating) · **0.40 projected total**. Reason: the composer is already shared and the reply composer already solves keyboard docking, so this is mostly reuse plus a reorder; the 13-theme check and phone acceptance keep it above the smallest references. Compare `v3/ui_tab_bar_scroll_away` (0.45) and composer decluttering (0.60). Intake and Step 1 missing, not backfilled.
## Approval
Reply "Approved Step 2" (or send changes) and I'll write Step 3.
*— Claude · 2026-10-31 UTC · Model: Claude Opus 5.5*
#meta #bug #railspike