Commit Graph

7 Commits

Author SHA1 Message Date
0156aae684 feat(session): impeccable session-screen pass + tasklane keyboard flow
Multi-step UX refactor of the assistant chat session screen, run via the
$impeccable skill. Heuristic score moved 24/40 → 33/40 (+9), with the biggest
gains on Aesthetic & Minimalist (1→3), Consistency & Standards (1→3), and
Recognition Rather Than Recall (2→4).

Distill — chat region:
- Remove the "Suggested checks" chip strip + selected-chip detail card; the
  TaskLane is the single canonical home for "what to do next"
- Add an inline Next steps · N pending cue above the latest action-bearing
  AI bubble (anchors attention without duplicating the lane's items)
- Link banner ↔ script-panel lifecycle: collapsing or dismissing the
  ProposalBanner now also hides the InlineNoTemplateDialog / TemplateMatchPanel
- Drop backdrop-blur on the handoff-context overlay (DESIGN-SYSTEM hard rule)

Quieter — drop decoration overshoot:
- Remove 3px side stripes on TaskLane done cards, all 6 ProposalBanner modes,
  WhatWeKnowItem fact rows
- Drop bg-gradient surfaces on WhatWeKnow + every ProposalBanner mode
- Drop 2px accent borderTop on the TaskLane header
- Replace bordered avatar boxes in banners with inline state-colored icons
- Each surface now uses a single decoration channel (top border + inline icon)

Layout:
- Header consolidates to Resolve + Escalate + ⋯ kebab; Context, New Ticket,
  Update Ticket, Pause now live behind the kebab on desktop, with feature
  parity in the existing mobile overflow menu
- Messages column anchors to max-w-3xl mx-auto to match the composer
- Chat bubbles drop from rounded-2xl to rounded-xl for vocabulary alignment

Typeset:
- Unify text sizing from 14 distinct sizes (with sub-pixel oddities and
  rem/px duplicates) to a 5-step scale: 10px / 11px / text-xs / 13px / text-sm

WhatWeKnow collapsible:
- Header is now a toggle; section body hides when collapsed
- Auto-collapses on first render when facts ≥ 5 so Questions / Diagnostic
  Checks stay above the fold
- Engineer's choice persists in sessionStorage per session and beats the
  auto-collapse heuristic on subsequent renders
- key=activeChatId on both render sites resets state cleanly across sessions

Polish:
- Split MessageCircleQuestion into Pencil (question Answer CTA, write
  affordance) + HelpCircle (per-check Explain toggle, universal help icon) —
  same icon for two different jobs was a discoverability bug
- Drop redundant text-xs from font-sans text-[0.625rem] / text-[0.6875rem]
  double-class definitions; the more-specific size always wins

TaskLane keyboard flow:
- Enter submits and auto-advances to the next pending task; Shift+Enter
  inserts a newline (consistent across question and action textareas — paste
  events don't fire keydown, so paste-then-Enter still works as expected)
- Esc cancels (same as the Cancel button)
- After the last pending task is submitted, focus moves to the Send Responses
  button so the engineer can fire the whole batch with one more keystroke
- Subtle hint row under each open input teaches the shortcut

Type-check, lint, and build all clean.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-01 16:22:50 -04:00
8582d24236 chore(pilot): remove deprecated SuggestedFix task-lane card
Superseded by ProposalBanner (Phase 8). The import was already removed
from AssistantChatPage in the previous commit; this deletes the orphaned
file itself and strips the now-unused suggestedFixSlot prop from
TaskLane's interface and both call sites.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 16:48:42 -04:00
8879f96fbf fix(pilot): drop sticky section headers in task lane
All checks were successful
Mirror to GitHub / mirror (push) Successful in 4s
Each lane section (What we know, Questions, Diagnostic Checks, Suggested
fix) had its own `position: sticky; top: 0` header. As the engineer
scrolled past a section, that section's header would pin until the
section's bottom edge cleared the viewport, producing an "orphaned"
label floating over unrelated content below. Headers now scroll with
their content — in a 340px-wide lane the affordance was negative value.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 16:01:14 -04:00
8a242f5db9 feat(pilot): Phase 7 — polish (loading/empty states, shortcuts, responsive drawer)
All checks were successful
Mirror to GitHub / mirror (push) Successful in 4s
- WhatWeKnow shows a "synthesizing" indicator + skeleton pulse while the
  chat cycle is in-flight; task-lane header mirrors the signal with a
  "thinking" pip so engineers know the AI is still working.
- Quiet-state hint when the lane is open (facts exist) but no open
  questions, checks, or active fix — keeps the surface from looking
  "finished" when the AI is about to follow up.
- Keyboard shortcuts: ⌘↵/Ctrl+↵ send in the composer (plain Enter still
  sends), ⌘G toggles the Script Generator panel for the active fix,
  `?` opens a new ShortcutsHelpOverlay listing all bindings. ⌘K palette
  was already wired in TopBar.
- Responsive: below 1200px the task lane collapses to a bottom drawer
  with a backdrop + a floating "Tasks ●" toggle button. TaskLane now
  takes a `variant: 'side' | 'drawer'` prop; drawer variant drops the
  resize handle and uses the shared slide-in-bottom animation.
- Build hygiene: fixed a pre-existing TS error in confirm-post error
  handling (duplicate `response` type keys) and an unused-import warning
  in TemplatizePrompt.

Verified: `npx tsc -b` and `npm run build` both clean against the dev
stack; Vite HMR applied each change without errors.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 14:19:44 -04:00
fa61376303 feat(pilot): Phase 5 — inline Script Generator integration
All checks were successful
Mirror to GitHub / mirror (push) Successful in 10s
Wires the SuggestedFix card to an inline panel that handles both cases:
template-matched fixes open the Script Library generator with parameters
pre-filled from session context; un-matched fixes open the three-option
dialog (one_off / draft_template / build_template). The decision endpoint
records the path choice with side effects: draft_template persists a
draft_templates row via a Sonnet-driven TemplateExtractionService;
build_template returns a redirect to the Script Builder; one_off just
records the choice.

Backend:
- TemplateExtractionService: drafts a parameter schema from a concrete
  rendered script. Conservative by default ("prefer fewer parameters").
  Round-trip-validates that templated_body only references declared
  parameters; missing-key mismatch falls back to the original script
  with no params. LLM/parse failures fall back identically — the
  engineer can still create a draft and refine in the post-resolve
  prompt (Phase 6).
- /suggested-fixes/{fix_id}/decision side effects:
  * one_off → returns rendered_script (engineer's edited version or the
    fix's ai_drafted_script verbatim)
  * draft_template → same + creates draft_templates row with extracted
    params, returns draft_template_id
  * build_template → returns redirect_path=/scripts/builder?from_session=
    &fix= so the frontend can navigate to the builder pre-loaded
- 400 when a non-template fix has no ai_drafted_script (template-matched
  fixes take the dedicated /scripts/generate path, not this endpoint).
- 12 tests: TemplateExtractionService parse + fallback paths, all four
  decision branches, edited_script override, missing-script 400.

Frontend:
- src/components/pilot/script/{TemplateMatchPanel, NoTemplateDialog,
  ParameterizationPreview}.tsx — inline panels rendered in the task
  lane's bottom slot when the engineer clicks a SuggestedFix card.
- TemplateMatchPanel: loads template via /scripts/templates/{id},
  pre-fills params from fix.ai_drafted_parameters with cyan "from
  session" tags, generates via existing /scripts/generate (already
  bumps state_version on ai_session_id from Phase 3). 404 falls back
  with a clear message instead of erroring.
- NoTemplateDialog: shows the AI-drafted script with proposed parameter
  values highlighted in amber via ParameterizationPreview; three option
  cards with the middle (draft_template) flagged Recommended; inline
  edit on the script body before deciding.
- SuggestedFix card now clickable: onActivate toggles the inline panel.
- AssistantChatPage: scriptPanelOpen state + handleScriptDecision that
  navigates on build_template and toasts on the other paths. Active fix
  changes auto-close the panel so engineers don't act on stale state.
- Cmd+K → "Open inline Script Generator" palette entry surfaces only on
  /pilot/:id routes; fires a window event the chat page subscribes to.
  No Resolve shortcut added per Section 14 decision (browser ⌘R conflict).

Verified 2026-04-22 against the dev stack:
- one_off / draft_template / build_template all return the right shape
  with real Sonnet TemplateExtractionService for the draft path.
- Conservative extraction confirmed: cmdkey + Restart-Process script
  yielded zero proposed parameters as intended.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 00:15:29 -04:00
66e592096c feat(pilot): Phase 3 — Suggested fix tracking + Resolve preview with state_version cache
Adds the AI-proposed resolution path and the inline preview of the
markdown that will be posted to the customer ticket on Resolve. The
preview is keyed on (session_id, ai_sessions.state_version) so back-to-
back fetches against unchanged state hit an in-process cache instead
of paying for a Sonnet call.

Backend:
- preview_cache: in-process LRU keyed on (kind, session_id, state_version).
  No TTL — state_version is the source of truth. Soft-cap 5000 entries.
- unified_chat_service: [SUGGEST_FIX] parser (last-block-wins, JSON
  payload, confidence clamped 0-100), supersession persistence (sets
  superseded_at on prior active row), atomic state_version bump.
- ResolutionNoteGeneratorService: pulls session, facts, active fix, and
  redacted script_generations into a structured input bundle for Sonnet;
  produces the four-section markdown (Problem / What we confirmed /
  Root cause / Resolution). Sensitive script parameters redacted via
  ScriptTemplateEngine.redact_sensitive driven by the template's
  parameters_schema.
- /api/v1/ai-sessions/{id}/suggested-fixes/active — 200 with the active
  fix or 404.
- /api/v1/ai-sessions/{id}/suggested-fixes/{fix_id}/decision — records
  one_off / draft_template / build_template / dismissed; dismiss
  supersedes; bumps state_version. 409 on dismissing an already-
  superseded fix.
- /api/v1/ai-sessions/{id}/resolution-note/preview — generates or returns
  cached markdown; from_cache flag in payload signals cache hit.
- scripts.py POST /generate now bumps state_version on the linked
  ai_session_id when present (third source of preview-cache invalidation
  per Section 5.5).
- ASSISTANT_SYSTEM_PROMPT documents [SUGGEST_FIX] (when to/not to emit,
  format, supersession semantics).
- 12 tests covering the parser (well-formed, last-wins, malformed,
  confidence clamping), supersession + state_version invariant, all
  decision branches, preview cache hit-on-no-change + miss-after-write.

Frontend:
- src/components/pilot/sections/SuggestedFix.tsx — amber-accented card
  with confidence badge; dismiss action wired to the decision endpoint.
- src/components/pilot/ResolutionNotePreview.tsx — popover with refresh,
  loading state, cached/fresh indicator, ticket-ref display.
- src/api/sessionSuggestedFixes.ts — typed client; getActive normalizes
  404 to null so callers don't have to special-case.
- TaskLane gains suggestedFixSlot + bottomSlot props (rendered after
  Diagnostic Checks; bottomSlot anchors the Resolve action).
- AssistantChatPage: refreshSessionDerived helper batches fact + fix
  refresh; fact mutations and chat sends both schedule a 500ms-debounced
  preview refresh per the Section 5.5 spec.

Verified end-to-end against the dev stack with a real Sonnet call:
- /active 404 → fact create → preview generates four-section markdown
  grounded only in provided facts → second preview call hits cache
  (from_cache=true, no LLM call) → fact write 2 → cache miss, regenerates.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 21:45:52 -04:00
625dba7548 feat(pilot): Phase 2 — What we know (facts) with stable task-lane IDs
Adds the load-bearing structural feature of the FlowPilot migration: a
"What we know" panel that holds confirmed facts for a session, fed by AI
[PROMOTE] markers and engineer-added notes. Facts feed the resolution
note preview (Phase 3) and survive across turns via stable UUIDs assigned
to pending_task_lane items.

Backend:
- FactSynthesisService: create/update/soft-delete facts with atomic
  state_version bumps; LLM-backed synthesize_from_question/check on the
  fact_synthesis (Haiku) action tier per Section 6.6.
- /api/v1/ai-sessions/{id}/facts CRUD + /facts/promote (proposed_text or
  via synthesis). PATCH returns 403 for question/diagnostic_check facts
  (edit the source item instead, Section 7.3).
- unified_chat_service: [PROMOTE] marker parser (JSON-block per Section
  8.1 spec drift note), stable-UUID assignment for pending_task_lane
  questions/actions preserved by exact text/label match across turns.
- ASSISTANT_SYSTEM_PROMPT: documents [PROMOTE] format, when to/not to
  emit, hallucination guardrails, source_ref handling.
- 17 tests covering parser, stable IDs, service validation, CRUD,
  editability rule, both promote modes, 422 null-synthesis path,
  state_version invariant.

Frontend:
- src/components/pilot/sections/{WhatWeKnow,WhatWeKnowItem,AddNoteButton}
  — green-gradient section above Questions, dashed-circle check, inline
  edit/delete gated by the server's editable flag.
- TaskLane gains a whatWeKnowSlot prop (existing assistant/ folder kept
  per the doc's "rename is opportunistic" guidance).
- AssistantChatPage fetches facts on selectChat and refetches after each
  chat send (so [PROMOTE]-synthesized facts appear immediately); auto-
  opens the lane when facts exist.

Verification: end-to-end smoke against the local docker stack confirms
all five endpoints (list/create/patch/delete/promote) plus the 403
editability rule. pytest suite verifies the same with mocked LLM. Live
[PROMOTE] flow remains untested until used in the UI — the marker shape
is covered by parser tests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 21:13:44 -04:00