From d386d11af247ba468d0056ab75e3bcccb96fd67e Mon Sep 17 00:00:00 2001 From: Michael Chihlas Date: Fri, 24 Apr 2026 06:17:08 -0400 Subject: [PATCH] docs(pilot): correct Phase 9 migration description MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Handoff + migration spec incorrectly claimed Phase 9 added a new parent_pilot_session_id FK. The implementation reuses the existing ai_session_id column; the migration only adds the origin discriminator + partial unique index. Also: ScriptBuilderTab wraps ScriptBuilderChat and ScriptBodyEditor (Monaco), not "ScriptBuilderChat in ephemeral mode" — there is no ephemeral mode on the presentational component. Applies applied_at call-site specifics: handleScriptDecision stamps on one_off/draft_template, TemplateMatchPanel stamps on onMarkRun, Script Builder tab Submit does not stamp. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../FLOWPILOT-MIGRATION.md | 20 ++++++++++--------- .../handoff/2026-04-22-flowpilot-migration.md | 10 +++++----- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/docs/FlowAssist_Migration/FLOWPILOT-MIGRATION.md b/docs/FlowAssist_Migration/FLOWPILOT-MIGRATION.md index 89ca92ac..f76f1c25 100644 --- a/docs/FlowAssist_Migration/FLOWPILOT-MIGRATION.md +++ b/docs/FlowAssist_Migration/FLOWPILOT-MIGRATION.md @@ -2,7 +2,7 @@ > **Target:** Transform `/assistant` (ResolutionAssist) into the new unified `/pilot` (FlowPilot) surface. > **Audience:** Claude Code (implementation) and Codex (review) reviewed by Michael (owner). -> **Status:** Phases 0–9 implemented. Phase 9 shipped the tabbed Script Builder integration (chat-region tab strip, `ScriptBuilderTab` in ephemeral mode, `InlineNoTemplateDialog` chat-region relocation, `PATCH /script` endpoint, `origin`/`parent_pilot_session_id` migration, `applied_at` semantics correction, and `EscalateInterceptDialog` fourth "partial attempt" choice). `tsc -b` and `npm run build` both clean. +> **Status:** Phases 0–9 implemented. Phase 9 shipped the tabbed Script Builder integration (chat-region tab strip, `ScriptBuilderTab` controller with AI + Monaco editor modes, `InlineNoTemplateDialog` chat-region relocation, `PATCH /script` endpoint, `origin` discriminator migration reusing the existing `ai_session_id` FK, `applied_at` semantics correction, and `EscalateInterceptDialog` fourth "partial" choice). `tsc -b` and `npm run build` both clean. > **Last updated:** April 24, 2026 (Phase 9 — Tabbed Script Builder — committed; handoff and migration spec updated) --- @@ -920,18 +920,20 @@ git commit -m "feat(pilot): Phase 8 — fix outcome banner replaces task-lane Su **Implementation plan:** [phase-9-implementation-plan.md](phase-9-implementation-plan.md) -**What this phase does:** Resolves open items #1 (NoTemplateDialog narrow-lane bug) and #3 (Tabbed Script Builder) from the Phase 6/7 backlog. The chat region gains a `[Chat] [Script Builder ●]` tab strip (`ChatTabStrip` + `ScriptBuilderTab`) that embeds `ScriptBuilderChat` in ephemeral mode — the generated script is returned to the caller and written back to `session_suggested_fixes.ai_drafted_script` via a new endpoint, which then unlocks the three-option dialog. Tabs use `display: none` toggling so chat scroll position, draft message, and history are fully preserved. `InlineNoTemplateDialog` is relocated from the task-lane `bottomSlot` into a dedicated chat-region placement wrapper, eliminating the narrow-lane viewport-breakpoint collision that made the three-option grid unusable. +**What this phase does:** Resolves open items #1 (NoTemplateDialog narrow-lane bug) and #3 (Tabbed Script Builder) from the Phase 6/7 backlog. The chat region gains a `[Chat] [Script Builder ●]` tab strip (`ChatTabStrip` + a new `ScriptBuilderTab` controller) that hosts two modes: an AI path reusing the existing (untouched) `ScriptBuilderChat`, and a "Write it myself" path using `ScriptBodyEditor` (Monaco). Engineer submit writes the drafted script back to `session_suggested_fixes.ai_drafted_script` via a new PATCH endpoint — `applied_at` is NOT stamped (a draft is not an application). Tabs use `display: none` toggling so chat scroll position, draft message, AI history, and Monaco buffer are all preserved across switches. `InlineNoTemplateDialog` is relocated from the task-lane `bottomSlot` into a dedicated chat-region placement wrapper, eliminating the narrow-lane viewport-breakpoint collision that made the three-option grid unusable. **Key backend additions:** -- `PATCH /api/v1/ai-sessions/{session_id}/suggested-fixes/{fix_id}/script` — writes `ai_drafted_script` + `ai_drafted_parameters` back to the fix record -- Alembic migration: `origin VARCHAR(20) NOT NULL DEFAULT 'standalone'` and `parent_pilot_session_id UUID NULL REFERENCES ai_sessions(id) ON DELETE SET NULL` added to `script_builder_sessions`; partial unique index `uq_script_builder_sessions_active_inline` prevents duplicate active inline sessions per pilot session -- `applied_at` semantics corrected: the field now stamps only when an action declares that the fix was run (e.g. `status='verified'` or `status='failed'`), not on the initial "Apply" click +- `PATCH /api/v1/ai-sessions/{session_id}/suggested-fixes/{fix_id}/script` — writes `ai_drafted_script` + `ai_drafted_parameters` without stamping `applied_at`; bumps `state_version` so Resolve/Escalate preview bundles regenerate; 409 on terminal fix status +- Alembic migration adds `origin VARCHAR(20) NOT NULL DEFAULT 'standalone'` to `script_builder_sessions` (CHECK enum `'standalone'|'pilot_inline'` + invariant `origin='pilot_inline' ⇒ ai_session_id IS NOT NULL`); reuses the pre-existing `ai_session_id` FK rather than adding a new parent column; partial unique index `ux_script_builder_sessions_pilot_inline` on `(user_id, ai_session_id) WHERE origin='pilot_inline'` backs get-or-create idempotency +- `POST /api/v1/scripts/builder/sessions` extended: accepts `origin` + `ai_session_id` with auth (pilot session must belong to caller); returns existing row on duplicate; race-safe via `IntegrityError` + re-read fallback; `list_sessions` and `count_user_sessions` default-scope to `origin='standalone'` so inline sessions don't pollute the dashboard or count against the 5-session cap +- `applied_at` semantics corrected: stamps only on run-declaring actions — `TemplateMatchPanel` "I ran this" click via new `onMarkRun` prop, and `NoTemplateDialog` decisions `one_off`/`draft_template` (both labelled "Run now, …"). `build_template` does NOT stamp. Script Builder tab Submit does NOT stamp. Banner `Apply` click no longer stamps directly **Key frontend additions:** -- `ChatTabStrip` — tab strip rendered in the chat column header when an inline script session is active -- `ScriptBuilderTab` — wraps `ScriptBuilderChat` in ephemeral mode; calls the `/script` PATCH endpoint on completion -- `InlineNoTemplateDialog` — chat-region placement wrapper replacing the previous task-lane `bottomSlot` rendering -- `EscalateInterceptDialog` gains a fourth "partial attempt" choice (escalating mid-fix with partial notes) +- `ChatTabStrip` — `[Chat] [Script Builder ●]` header strip in the chat region when the active fix needs a drafted script (status proposed/applied_partial, no template, no drafted script) +- `ScriptBuilderTab` — new controller wrapping `ScriptBuilderChat` (AI mode) + `ScriptBodyEditor` (Monaco, "Write it myself" mode); get-or-create on mount; Submit calls `sessionSuggestedFixesApi.patchScript` +- `InlineNoTemplateDialog` — chat-region slide-up wrapper around the existing `NoTemplateDialog`; replaces the previous task-lane `bottomSlot` rendering of the drafted-script three-card decision +- `TemplateMatchPanel` gains `onMarkRun` optional prop + "✓ I ran this" primary button +- `EscalateInterceptDialog` gains a fourth "I applied some of it — partial" choice (dispatches `applied_partial` via the existing `FixOutcome` pass-through) **Commit range:** `5bcb7aa` (Phase 9 Task 1 start) through `faf1d8d` diff --git a/docs/handoff/2026-04-22-flowpilot-migration.md b/docs/handoff/2026-04-22-flowpilot-migration.md index 670ef000..40a9fc32 100644 --- a/docs/handoff/2026-04-22-flowpilot-migration.md +++ b/docs/handoff/2026-04-22-flowpilot-migration.md @@ -29,7 +29,7 @@ All nine migration phases are merged onto the branch and verified against the li | 6 — post-resolve templatize | `4aaf57a` | `draft_templates` table, accept/reject endpoints, `TemplatizePrompt` modal, account preferences | | 7 — polish | `8a242f5` | loading/empty states, keyboard shortcuts (`⌘↵`, `⌘G`, `?` overlay), responsive bottom-drawer <1200px | | 8 — Fix Outcome Banner | `cdd8bb0`..`a47ce07` | Six outcome columns on `session_suggested_fixes` (`status`, `applied_at`, `verified_at`, `partial_notes`, `failure_reason`, `ai_outcome_proposal`) + `PATCH /api/v1/ai-sessions/{sid}/suggested-fixes/{fid}/outcome` endpoint + `[FIX_OUTCOME]` marker; replaces task-lane `SuggestedFix` card with a chat-composer-anchored `ProposalBanner` (5 states: proposed/verifying/partial/ai_confirming/nudge + collapsed); `EscalateInterceptDialog` captures outcome before handoff; Resolve-while-verifying auto-marks success; 17 new tests (8 endpoint + 7 marker + 2 anti-parrot) | -| 9 — Tabbed Script Builder | `5bcb7aa`..`faf1d8d` | Chat-region tab strip (`[Chat] [Script Builder ●]`) with `ChatTabStrip` + `ScriptBuilderTab` (inline `ScriptBuilderChat` in ephemeral mode); `InlineNoTemplateDialog` relocated from task-lane `bottomSlot` to a chat-region placement wrapper; `EscalateInterceptDialog` gains a fourth "partial attempt" choice; `PATCH /api/v1/ai-sessions/{id}/suggested-fixes/{fid}/script` endpoint for writing back AI-drafted script; Alembic migration adds `origin` column + `parent_pilot_session_id` FK to `script_builder_sessions` with partial unique index; `applied_at` semantics corrected to stamp only on run-declaring actions (not the Apply click) | +| 9 — Tabbed Script Builder | `5bcb7aa`..`faf1d8d` | Chat-region tab strip (`[Chat] [Script Builder ●]`) with `ChatTabStrip` + new `ScriptBuilderTab` controller wrapping the existing `ScriptBuilderChat` + Monaco editor (`ScriptBodyEditor`); `InlineNoTemplateDialog` relocates the existing `NoTemplateDialog` from the narrow task-lane `bottomSlot` to a chat-region placement wrapper; `EscalateInterceptDialog` gains a fourth "partial" choice; `PATCH /api/v1/ai-sessions/{sid}/suggested-fixes/{fid}/script` endpoint for engineer-drafted scripts (does not stamp `applied_at`); Alembic migration adds `origin VARCHAR(20)` to `script_builder_sessions` (reuses existing `ai_session_id` FK) + partial unique index on `(user_id, ai_session_id) WHERE origin='pilot_inline'` for idempotent get-or-create; `applied_at` semantics corrected to stamp only on run-declaring actions (`handleScriptDecision` for `one_off`/`draft_template`; new `onMarkRun` on `TemplateMatchPanel`) — not the Apply click | Plus the structural fixes that came up along the way: - `50215b9` + `d0ebdef` — full sweep removing literal payloads from AI system prompts; new `tests/test_prompt_anti_parrot.py` guardrail @@ -63,11 +63,11 @@ See [docs/FlowAssist_Migration/phase-8-fix-outcome-banner.md](../FlowAssist_Migr ### 3. Tabbed Script Builder inside the chat (Option A from the modal-vs-tab discussion) **Status: RESOLVED by Phase 9.** -Phase 9 shipped the complete tabbed Script Builder integration. The chat region now has a `[Chat] [Script Builder ●]` tab strip (`ChatTabStrip`) powered by `ScriptBuilderTab`, which embeds `ScriptBuilderChat` in ephemeral mode (returns script to caller, no standalone `script_templates` row). `display: none` toggling preserves chat scroll position, draft message, and history across tab switches. +Phase 9 shipped the complete tabbed Script Builder integration. The chat region now has a `[Chat] [Script Builder ●]` tab strip (`ChatTabStrip`) powered by a new `ScriptBuilderTab` controller that wraps the existing (untouched) `ScriptBuilderChat` for AI mode and `ScriptBodyEditor` (Monaco) for a "Write it myself" editor mode. `display: none` toggling preserves chat scroll position, draft message, and editor buffer across tab switches. -The `PATCH /api/v1/ai-sessions/{id}/suggested-fixes/{fid}/script` endpoint writes `ai_drafted_script` + `ai_drafted_parameters` back to the fix record so the three-option dialog unlocks normally after script generation. +The `PATCH /api/v1/ai-sessions/{sid}/suggested-fixes/{fid}/script` endpoint writes `ai_drafted_script` + `ai_drafted_parameters` back to the fix record without stamping `applied_at` — a draft is not an application. Bumps `state_version` so cached Resolve/Escalate previews regenerate. -The migration added `origin VARCHAR(20) DEFAULT 'standalone'` and `parent_pilot_session_id UUID NULL REFERENCES ai_sessions(id)` to `script_builder_sessions`, with a partial unique index ensuring only one active inline session per pilot session. +The migration added `origin VARCHAR(20) NOT NULL DEFAULT 'standalone'` (with CHECK constraint on the two valid values + invariant that `origin='pilot_inline'` requires `ai_session_id IS NOT NULL`) to `script_builder_sessions`. It reuses the pre-existing `ai_session_id` FK rather than adding a new parent column. A partial unique index on `(user_id, ai_session_id) WHERE origin='pilot_inline'` backs get-or-create idempotency from the inline tab. See [docs/FlowAssist_Migration/phase-9-implementation-plan.md](../FlowAssist_Migration/phase-9-implementation-plan.md) and [docs/FlowAssist_Migration/phase-9-script-builder-tab.md](../FlowAssist_Migration/phase-9-script-builder-tab.md) for full implementation details. @@ -75,7 +75,7 @@ See [docs/FlowAssist_Migration/phase-9-implementation-plan.md](../FlowAssist_Mig - **PR not opened.** Branch is pushed but no Gitea PR yet. When ready: `gh pr create` works against the GitHub mirror, but the actual review happens in Gitea. - **`/ultrareview` not run** on the final state of the branch (including Phase 9). Worth doing before PR creation. -- **Phase 9 browser QA not done.** The new tab strip, `ScriptBuilderTab`, `InlineNoTemplateDialog` chat-region placement, and `EscalateInterceptDialog` fourth-choice flow have not been exercised in a headless-browser session. Key states to cover: tab strip renders and toggles without unmounting chat; ephemeral Script Builder returns a script and unlocks the three-option dialog; partial-attempt choice in `EscalateInterceptDialog` is recorded correctly. +- **Phase 9 browser QA not done.** The new tab strip, `ScriptBuilderTab` (AI + editor modes), `InlineNoTemplateDialog` chat-region placement, and `EscalateInterceptDialog` fourth-choice flow have not been exercised in a headless-browser session. Key states to cover: tab strip renders and toggles without unmounting chat or losing editor buffer; Script Builder tab Submit persists script via PATCH without stamping `applied_at`; `one_off`/`draft_template` decisions DO stamp; `build_template` does NOT stamp; `TemplateMatchPanel` "I ran this" stamps via `onMarkRun`; partial-attempt choice in `EscalateInterceptDialog` is recorded correctly. - **Phase 8 browser QA not done.** The `ProposalBanner` and `EscalateInterceptDialog` (three-choice variant) have not been exercised in a headless-browser session. Key states: banner appears on `[FIX_OUTCOME]` marker; banner dismisses correctly; escalate mid-fix triggers dialog; banner auto-collapses after session resolved. Use `/qa` or `/design-review` against `mockups/06-slide-up-banner.html` and `mockups/07-verify-states.html`. - **Phase 7 visual verification was structural only** — `tsc -b` and `npm run build` both clean, HMR applied each change without error, but no headless-browser screenshot comparison against the mockup PNGs. If you want pixel-level verification, `/qa` or `/design-review` would catch deltas. - **Anti-parrot test runs as part of `pytest`** but is not enforced in any specific CI step yet — verify `tests/test_prompt_anti_parrot.py` is discovered by the existing pytest run, and consider failing CI explicitly on regression.