fix(panel): V6 review gaps — honest errors, safe secretary start, real tests

CEO A2A mutations now invalidate the Mine-list query key so the list
refreshes without the socket; the tg Metrics tab renders explicit error
notes instead of confident zero stats when a section's fetch fails; the
tg Secretary chat checks a new registry-backed /secretary/live/active
route before auto-starting, showing a Take Over button instead of
silently killing a session live on another device; the AI-routing card
surfaces roster fetch errors instead of an empty grid; the shared
acceptance-criteria editor caps at the backend's 7-item limit; the
board-tab comment no longer calls the task sheet read-only. Tests:
task-sheet approve/reject interactions (not just visibility), a
non-demo metrics error-state test, secretary take-over branches, and
dashboard-router auth-gate coverage (the e2e harness now mounts the
dashboard router so the gate is actually exercised).
This commit is contained in:
Renn F
2026-07-22 03:31:25 +02:00
parent 5ca8a9c4a6
commit a1233b2aeb
18 changed files with 726 additions and 144 deletions
@@ -413,6 +413,27 @@ describe("AIRoutingCard", () => {
expect(mixSection.querySelector(".animate-pulse")).toBeInTheDocument();
});
it("shows an error note (not a silently empty grid) when the roster fetch fails", async () => {
useAgentDefinitions.mockReturnValue({
data: undefined,
isLoading: false,
isError: true,
});
render(withQueryClient(<AIRoutingCard />));
await screen.findByText("Per-agent override (mix mode)");
expect(
screen.getByText(/Couldn.t load the agent roster/i),
).toBeInTheDocument();
expect(
screen.queryByRole("heading", { level: 4, name: "Board" }),
).not.toBeInTheDocument();
const mixSection = screen
.getByText("Per-agent override (mix mode)")
.closest("section")!;
expect(mixSection.querySelector(".animate-pulse")).not.toBeInTheDocument();
});
it("tooltip-wraps the Grok/Ollama key labels and status badges, not the raw Switch", async () => {
render(withQueryClient(<AIRoutingCard />));
await screen.findByText("Grok (xAI) API key");
@@ -131,7 +131,11 @@ export function AIRoutingCard() {
const { data: keyStatus } = useOllamaKey();
const { data: snapshot } = useRoutingMode();
const { data: selfHostedModels = [] } = useSelfHostedModels();
const { data: agentDefs, isLoading: agentsLoading } = useAgentDefinitions();
const {
data: agentDefs,
isLoading: agentsLoading,
isError: agentsError,
} = useAgentDefinitions();
const agentGroups = useMemo(
() =>
@@ -662,7 +666,13 @@ export function AIRoutingCard() {
Leave a row blank to inherit from the global mode. Saving overwrites
all per-agent overrides with what&apos;s picked here.
</p>
{agentsLoading ? (
{agentsError ? (
<p className="flex items-center gap-1 rounded-md border p-4 text-xs text-amber-600">
<AlertTriangle className="h-3 w-3 shrink-0" />
Couldn&apos;t load the agent roster per-agent overrides are
unavailable until this reloads.
</p>
) : agentsLoading ? (
<div className="divide-y rounded-md border">
{Array.from({ length: 4 }).map((_, i) => (
<div key={i} className="p-4">