Server-assigns a uuid4 id to every AI-generated node (Finding 1 showstopper:
nodes had no id but the advance protocol keys on node_id, so ai_build walks
never advanced past question 1). Replaces the hidden {"node_type":"meta"}
walked_path convention with real category/problem_text/pending_node columns on
l1_walk_sessions (migration 61dda4f615c6) — fixes junk proposals + off-by-one
depth cap (Findings 8,9), and pending_node replays the served node on re-mount
(no duplicate paid LLM call). Intake honors explicit flow_id and adhoc=True
(Findings 4,5); flow_proposals.l1_session_id FK -> CASCADE (Finding 6 time
bomb); L1 category GET is owner+admin like PATCH and require_account_owner_or_admin
delegates to User.can_manage_account (Finding 7); escalate falls back to default
recipients + filters deleted_at + warns when empty (Finding 10). Cleanups: dead
ticket_ref removed, IntakeResponse per-outcome validator, unused acknowledged
dropped, escalations partial index, restored a deleted audit assertion.
Full Phase 2A backend set: 110 passed / 0 failed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
GET /accounts/me/l1-categories (require_l1_or_above) returns enabled + available
+ hard_floor; PATCH (require_account_owner_or_admin) sets the enabled set, dropping
unknown/hard-floored keys via l1_category_service. New L1CategoriesResponse/Update
schemas. 6 API tests green (incl. engineer + l1_tech write both 403); test_accounts
regression 36 passed.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Owner-only endpoint to toggle can_cover_l1 on an engineer user. 422 if target
role is not engineer (owners/super_admins already see L1 surface; viewers/
l1_techs don't need this flag). 404 for cross-account targets.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Returns {engineer: SeatCheckResult, l1_tech: SeatCheckResult} for the
authenticated engineer's account. Powers the SeatCounterWidget UI in the
admin/users + account/users surfaces. Engineer+ access only.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- oauth.py: use status.HTTP_402_PAYMENT_REQUIRED constant (was raw 402)
- accounts.py bulk-invite: catch HTTPException separately to preserve
structured detail dict in failed-row error (was stringified repr,
unparseable by clients)
- Add bulk-invite per-row 402 test verifying structured error preserved
T8 code review identified these as Important issues. Functional change is
the bulk-invite fix; clients can now parse seat-limit errors from bulk
responses. 13/13 seat-enforcement tests pass.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
For engineer + l1_tech roles, check_seat_available is called at each
mutation point. Returns 402 Payment Required with structured detail
{code: 'seat_limit_exceeded', role, current, limit, upgrade_url} when
seats are full. Grandfathering: existing over-seated accounts keep
existing users; only new mutations are blocked.
Also updates AccountInviteCreate and AccountRoleUpdate schemas to
accept l1_tech as a valid role value.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Closes the loop on the Phase 5 "Run now, templatize after resolve" path.
After a session resolves, drafts queued by the three-option dialog surface
as a modal that lets the engineer review the AI-proposed parameterization
and either save as a reusable team template or skip. A "don't ask again"
toggle writes to account_settings.preferences so the next resolve won't
pop the modal.
Backend:
- /api/v1/draft-templates:
* GET — list account drafts (pending_only default true; pass false for
audit view including accepted/rejected)
* GET /{id} — single draft
* POST /{id}/accept — promotes to a new script_templates row with
source_session_id / source_user_id / source_ticket_ref populated
(drives the Script Library "generated from CW #X · resolved by Y"
provenance chip). Draft flips to status=accepted,
promoted_template_id set, resolved_at stamped. 409 on re-accept /
already-rejected. 400 on unknown category_id.
* POST /{id}/reject — flips to status=rejected. 409 on re-reject.
- /api/v1/accounts/me/preferences (GET/PATCH) — thin wrapper over
AccountSettings.get_setting/set_setting. PATCH merges keys into the
JSONB column, preserving existing keys the client didn't touch.
Used by the "Don't ask again for this team" checkbox
(templatize_prompt_enabled=false) and, forward-looking, by
cw_resolved_status_id / cw_escalated_status_id from Phase 4.
- 13 tests: list filter, accept with/without edited_body, provenance
copy-through, reject, 409 on re-accept / re-reject, 400 on unknown
category, prefs round-trip with merge semantics.
Frontend:
- src/components/pilot/script/TemplatizePrompt.tsx — modal showing the
drafted script with proposed parameters in the Phase 5
ParameterizationPreview, editable name/category/description, an
individual-parameter remove button, and the "don't ask again" opt-out.
Accept posts to /draft-templates/{id}/accept + optionally PATCHes
preferences. Skip posts /reject.
- src/api/draftTemplates.ts — typed client plus accountPreferencesApi.
- AssistantChatPage: after a successful Resolve (external OR local),
fetches preferences + pending drafts for the session and queues the
modal one draft at a time. Escalate does not trigger this flow.
- Sidebar: Scripts nav shows the pending-draft count as a badge. Fetched
independently of the main sidebar stats so endpoint flakes don't
break the rest of the sidebar.
Verified live 2026-04-22: seed two drafts → GET sees both pending →
accept draft A (template created, provenance CW #99123 populated) →
reject draft B → pending count drops → PATCH opt-out → GET confirms
persistence.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase 4 enabled RLS on the users table. All code paths that touch users
(or other RLS-protected tables) before require_tenant_context sets
app.current_account_id must use get_admin_db (BYPASSRLS):
- deps.py: get_current_user and get_current_active_user → get_admin_db
- auth.py: all endpoints → get_admin_db (login, register, refresh, etc.
run before tenant context exists; mutation endpoints also need session
consistency since current_user is in the admin session)
- accounts.py: transfer_ownership, leave_account, delete_account
→ get_admin_db (these mutate current_user directly)
- onboarding.py: dismiss_onboarding → get_admin_db (same reason)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add branding_logo_url, branding_primary_color, branding_company_name columns to Account model
- Add Alembic migration (58e3f27f3e8f) for branding and SSO columns
- Add GET/PATCH /accounts/me/branding endpoints (owner-only for PATCH)
- Add BrandingSettingsPage with logo URL input, color picker, preview section
- Add /account/branding route (ProtectedRoute owner) in router.tsx
- Add Branding link card in AccountSettingsPage
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: update Google Fonts to Bricolage Grotesque, IBM Plex Sans, JetBrains Mono
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore: update Tailwind config to Slate & Ice theme colors and fonts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: update CSS variables and glass-card utilities for Slate & Ice theme
- Replace all color variables with Slate & Ice palette
- Add glass system vars (--glass-bg, --glass-blur, --shadow-float)
- Replace legacy glass-card with new variable-driven glass classes
- Add breatheGlow, bellWobble, slideDown, fadeInRight keyframes
- Update font references to IBM Plex Sans and Bricolage Grotesque
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: recolor BrandLogo to cyan gradient, split BrandWordmark for gradient Flow text
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: update TopBar with glassmorphism backdrop and cyan accent styling
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: update Sidebar with glassmorphism backdrop
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add ambient atmosphere gradient orbs behind app shell
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: update QuickStats and SessionsPanel with glass-card styling
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add WeeklyCalendar, QuickActions, OpenSessions, RecentActivity dashboard components
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: redesign dashboard layout with calendar, open sessions, and glass-card panels
New layout: greeting → calendar+actions → sessions+stats → activity
Replaces old QuickStats and SessionsPanel with new dashboard components
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: replace remaining purple hex references with ice-cyan accent
Sweep of hardcoded purple hex values (#818cf8, #6366f1) replaced with
new cyan accent (#06b6d4) in QuickActions, RecentActivity, QuickLaunch,
and SVG brand assets.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs: update CLAUDE.md branding and design system for Slate & Ice Modern
Updated Last Updated date, branding section (fonts, colors, glass
utilities, atmosphere orbs), component styling rules, and Design System
section to reflect the new ice-cyan glassmorphism theme.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs: add Slate & Ice Modern design doc and implementation plan
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: redesign login page with Slate & Ice Modern design system
Apply glassmorphism styling, atmosphere orbs, branded wordmark, and
consistent design tokens to match the updated app shell aesthetic.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: raise TopBar z-index so profile dropdown renders above main content
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add AI assistant with in-session copilot and standalone chat with RAG
Implements three-phase AI assistant feature:
- Phase 0: RAG infrastructure with pgvector embeddings, Voyage AI integration,
tree chunking service, and semantic search over team's flow library
- Phase 1: In-session copilot panel during flow navigation with contextual
AI help, current step awareness, and suggested related flows
- Phase 2: Standalone AI chat page with persistent conversation history,
pin/delete, and configurable retention policies (account-level)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add account management, email verification, AI fixes, and user guides
- Profile settings, account transfer, delete/leave account flows
- Email verification with JWT tokens and Resend integration
- AI assistant/copilot fixes: markdown rendering, shared RAG helpers,
token tracking, input refocus, model_validate usage
- User guides hub + detail pages with 13 topic guides
- Sidebar and top bar navigation for guides
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: prevent stale chunk errors after deployments
- Set Cache-Control no-cache on index.html in nginx so browsers always
fetch fresh chunk references after a deploy
- Auto-reload on chunk load failures (stale deploy detection) with
loop prevention via sessionStorage
- Show friendly "App Updated" message if auto-reload doesn't resolve it
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add email verification toggle to admin settings
Adds platform-level toggle to enable/disable email verification.
When disabled, the verification banner is hidden and the send
endpoint returns 403.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Revoke-and-recreate flow for both invite systems with email delivery
via Resend API. Includes account invite email template and audit logging.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace team_id with account_id across all API endpoints (trees,
categories, tags, steps, step_categories, admin, auth). Add new
accounts and webhooks endpoints. Registration now atomically creates
Account + Subscription, with account_invite_code bypassing the
platform invite gate.
Schemas updated for account_id/account_role. 82 tests passing
including 18 new tests for accounts, subscriptions, and permissions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>