fix(l1): resolve PR #193 frontend review findings (2a,2b,3,4,5,7)

Mounts L1EscalationsSection on EscalationQueuePage (Finding 2a — it was never
rendered) and renders the correct fields: step.question ?? step.text, timeAgo,
and the session problem_text (Finding 2b). ProposalDetail gates the /pilot link
on source_session_id and shows an L1-source block for l1_session_id-sourced
proposals (Finding 3 — was a broken /pilot/null link). Collapses the three
near-identical intake handlers into one runIntake: "Use this flow" now passes
near_miss.flow_id (Finding 4 — it previously re-suggested forever) and a
navigate guard prevents /l1/walk/undefined; out_of_scope gains a "Walk it
ad-hoc" button (Finding 5). Aligns L1-category permissions to owner+admin:
usePermissions.canManageAccount includes account admins, User.account_role TS
type gains 'admin', and a new ProtectedRoute requireAccountManager guard fronts
the route (Finding 7). Drops the unused NextNodeRequest.acknowledged field.

tsc -b + eslint + vite build clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-09 15:55:55 -04:00
parent ac89e7b2fa
commit 9afaf37fb3
10 changed files with 127 additions and 84 deletions

View File

@@ -44,7 +44,7 @@ export function L1WalkTreeVariant({ session, onSessionUpdate, onDone }: Props) {
}, [isAiBuild, session.id, session.status])
const advanceNode = useCallback(
async (body: { answer?: 'yes' | 'no'; acknowledged?: boolean }) => {
async (body: { answer?: 'yes' | 'no' }) => {
if (!node) return
setNodeLoading(true)
setNodeError(null)
@@ -183,7 +183,7 @@ export function L1WalkTreeVariant({ session, onSessionUpdate, onDone }: Props) {
<>
<p className="text-lg">{node.text}</p>
<button
onClick={() => advanceNode({ acknowledged: true })}
onClick={() => advanceNode({})}
className="rounded-md bg-accent text-white px-5 py-3 text-base font-medium hover:bg-accent/90 min-h-[44px] transition-colors"
>
Done next step
@@ -251,8 +251,8 @@ export function L1WalkTreeVariant({ session, onSessionUpdate, onDone }: Props) {
<ol className="space-y-3 text-sm">
{session.walked_path.map((step, i) => (
<li key={i} className="flex flex-col">
<span className="text-muted-foreground text-xs">{step.question}</span>
<span className="font-medium"> {step.answer}</span>
<span className="text-muted-foreground text-xs">{step.question ?? step.text}</span>
{step.answer && <span className="font-medium"> {step.answer}</span>}
{step.l1_note && <span className="text-muted-foreground text-xs italic mt-0.5">{step.l1_note}</span>}
</li>
))}