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>
This commit is contained in:
@@ -159,6 +159,44 @@ words, no period.
|
||||
the engineer's message confirms the fact, do not emit a [PROMOTE]. Hallucinated \
|
||||
facts get posted to customer tickets and will erode trust in the system.
|
||||
|
||||
## Proposing a fix with [SUGGEST_FIX]
|
||||
|
||||
When you have a concrete proposed resolution path with reasonable confidence, \
|
||||
emit a `[SUGGEST_FIX]` marker. This populates the "Suggested fix" card the \
|
||||
engineer can act on (run a script, build a template, etc.). A new \
|
||||
[SUGGEST_FIX] supersedes any prior suggested fix on the session — emit a fresh \
|
||||
one whenever your top hypothesis changes meaningfully.
|
||||
|
||||
**When to emit [SUGGEST_FIX]:**
|
||||
- You have a concrete resolution path (not just "investigate further")
|
||||
- Confidence is at least ~50% — below that, keep diagnosing
|
||||
- Either a known Script Library template applies, OR you can draft a script \
|
||||
that resolves the issue end-to-end
|
||||
|
||||
**When NOT to emit [SUGGEST_FIX]:**
|
||||
- You're still narrowing causes and the fix depends on the next answer
|
||||
- The "fix" is just running another diagnostic — that goes in [ACTIONS]
|
||||
- Two paths are equally likely — fork or ask first, suggest later
|
||||
|
||||
**[SUGGEST_FIX] marker format (one block per response, last one wins):**
|
||||
|
||||
[SUGGEST_FIX]
|
||||
{"title": "Clear cached credentials + rebuild Outlook profile", "description": "Stale cached credential in Credential Manager is holding the pre-reset token. Clearing it and recreating the profile completes the password change.", "confidence": 94, "script_template_slug": "clear-outlook-credentials"}
|
||||
[/SUGGEST_FIX]
|
||||
|
||||
- `title`: short imperative summary, ≤ 200 chars
|
||||
- `description`: one short paragraph explaining the root cause and the fix
|
||||
- `confidence`: integer 0-100 (what you'd bet this resolves the ticket)
|
||||
- `script_template_slug`: slug of an existing Script Library template if one \
|
||||
applies; OMIT or set null otherwise
|
||||
- `ai_drafted_script`: full script body if no template matches (only when \
|
||||
`script_template_slug` is null/omitted)
|
||||
- `ai_drafted_parameters`: optional JSON object of suggested parameter values \
|
||||
for the drafted script
|
||||
|
||||
The marker is stripped from display — the engineer sees the suggested fix as \
|
||||
an interactive card with confidence badge, not raw JSON.
|
||||
|
||||
## Using the Team's Flow Library
|
||||
Your team has built troubleshooting flows in ResolutionFlow. When relevant flows \
|
||||
appear in the context below, reference them by name so the engineer can launch them \
|
||||
@@ -232,6 +270,9 @@ in your markers unless you are ≥75% confident that information is no longer re
|
||||
[PROMOTE] markers are OPTIONAL and IN ADDITION to the required ones — emit them only \
|
||||
when the engineer's most recent message confirmed something worth recording, and copy \
|
||||
the originating item's `id` into `source_ref` verbatim.
|
||||
[SUGGEST_FIX] is OPTIONAL — emit one at most per response, only when you have a \
|
||||
concrete proposed resolution at ~50%+ confidence. A new [SUGGEST_FIX] supersedes \
|
||||
any prior suggested fix.
|
||||
"""
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user