fluffychat/.github/instructions/choreographer.instructions.md
wcjord dec473d579
Writing assistance (#5598)
* feat: wa working full stack

* feat: writing assistance made anew

* docs: migrate copilot docs to .github/instructions/ format

- Create choreographer.instructions.md (applyTo: lib/pangea/choreographer/**)
- Create events-and-tokens.instructions.md (applyTo: lib/pangea/events/**,lib/pangea/extensions/**)
- Create modules.instructions.md (applyTo: lib/pangea/**) — full module map
- Track copilot-instructions.md (remove .gitignore rule)
- Add documentation reference table to copilot-instructions.md

Content sourced from docs/copilot/ on writing-assistance branch.

* docs: remove old docs/copilot/ (migrated to .github/instructions/)

* docs: update choreographer + modules docs for writing-assistance audit

- Mark IT (Interactive Translation) as deprecated throughout
- Document new ReplacementTypeEnum taxonomy (grammar, surface, word-choice categories)
- Add AssistanceStateEnum, AutocorrectPopup, feedback rerun flow
- Mark SpanDataRepo/span_details as dead code
- Mark SpanChoiceTypeEnum.bestCorrection/bestAnswer as deprecated
- Add new files to modules listing (autocorrect_popup, start_igc_button, etc.)
- Update API endpoints table with active/deprecated/dead status

* formatting, replace deprecated withOpacity calls

* fix linter issues from deprecated types

* use better error color

* move cloing of overlays into choreographer

* reduce duplicate code on igc_controller, update UI on feedback

* couple of adjustments

* display prompt in span card by type

* fix error in tests

* translations

* simplify span card feedback

---------

Co-authored-by: ggurdin <ggurdin@gmail.com>
2026-02-09 15:55:18 -05:00

161 lines
8.6 KiB
Markdown

---
applyTo: "lib/pangea/choreographer/**"
---
# Choreographer — Writing Assistance Flow
The choreographer is the client-side orchestrator for real-time writing assistance. It coordinates user text input, API calls to `/grammar_v2`, match display, and the creation of choreo records saved with sent messages.
> **⚠️ IT (Interactive Translation) is deprecated.** The `it/` directory, `ITController`, and `/it_initialstep` endpoint are still wired into the choreographer but are being phased out. IT will become just another match type returned by IGC. Do not add new IT functionality.
## Architecture
```
Choreographer (ChangeNotifier)
├── PangeaTextController ← Extended TextEditingController (tracks edit types)
├── IgcController ← Grammar check matches (primary flow)
├── ITController ← ⚠️ DEPRECATED — Translation step-by-step flow
├── ChoreographerErrorController ← Error state + backoff
└── ChoreographerStateExtension ← AssistanceStateEnum derivation
```
### Key files
| File | Purpose |
|---|---|
| `choreographer.dart` | Main orchestrator (ChangeNotifier) |
| `choreographer_state_extension.dart` | Derives `AssistanceStateEnum` from current state |
| `assistance_state_enum.dart` | UI states: noSub, noMessage, notFetched, fetching, fetched, complete, error |
| `choreo_mode_enum.dart` | `igc` (active) or `it` (⚠️ deprecated) |
| `choreo_record_model.dart` | Record of edits saved with message |
| `igc/igc_controller.dart` | IGC state management (437 lines) |
| `igc/replacement_type_enum.dart` | Granular match type taxonomy (grammar, surface, word-choice, etc.) |
| `igc/autocorrect_popup.dart` | Undo popup for auto-applied corrections |
| `text_editing/pangea_text_controller.dart` | Text controller with edit type tracking |
| `it/it_controller.dart` | ⚠️ DEPRECATED — IT state |
## Flow
### 1. User types → debounce → IGC request
1. User types in chat input. `PangeaTextController` fires `_onChange`.
2. After debounce (`ChoreoConstants.msBeforeIGCStart`), `requestWritingAssistance()` is called.
3. `IgcController.getIGCTextData()` calls `/grammar_v2` via `IgcRepo`.
4. Response contains a list of `SpanData` (matches) — grammar errors, out-of-target markers, normalization fixes.
5. Auto-apply matches (punct, diacritics, spell, cap) are accepted automatically via `acceptNormalizationMatches()`. Grammar/word-choice matches become `openMatches`.
### 2. Matches displayed → Span cards
1. Open matches render as colored underlines in the text field (colors set by `ReplacementTypeEnum.underlineColor()`).
2. Tapping a match opens a **span card** overlay (`span_card.dart`) showing the error category (`ReplacementTypeEnum.displayName()`), choices, and the error message.
3. Auto-applied corrections show an `AutocorrectPopup` with undo capability.
### 3. User resolves matches
Each match goes through `PangeaMatchState` with status transitions:
- `open``accepted` (user chose a replacement)
- `open``ignored` (user dismissed)
- `open``automatic` (auto-apply correction)
- Any → `undo` (user reverted)
When a match is accepted/ignored, the `IgcController` fires `matchUpdateStream`. The `Choreographer` listens and:
- Updates the text via `textController.setSystemText()`
- Records the step in `ChoreoRecordModel`
### 4. Feedback rerun
If the user is unsatisfied with results, `rerunWithFeedback(feedbackText)` re-calls IGC with user feedback and the previous request/response context (`_lastRequest`, `_lastResponse`).
### 5. Sending
On send, `Choreographer.getMessageContent()`:
1. Calls `/tokenize` to get `PangeaToken` data for the final text (with exponential backoff on errors).
2. Builds `PangeaMessageContentModel` containing:
- The final message text
- `ChoreoRecordModel` (full editing history)
- `PangeaRepresentation` for original written text (if IT was used)
- `PangeaMessageTokens` (token/lemma/morph data)
## AssistanceStateEnum
Derived in `choreographer_state_extension.dart`. Drives the send-button color and UI hints:
| State | Meaning |
|---|---|
| `noSub` | User has no active subscription |
| `noMessage` | Text field is empty |
| `notFetched` | Text entered but IGC hasn't run yet |
| `fetching` | IGC request in flight |
| `fetched` | Matches present — user needs to resolve them |
| `complete` | All matches resolved, ready to send |
| `error` | IGC error (backoff active) |
## ReplacementTypeEnum — Match Type Taxonomy
Defined in `igc/replacement_type_enum.dart`. Categories returned by `/grammar_v2`:
| Category | Types | Behavior |
|---|---|---|
| **Client-only** | `definition`, `practice`, `itStart` | Not from server; `itStart` triggers deprecated IT flow |
| **Grammar** (~21 types) | `verbConjugation`, `verbTense`, `verbMood`, `subjectVerbAgreement`, `genderAgreement`, `numberAgreement`, `caseError`, `article`, `preposition`, `pronoun`, `wordOrder`, `negation`, `questionFormation`, `relativeClause`, `connector`, `possessive`, `comparative`, `passiveVoice`, `conditional`, `infinitiveGerund`, `modal` | Orange underline, user must accept/ignore |
| **Surface corrections** | `punct`, `diacritics`, `spell`, `cap` | Auto-applied (no user interaction), undo via `AutocorrectPopup` |
| **Word choice** | `falseCognate`, `l1Interference`, `collocation`, `semanticConfusion` | Blue underline, user must accept/ignore |
| **Higher-level** | `transcription`, `style`, `fluency`, `didYouMean`, `translation`, `other` | Teal (style/fluency) or error color |
Key extension helpers: `isAutoApply`, `isGrammarType`, `isWordChoiceType`, `underlineColor()`, `displayName()`, `fromString()` (handles legacy snake_case and old type names like `grammar``subjectVerbAgreement`).
## Key Models
| Model | File | Purpose |
|---|---|---|
| `SpanData` | `igc/span_data_model.dart` | A match span (offset, length, choices, message, rule, `ReplacementTypeEnum`) |
| `PangeaMatch` | `igc/pangea_match_model.dart` | SpanData + status |
| `PangeaMatchState` | `igc/pangea_match_state_model.dart` | Mutable wrapper tracking original vs updated match state |
| `ChoreoRecordModel` | `choreo_record_model.dart` | Full editing history: steps, open matches, original text |
| `ChoreoRecordStepModel` | `choreo_edit_model.dart` | Single edit step (text before/after, accepted match) |
| `IGCRequestModel` | `igc/igc_request_model.dart` | Request to `/grammar_v2` |
| `IGCResponseModel` | `igc/igc_response_model.dart` | Response from `/grammar_v2` |
| `MatchRuleIdModel` | `igc/match_rule_id_model.dart` | Rule ID constants (⚠️ `tokenNeedsTranslation`, `tokenSpanNeedsTranslation`, `l1SpanAndGrammar` — not currently sent by server) |
| `AutocorrectPopup` | `igc/autocorrect_popup.dart` | Undo widget for auto-applied corrections |
## API Endpoints
| Endpoint | Repo File | Status |
|---|---|---|
| `/choreo/grammar_v2` | `igc/igc_repo.dart` | ✅ Active — primary IGC endpoint |
| `/choreo/tokenize` | `events/repo/tokens_repo.dart` | ✅ Active — tokenizes final text on send |
| `/choreo/span_details` | `igc/span_data_repo.dart` | ❌ Dead code — `SpanDataRepo` class is defined but never imported anywhere |
| `/choreo/it_initialstep` | `it/it_repo.dart` | ⚠️ Deprecated — IT flow |
| `/choreo/contextual_definition` | `contextual_definition_repo.dart` | ⚠️ Deprecated — only used by IT's `word_data_card.dart` |
## Edit Types (`EditTypeEnum`)
- `keyboard` — User typing
- `igc` — System applying IGC match
- `it` — ⚠️ Deprecated — System applying IT continuance
- `itDismissed` — ⚠️ Deprecated — IT dismissed, restoring source text
## Deprecated: SpanChoiceTypeEnum
In `igc/span_choice_type_enum.dart`:
- `bestCorrection``@Deprecated('Use suggestion instead')`
- `bestAnswer``@Deprecated('Use suggestion instead')`
- `suggestion` — Active replacement
## Error Handling
- IGC and token errors trigger exponential backoff (`_igcErrorBackoff *= 2`, `_tokenErrorBackoff *= 2`)
- Backoff resets on next successful request
- Errors surfaced via `ChoreographerErrorController`
- Error state exposed in `AssistanceStateEnum.error`
## ⚠️ Deprecated: Interactive Translation (IT)
> **Do not extend.** IT is being deprecated. Translation will become a match type within IGC.
The `it/` directory still contains `ITController`, `ITRepo`, `ITStepModel`, `CompletedITStepModel`, `GoldRouteTrackerModel`, `it_bar.dart`, `it_feedback_card.dart`, and `word_data_card.dart`. The choreographer still wires up IT via `_onOpenIT()` / `_onCloseIT()` / `_onAcceptContinuance()`, triggered when an `itStart` match is found. The `it_bar.dart` widget is still imported by `chat_input_bar.dart`.
This entire flow will be removed once testing confirms IT is no longer needed as a separate mode.