From f60951b1d5f4887c630695443fd38321db6f804c Mon Sep 17 00:00:00 2001 From: Phil Merrell Date: Sat, 25 Jul 2026 14:46:43 -0600 Subject: [PATCH] fix(marketplace): the agent detail page never loaded its agent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `AgentDetailPage` called `load()` from its constructor, and `load()` reads `this.id()` — an `input.required()` bound by `withComponentInputBinding()`. The router sets that input *after* construction, so the read threw NG0950 before `AgentApiService.getAgent()` was ever called. The throw landed inside `load()`'s own try/catch, which turned it into `this.error.set('Failed to load this agent.')`. So the page rendered a plausible error banner with **no HTTP request behind it** — no console error, no failed request, nothing to grep for. `/agents/:id` has been in this state since phase 3 (66f38346); the detail page has never successfully loaded in a browser. Moved both init calls to `ngOnInit`, which runs after input binding. Found while running the phase 5-7 dev smoke test, where the detail page is the only surface carrying the pin control. There is no `agent-detail.page.spec.ts` at all, which is why CI never caught it — a regression spec is tracked separately. Note that a spec asserting this must set the input the way the router does (after creation, e.g. via `RouterTestingHarness`); passing `id` at construction time reproduces neither the bug nor the fix. Co-Authored-By: Claude Opus 5 --- .../src/app/agents/detail/agent-detail.page.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/frontend/ai.client/src/app/agents/detail/agent-detail.page.ts b/frontend/ai.client/src/app/agents/detail/agent-detail.page.ts index d075e1426..0eee1c73d 100644 --- a/frontend/ai.client/src/app/agents/detail/agent-detail.page.ts +++ b/frontend/ai.client/src/app/agents/detail/agent-detail.page.ts @@ -4,6 +4,7 @@ import { computed, inject, input, + OnInit, signal, } from '@angular/core'; import { Router } from '@angular/router'; @@ -358,7 +359,7 @@ import { TooltipDirective } from '../../components/tooltip/tooltip.directive'; `, }) -export class AgentDetailPage { +export class AgentDetailPage implements OnInit { private api = inject(AgentApiService); private pinService = inject(AgentPinService); private router = inject(Router); @@ -392,7 +393,14 @@ export class AgentDetailPage { readonly reportConfirmation = signal(null); private readonly hasOpenReport = signal(false); - constructor() { + /** + * ``ngOnInit``, not the constructor: ``id`` is a required signal input bound by + * ``withComponentInputBinding()``, and the router sets it *after* construction. + * Reading it a moment too early throws NG0950, which ``load()``'s own try/catch + * then swallowed into "Failed to load this agent." — an error banner with no + * network request behind it, which is what this page did from phase 3 until now. + */ + ngOnInit(): void { void this.load(); // Cached across the session, so arriving from a shelf row costs nothing. void this.pinService.load();