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>
An earlier anchor-edit silently failed, so POST /sessions/{id}/next-node and
GET /escalations were never added (they 404'd). Add both, anchored on the real
/escalate-without-walk route.
Phase-1 test_l1_endpoints tests used POST /intake to create adhoc setup sessions,
but Phase 2A intake now dispatches via match_or_build (build/matched/suggest/
out_of_scope — never adhoc). Add a _create_adhoc_session service helper and route
the step/notes/resolve/escalate/cross-account setup through it; rewrite
test_intake_adhoc as test_intake_build_creates_ai_build_session (mocked outcome).
All green: test_l1_endpoints + test_l1_api_ai_build = 25 passed; full Phase 2A
backend service/unit/model suite = 56 passed; notification suite = 18 passed.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- /intake now runs match_or_build (matched/suggest/out_of_scope/build); build
seeds the classified category as a hidden meta walked_path entry, matched starts
a flow session, suggest/out_of_scope return prompt data with no session.
- New POST /sessions/{id}/next-node (threads node_text to advance_ai_build) and
GET /escalations (engineer-or-above) for the handoff queue.
- New IntakeResponse(outcome=...)/NextNodeRequest/NextNodeResponse schemas and
require_account_owner_or_admin dep.
- Reconcile Phase-1 intake tests to the new contract (mock match_or_build); add
test_l1_api_ai_build.py covering build/out_of_scope/suggest/next-node/escalations.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sessions are account-scoped (per spec §7.9), not user-scoped, to support
team coverage. Comment-only fix surfaced by final review.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Mounts /api/v1/l1/* with require_l1_or_coverage on every route. Intake
creates an internal ticket and starts a flow OR adhoc session (PSA queue
merge follows in Phase 2). Step/notes/resolve/escalate delegate to
l1_session_service. escalate-without-walk creates an immediately-
escalated session for the BuildAbortedNoKB path.
ValueError from services → 400. Cross-account session access → 404.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>