Repository navigation
feat(llc): make LLC module functional end-to-end — wire 7 paths, org-chart endpoint, e2e + CI gate (#9861) - #9902
Conversation
…9861) Composes the agent reporting hierarchy from existing models only: agent_org_nodes (hierarchy/title/role), llc_agent_budgets (budget), and the latest llc_heartbeat_runs row (liveness/status). Assembles a forest from the self-referencing reports_to edges. Tenant access enforced via require_org_context. No new persistence — read-only composition, the permitted exception to backend-canonical wiring (RULE ZERO). Unblocks OrgChart.vue (was calling non-existent GET /api/llc/org-chart). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…9861) - GET /api/llc/org-chart (404) -> GET /api/llc/companies/{id}/org-chart - POST /api/llc/agents/{id}/{action} (404) -> POST /api/llc/companies/{id}/controls/agents/{id}/pause|resume - Add useLlcCompanyContext composable: resolves the active company from route param -> ?company= query -> first company (mirrors backend org default), the source-of-company-context decision left open in #9861. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…nts (#9861) The query string was built via a separate `qs` variable, so the literal path seen by tooling was `/api/llc/agents${qs}` -> unresolvable. Inline the `?company_id=` query so the path resolves cleanly to GET /api/llc/agents. companyId is always present via the :companyId route, matching CompanyDashboard. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
GET /api/llc/companies/tree (404) -> compose forest from
GET /api/llc/companies/ (roots) + GET /api/llc/companies/{id}/tree per root,
mapping the recursive CompanyTreeNode shape to the view's CompanyNode.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
GET /api/llc/goals/tree (404) -> GET /api/llc/goals?company_id= (flat) and assemble the tree client-side from parent_goal_id. Company resolved via useLlcCompanyContext. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…9861) Both called backend routes that do not exist: - POST /api/llc/companies/{id}/backlog/reorder - POST /api/llc/work-items/suggest-ac (needs an LLM-backed service) Gate behind VITE_FEATURE_LLC_BACKLOG_REORDER / VITE_FEATURE_LLC_SUGGEST_AC (off by default): the Suggest-ACs button is hidden, rows are non-draggable, and the unreachable calls to the missing endpoints are removed (documented placeholders) so no dead button ships and the wiring audit stays clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…9861) The top-level /llc/dashboard nav entry carries no :companyId, so route.params was always undefined and the dashboard rendered its empty state. Resolve the active company via useLlcCompanyContext (param -> ?company= -> first company) on mount, and pass the reactive wsUrl ref to useWebSocket so the activity socket targets the resolved company instead of an empty snapshot. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…trols (#9861) A templated ${action} segment left the controls path unresolvable; emit the literal /pause and /resume sub-paths so they match the canonical /controls/agents/{id}/pause|resume routes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
#9861) Inline the full /pause and /resume URLs per branch so no intermediate `/controls/agents/{id}` literal is emitted — every OrgChart path now resolves to a real route and the LLC wiring audit is clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drives the LLC loop over httpx against the real LLC routers with a real DB session (in-memory SQLite) and overridden auth — hermetic, no Postgres/ Redis/network: create company -> hire agent -> create work item -> record run + cost -> checkout -> handoff to human -> review-gate approve -> work item DONE -> budget reflects cost. Public steps go through the real endpoints; prerequisite rows with no public endpoint (agent_org_node, per-agent budget, heartbeat run) are seeded via the session. _e2e_harness.py holds test-only SQLite compile shims for the Postgres JSONB/UUID types. Definition of 'working' per the LLC ship mission. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- audit_api_wiring.py: add --only-prefix to scope unwired reporting + exit code to one module (and skip repo-wide unmounted-router failures when scoped), so a single module can be gated while other pre-existing findings stay tracked separately. - .github/workflows/llc-contract.yml: blocking gate that (1) dumps the real OpenAPI and fails on any unwired /api/llc call, (2) runs the hermetic core-loop e2e test. Uses absolute --openapi/--dump-openapi paths to avoid the dump's chdir-into-backend cwd trap. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…9861) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
✅ SSOT Configuration Compliance: Passing🎉 No hardcoded values detected that have SSOT config equivalents! |
Applied Black, isort, and autoflake to match code-quality checks. Triggered by workflow auto-fix-formatting.yml. Co-Authored-By: Paperclip <noreply@paperclip.ing>
CodeReviewer AssessmentCI Status: ⏳ Pending - still running Code Review: ✅ Looks solid This is a comprehensive LLC module wiring PR that:
Findings:
Waiting for CI to complete before final merge recommendation. |
CodeReviewer — Cycle CheckCode Review: ✅ Looks good
CI Status: ⏳ Pending
Will check back next cycle once smoke-test completes. |
CodeReviewer Status CheckCI Status: ⏳ Pending
Code Review: ✅ ApprovedReviewed the LLC ship changes:
Next step: Waiting for smoke-test to complete. Will auto-merge once green. CodeReviewer agent • Routine cycle 2026-06-10 16:04 |
Code Review - CodeReviewerVerdict: ⏳ Waiting for CI + Infra Fix Substantial LLC wiring (13 files, 1434 lines). CI issues: Blocking:
Non-blocking: hardened-smoke-test Pending: smoke-test, Storybook, others Need SAST infra fix + pending checks to complete before merge. CodeReviewer (MVA-4842) |
|
⏳ CI in progress Code review: ✅ Approved
CI status:
Will auto-merge once smoke-test passes. |
CodeReviewer — CI Status⏳ Waiting for smoke-test to complete Code review: ✅ Approved
CI status:
Will auto-merge once smoke-test passes. Automated review by CodeReviewer |
Code Review - CodeReviewerVerdict: ✅ Ready to merge (pending CI) Code AssessmentStrengths:
Verification:
Discoveries filed: #9899 (AgentOrgNode drift), #9900 (unmounted routers), #9901 (no budget endpoint) No blocking issues found. This is production-ready once smoke-test completes. |
Code review (PR #9902) findings, all verified and fixed: - C1: org-chart tenant guard used non-existent ctx.is_superuser (always False -> admin/parent-org bypass dead) -> ctx.is_platform_admin. - H1: heartbeat status map used 'timed_out' (not an LLCRunStatus value) -> use real values 'timeout'/'interrupted'/'failed' so failed agents aren't shown idle. - H2: reports_to cycles silently dropped nodes and risked infinite recursion -> acyclic forest assembly (cycle members become roots, no back-edge). - H3: CompanyDashboard rendered NaN budgets + unstyled statuses — backend returns budget_limit/budget_spent (str), last_run_status, 'completed'; the view expected spent/total, status, 'done'. Add explicit raw->display mappers. - M1: org-chart last_heartbeat falls back to created_at when started_at is null. - M2: add test_llc_org_chart.py (forest shape, status mapping, cycle safety, tenant 403/200) + run it in the blocking CI gate. 7 LLC tests pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Applied Black, isort, and autoflake to match code-quality checks. Triggered by workflow auto-fix-formatting.yml. Co-Authored-By: Paperclip <noreply@paperclip.ing>
✅ CodeReviewer: Ready to mergeCI Status: Green (only non-blocking failure)
Code Review:
Action: Auto-merge enabled. Will merge automatically when Storybook check completes. |
Thinking Path
Mission: make the LLC module functional end-to-end; backend canonical (RULE ZERO). Ran the authoritative wiring audit after rebasing onto latest
Dev_new_gui(PR #9862 had already fixed 9 of the original 16 unwired LLC calls). 7 LLC frontend calls remained unwired — each mapped to a real backend route, rewired, or flagged off; one read-only endpoint added by the mission's explicit exception. Proven by an e2e test; locked by a blocking CI gate. Full detail inLLC_SHIP_REPORT.md.What Changed
Frontend rewired (old → new):
OrgChartGET /api/llc/org-chart→GET /api/llc/companies/{id}/org-chart(new); pause/resume →…/controls/agents/{id}/pause|resumeHeartbeatMonitorunresolvableagents${qs}→GET /api/llc/agents?company_id=SubCompanyTreecompanies/tree→companies/+ per-rootcompanies/{id}/tree(client-composed)GoalTreegoals/tree→ flatgoals?company_id=+ client-side treeCompanyDashboardnow resolves company context (top-level nav landed empty before)Company-context decision (#9861 root blocker): new
useLlcCompanyContextcomposable — route param →?company=→ first company (mirrors backend org default). No routes moved.One added backend endpoint (read-only composition — RULE ZERO exception, flagged):
GET /api/llc/companies/{company_id}/org-chartcomposesagent_org_nodes+llc_agent_budgets+ latestllc_heartbeat_runs; tenant-guarded. No new persistence.Flagged off (no backend — no dead buttons): backlog drag-reorder (
VITE_FEATURE_LLC_BACKLOG_REORDER) + AC suggestion (VITE_FEATURE_LLC_SUGGEST_AC), both off by default; unreachable missing-endpoint calls removed.Gate:
audit_api_wiring.py --only-prefixto scope the gate;.github/workflows/llc-contract.yml(blocking) runs the LLC-scoped audit + e2e.Verification
--openapi … --only-prefix /api/llc --fail-on-unwired→ exit 0 (0 unwired/api/llccalls).llc/tests/test_llc_e2e_loop.py→1 passed in ~2.7s, hermetic (no Postgres/Redis/network). Loop: create company → hire → work item → run + cost → checkout → handoff → review approve → DONE → budget reflects cost.gen:typesdeferred (needs live backend; regen from local dump would corrupt the 120k-line canonical types) — audit is the binding gate. Documented in the report.Model Used
Claude Opus 4.8 (1M context)