Skip to content

feat(W15-A14): Autopilot tab — planner queue, agent activity, freeze/thaw - #210

Merged
Ghenghis merged 1 commit into
developfrom
claude/w15-a14-tabs-a
May 10, 2026
Merged

Ghenghis merged 1 commit into
developfrom
claude/w15-a14-tabs-a

Conversation

@Ghenghis

@Ghenghis Ghenghis commented May 10, 2026 •

Copy link
Copy Markdown
Owner

Wave 15 — Agent 14 · Primary Tabs A

Brings the Autopilot tab in line with the Wave 15 brief
(planner queue + agent activity feed + freeze/thaw controls) while
leaving the already-FULLY_WIRED Design / Gen3D / Jobs tabs untouched.

What changed

  • components/autopilot/PlannerQueue.tsx — reads getActiveWorkflows() (live /api/workflows/active).
  • components/autopilot/AgentActivityFeed.tsx — reads getAgents() (live /api/agents).
  • components/autopilot/FreezeThawControls.tsx — POSTs to /api/autopilot/freeze & /thaw; renders explicit "Blocked: endpoint not implemented" when 404/405 (W15 A20 owns the backend route).
  • tabs/Autopilot.tsx — wraps existing READINESS/SAFE ACTIONS/GUARDRAILS in a 7-col left pane; new components go into a 5-col right pane.

Disjoint scope respected

Only Autopilot.tsx + new autopilot/* components touched. Design / Gen3D / Jobs unchanged.

No-fake policy

  • PlannerQueue / AgentActivityFeed: empty → explicit "No active workflows returned…" message; fetch error → "Blocked: …unreachable."
  • FreezeThawControls: starts at mode=unknown; only flips to frozen/thawed after a real HTTP 2xx; surfaces 404/405 as explicit "Blocked: /api/autopilot/ is not implemented on this backend (W15 A20 owns the endpoint)."

4 tabs status

Tab Route Visual Backend truth
Autopilot #autopilot left col READINESS/SAFE ACTIONS/GUARDRAILS + right col new PLANNER QUEUE/AGENT ACTIVITY/FREEZE-THAW /api/autopilot/* /api/workflows/active /api/agents live; freeze/thaw 404-blocked-honest
Design #design unchanged — Design Intake + Toolchain + CAD Providers + Templates /api/design/* live
Gen3D #gen3d unchanged — Prompt + Reference + Providers + Plan Preview + Templates + Generated Models /api/gen3d/* + /api/generation/run live
Jobs #jobs unchanged — filter tabs (Queued/Running/Done/Failed/Cancelled) + detail pane + proof-gated pipeline /api/jobs/* (9 paths) live

Self-audit (all PASS)

  • npx tsc --noEmit — EXIT 0
  • npm run build — built in 1.14s, all chunks emitted
  • Each tab renders without runtime errors (only network errors are the expected 127.0.0.1:8765 ConnectionRefused since no backend is running locally — the UI surfaces these as honest empty/blocked states)
  • 4 screenshots at 1536×1024 in 03_implementation/proof/screenshots/w15-a14/:
    • autopilot.png, design.png, gen3d.png, jobs.png (1536×1024)
    • bonus: autopilot-1536x1400.png showing all 6 sections in one frame
    • bonus: autopilot-freeze-thaw-detail.png showing the new freeze/thaw card

Sources cited

  1. Official React composition — small, read-only, single-responsibility components, each owning their own useEffect polling (matches existing AutopilotConsole + Autopilot.tsx patterns in this repo).
  2. Cross-project — GitHub Actions runs UI — table-with-status-pill row pattern used by AgentActivityFeed (status dot + role + meta + last-activity time, sorted active → idle → error).

Hermes lock

  • Owner: claude-w15-a14-tabs-a
  • Files: 03_implementation/ui/src/tabs/{Autopilot,Design,Gen3D,Jobs}.tsx
  • Task ID: W15-A14-TABS-A-2026-05-10
  • Release on merge (or now if PR is approved-and-green).

Ledger

03_implementation/docs/handoffs/GUI_VISUAL_E2E_COMPLETION_LEDGER_2026-05-10.md updated under the Wave 15 Phase 3 — Agent 14 row.

Test plan

  • CI green on develop merge
  • Run npm run build locally
  • Open #autopilot against a live backend; planner queue + agent activity show real rows; freeze/thaw shows "Blocked: not implemented" until W15 A20 lands the endpoint
  • Confirm Design/Gen3D/Jobs unchanged (no regressions)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Planner Queue panel to monitor active workflows with stage progress
    • Agent Activity Feed showing agent status, counts, and recent activity
    • Freeze/Thaw Controls to manage the autopilot loop
    • Redesigned Autopilot tab into a responsive two-column layout
  • Tests

    • Added Playwright screenshot harnesses to capture and verify Autopilot UI states
  • Documentation

    • Updated GUI visual completion ledger with Phase 3 progress and proof artifacts

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 10, 2026 •

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 15a8ea99-aba6-42eb-8e67-ad42c596604f

📥 Commits

Reviewing files that changed from the base of the PR and between 2daf04b and adc2ec0.

⛔ Files ignored due to path filters (7)
  • 03_implementation/proof/screenshots/w15-a14/autopilot-1536x1400.png is excluded by !**/*.png
  • 03_implementation/proof/screenshots/w15-a14/autopilot-freeze-thaw-detail.png is excluded by !**/*.png
  • 03_implementation/proof/screenshots/w15-a14/autopilot-fullpage.png is excluded by !**/*.png
  • 03_implementation/proof/screenshots/w15-a14/autopilot.png is excluded by !**/*.png
  • 03_implementation/proof/screenshots/w15-a14/design.png is excluded by !**/*.png
  • 03_implementation/proof/screenshots/w15-a14/gen3d.png is excluded by !**/*.png
  • 03_implementation/proof/screenshots/w15-a14/jobs.png is excluded by !**/*.png
📒 Files selected for processing (7)
  • 03_implementation/docs/handoffs/GUI_VISUAL_E2E_COMPLETION_LEDGER_2026-05-10.md
  • 03_implementation/ui/src/components/autopilot/AgentActivityFeed.tsx
  • 03_implementation/ui/src/components/autopilot/FreezeThawControls.tsx
  • 03_implementation/ui/src/components/autopilot/PlannerQueue.tsx
  • 03_implementation/ui/src/tabs/Autopilot.tsx
  • 03_implementation/ui/tests/screenshots/w15-a14-capture.mjs
  • 03_implementation/ui/tests/screenshots/w15-a14-verify-freeze-thaw.mjs
✅ Files skipped from review due to trivial changes (1)
  • 03_implementation/docs/handoffs/GUI_VISUAL_E2E_COMPLETION_LEDGER_2026-05-10.md
🚧 Files skipped from review as they are similar to previous changes (6)
  • 03_implementation/ui/tests/screenshots/w15-a14-verify-freeze-thaw.mjs
  • 03_implementation/ui/tests/screenshots/w15-a14-capture.mjs
  • 03_implementation/ui/src/components/autopilot/AgentActivityFeed.tsx
  • 03_implementation/ui/src/components/autopilot/FreezeThawControls.tsx
  • 03_implementation/ui/src/components/autopilot/PlannerQueue.tsx
  • 03_implementation/ui/src/tabs/Autopilot.tsx

📝 Walkthrough

Walkthrough

This PR adds three new Autopilot control panels—PlannerQueue, AgentActivityFeed, and FreezeThawControls—with polling and backend freeze/thaw wiring, integrates them into a responsive two-column Autopilot tab, updates the completion ledger, and adds Playwright scripts for screenshots and freeze/thaw verification.

Changes

Autopilot UI Components & Tab Integration

Layer / File(s) Summary
Documentation & Completion Record
03_implementation/docs/handoffs/GUI_VISUAL_E2E_COMPLETION_LEDGER_2026-05-10.md
Ledger and loop log updated to mark "Primary Tabs A" as landed on claude/w15-a14-tabs-a and record Agent 14's integration with proof artifact paths and branch lock/rebase reference.
Component Logic & State Management
03_implementation/ui/src/components/autopilot/AgentActivityFeed.tsx, 03_implementation/ui/src/components/autopilot/PlannerQueue.tsx, 03_implementation/ui/src/components/autopilot/FreezeThawControls.tsx
AgentActivityFeed initializes from optional props or polls adapters.getAgents() every 20s; PlannerQueue initializes from optional props or polls adapters.getActiveWorkflows() every 15s; FreezeThawControls manages mode/message/pending state and POSTs to bridge freeze/thaw endpoints, handling 404/405 as blocked and emitting proof events.
Component Rendering & UI Output
03_implementation/ui/src/components/autopilot/AgentActivityFeed.tsx, .../PlannerQueue.tsx, .../FreezeThawControls.tsx
AgentActivityFeed renders a status-sorted roster with active counter and conditional error/empty states; PlannerQueue shows workflow rows with stage/started time and status badges; FreezeThawControls renders freeze/thaw buttons, mode indicator, and message panel.
Helper Functions & Style Mapping
03_implementation/ui/src/components/autopilot/AgentActivityFeed.tsx, .../PlannerQueue.tsx, .../FreezeThawControls.tsx
statusWeight/statusDot for agents, workflowTone for workflows, UI tone selection, payloadSummary for backend responses, and describeError for thrown values.
Tab Layout & Wiring
03_implementation/ui/src/tabs/Autopilot.tsx
Root container updated to lg:grid-cols-12; left column (lg:col-span-7) preserves existing sections, right column (lg:col-span-5) stacks PlannerQueue, AgentActivityFeed, and FreezeThawControls; imports added.
E2E Testing & Screenshots
03_implementation/ui/tests/screenshots/w15-a14-capture.mjs, 03_implementation/ui/tests/screenshots/w15-a14-verify-freeze-thaw.mjs
Playwright capture script saves per-tab and tall autopilot screenshots; verification script checks DOM presence for planner queue, agent activity, and freeze/thaw elements and captures clipped or fallback screenshots.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 Three new panels hop into view on the right,
Polling and status dots keeping watch through the night,
Freeze and thaw buttons stand ready to try,
Screenshots captured tall, proofs stacked nearby—
A tidy tab split gives the controls room to write!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and specifically describes the main changes: addition of three new Autopilot components (planner queue, agent activity feed, and freeze/thaw controls) to the Autopilot tab as part of Wave 15 Agent 14.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/w15-a14-tabs-a

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements the 'Primary Tabs A' functionality, specifically enhancing the Autopilot tab with new live-data components: AgentActivityFeed, PlannerQueue, and FreezeThawControls. These components are integrated into the UI and wired to backend endpoints for real-time monitoring and control. Feedback suggests improving the portability of the new test scripts by removing hardcoded absolute paths, centralizing duplicated configuration logic for backend URLs, and abstracting direct fetch calls into the existing adapters layer for better architectural consistency.

Comment on lines +1 to +27
// Wave 15 A14 — confirm freeze/thaw element is present in autopilot DOM.
import { chromium } from "@playwright/test";
const BASE = process.env.W15_PREVIEW_URL || "http://127.0.0.1:4173";
const browser = await chromium.launch();
try {
const page = await browser.newPage({ viewport: { width: 1536, height: 1024 } });
page.on("console", (msg) => { if (msg.type() === "error") console.error(`[err] ${msg.text()}`); });
await page.goto(`${BASE}/#autopilot`, { waitUntil: "networkidle", timeout: 30_000 });
await page.waitForTimeout(1500);
const present = {
planner: await page.locator('[data-testid="autopilot-planner-queue"]').count(),
agents: await page.locator('[data-testid="autopilot-agent-activity"]').count(),
freezeThaw: await page.locator('[data-testid="autopilot-freeze-thaw"]').count(),
freezeBtn: await page.locator('[data-testid="autopilot-freeze-button"]').count(),
thawBtn: await page.locator('[data-testid="autopilot-thaw-button"]').count(),
};
console.log("DOM presence:", JSON.stringify(present, null, 2));
// Scroll the freeze/thaw into view and capture.
const el = page.locator('[data-testid="autopilot-freeze-thaw"]').first();
await el.scrollIntoViewIfNeeded({ timeout: 5000 }).catch(() => {});
await page.screenshot({ path: "G:/Github/Hermes3D/03_implementation/proof/screenshots/w15-a14/autopilot-freeze-thaw-detail.png", clip: await el.boundingBox().then((b) => ({ x: Math.max(b.x - 12, 0), y: Math.max(b.y - 12, 0), width: Math.min(b.width + 24, 1536), height: Math.min(b.height + 24, 1024) })) }).catch(async (e) => {
console.error("bbox screenshot failed:", e.message);
await page.screenshot({ path: "G:/Github/Hermes3D/03_implementation/proof/screenshots/w15-a14/autopilot-after-scroll.png" });
});
} finally {
await browser.close();
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The script uses hardcoded absolute Windows paths for saving screenshots (e.g., G:/Github/Hermes3D/...), which will cause it to fail on other systems or in CI. It also lacks necessary imports for path manipulation. I've updated the script to use relative paths and proper path utilities, consistent with w15-a14-capture.mjs.

// Wave 15 A14 — confirm freeze/thaw element is present in autopilot DOM.
import { chromium } from "@playwright/test";
import path from "node:path";
import url from "node:url";

const HERE = path.dirname(url.fileURLToPath(import.meta.url));
const REPO_ROOT = path.resolve(HERE, "../../../../");
const OUT_DIR = path.join(REPO_ROOT, "03_implementation/proof/screenshots/w15-a14");

const BASE = process.env.W15_PREVIEW_URL || "http://127.0.0.1:4173";
const browser = await chromium.launch();
try {
  const page = await browser.newPage({ viewport: { width: 1536, height: 1024 } });
  page.on("console", (msg) => { if (msg.type() === "error") console.error(`[err] ${msg.text()}`); });
  await page.goto(`${BASE}/#autopilot`, { waitUntil: "networkidle", timeout: 30_000 });
  await page.waitForTimeout(1500);
  const present = {
    planner: await page.locator('[data-testid="autopilot-planner-queue"]').count(),
    agents: await page.locator('[data-testid="autopilot-agent-activity"]').count(),
    freezeThaw: await page.locator('[data-testid="autopilot-freeze-thaw"]').count(),
    freezeBtn: await page.locator('[data-testid="autopilot-freeze-button"]').count(),
    thawBtn: await page.locator('[data-testid="autopilot-thaw-button"]').count(),
  };
  console.log("DOM presence:", JSON.stringify(present, null, 2));
  // Scroll the freeze/thaw into view and capture.
  const el = page.locator('[data-testid="autopilot-freeze-thaw"]').first();
  await el.scrollIntoViewIfNeeded({ timeout: 5000 }).catch(() => {});
  const outPath = path.join(OUT_DIR, "autopilot-freeze-thaw-detail.png");
  await page.screenshot({ path: outPath, clip: await el.boundingBox().then((b) => ({ x: Math.max(b.x - 12, 0), y: Math.max(b.y - 12, 0), width: Math.min(b.width + 24, 1536), height: Math.min(b.height + 24, 1024) })) }).catch(async (e) => {
    console.error("bbox screenshot failed:", e.message);
    const fallbackPath = path.join(OUT_DIR, "autopilot-after-scroll.png");
    await page.screenshot({ path: fallbackPath });
  });
} finally {
  await browser.close();
}

Comment on lines +20 to +28
type HermesImportMeta = ImportMeta & {
env: {
VITE_HERMES3D_BRIDGE_PORT?: string;
};
};

const DEFAULT_BRIDGE_PORT = "8765";
const LIVE_BRIDGE_PORT = (import.meta as HermesImportMeta).env.VITE_HERMES3D_BRIDGE_PORT ?? DEFAULT_BRIDGE_PORT;
const LIVE_BASE_URL = `http://127.0.0.1:${LIVE_BRIDGE_PORT}`;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The HermesImportMeta type definition and the LIVE_BASE_URL construction logic are duplicated from Autopilot.tsx. This duplication makes the configuration fragile and harder to maintain. Consider centralizing this logic in a shared constants file or within the adapters layer to ensure consistency across the application.

Comment on lines +42 to +47
const response = await fetch(`${LIVE_BASE_URL}/api/autopilot/${path}`, {
method: "POST",
headers: { Accept: "application/json", "Content-Type": "application/json" },
body: JSON.stringify({ source: "autopilot.freeze_thaw_controls" }),
cache: "no-store",
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This component uses fetch directly to interact with the backend API. Following the project's established pattern, these network calls should be abstracted into the adapters layer. This improves maintainability, allows for easier mocking in tests, and centralizes error handling and base URL management.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@03_implementation/docs/handoffs/GUI_VISUAL_E2E_COMPLETION_LEDGER_2026-05-10.md`:
- Line 37: Update the screenshot count in the "Primary Tabs A
(Autopilot/Design/Gen3D/Jobs)" entry in
GUI_VISUAL_E2E_COMPLETION_LEDGER_2026-05-10.md: change the phrase "4 screenshots
in `proof/screenshots/w15-a14/`" to "6 screenshots in
`proof/screenshots/w15-a14/`" so it matches the six files listed later; ensure
the updated sentence remains in the same entry that starts with "Primary Tabs A
(Autopilot/Design/Gen3D/Jobs)".

In `@03_implementation/ui/src/components/autopilot/PlannerQueue.tsx`:
- Around line 100-101: The UI assumes workflow.stages is non-empty and
workflow.active_stage is in-range, causing outputs like "1/0" when stages is []
or active_stage is invalid; in PlannerQueue (the JSX that renders "stage
{workflow.active_stage + 1}/{workflow.stages.length}"), guard rendering by
checking workflow.stages && workflow.stages.length > 0 and that
workflow.active_stage is a number within [0, workflow.stages.length - 1];
compute a safe displayActive and totalStages (or render a fallback like "—" or
"0/0") before interpolation and use those safe values in place of the current
expression so out-of-range or empty stage arrays don't produce invalid UI.

In `@03_implementation/ui/tests/screenshots/w15-a14-verify-freeze-thaw.mjs`:
- Around line 10-17: The current DOM presence check only logs counts (present
object) and can silently pass; replace these logs with hard assertions that fail
the test when required elements are missing by asserting the locator counts for
freezeThaw, freezeBtn, thawBtn (and optionally planner and agents) are > 0; use
Playwright's expect/assert (e.g., expect(await
page.locator(...).count()).toBeGreaterThan(0)) or your test framework's
equivalent and import expect if not already present so the test fails when
selectors are absent.
- Around line 21-23: The screenshots use hardcoded absolute Windows paths in the
page.screenshot calls (see page.screenshot and the fallback screenshot) which
will fail on other machines; update both calls to build repo-relative output
paths instead (use process.cwd() or __dirname with path.join/path.resolve) and
ensure the target directory is created before calling page.screenshot; modify
the path arguments in the page.screenshot invocations and any related error
handler so they reference the repo-relative
"03_implementation/proof/screenshots/w15-a14" location rather than "G:/...".
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ff790e0f-9ec5-4499-8799-7df26b664f66

📥 Commits

Reviewing files that changed from the base of the PR and between 3934eb8 and 2daf04b.

⛔ Files ignored due to path filters (7)
  • 03_implementation/proof/screenshots/w15-a14/autopilot-1536x1400.png is excluded by !**/*.png
  • 03_implementation/proof/screenshots/w15-a14/autopilot-freeze-thaw-detail.png is excluded by !**/*.png
  • 03_implementation/proof/screenshots/w15-a14/autopilot-fullpage.png is excluded by !**/*.png
  • 03_implementation/proof/screenshots/w15-a14/autopilot.png is excluded by !**/*.png
  • 03_implementation/proof/screenshots/w15-a14/design.png is excluded by !**/*.png
  • 03_implementation/proof/screenshots/w15-a14/gen3d.png is excluded by !**/*.png
  • 03_implementation/proof/screenshots/w15-a14/jobs.png is excluded by !**/*.png
📒 Files selected for processing (7)
  • 03_implementation/docs/handoffs/GUI_VISUAL_E2E_COMPLETION_LEDGER_2026-05-10.md
  • 03_implementation/ui/src/components/autopilot/AgentActivityFeed.tsx
  • 03_implementation/ui/src/components/autopilot/FreezeThawControls.tsx
  • 03_implementation/ui/src/components/autopilot/PlannerQueue.tsx
  • 03_implementation/ui/src/tabs/Autopilot.tsx
  • 03_implementation/ui/tests/screenshots/w15-a14-capture.mjs
  • 03_implementation/ui/tests/screenshots/w15-a14-verify-freeze-thaw.mjs

| 12 | Dashboard Modes | _pending_ |
| 13 | Source OS + 60 Apps | _pending_ |
| 14 | Primary Tabs A (Autopilot/Design/Gen3D/Jobs) | _pending_ |
| 14 | Primary Tabs A (Autopilot/Design/Gen3D/Jobs) | claude/w15-a14-tabs-a — Autopilot: +PlannerQueue/+AgentActivityFeed/+FreezeThawControls components wired to live `/api/workflows/active`, `/api/agents`, freeze/thaw endpoints (blocked-honest when not implemented). Design/Gen3D/Jobs already FULLY_WIRED per W15-A3 audit; verified no fake fallback + tsc/build PASS. 4 screenshots in `proof/screenshots/w15-a14/`. |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update screenshot count to match recorded artifacts.

Line 37 says “4 screenshots,” but Line 60 lists 6 files. Keeping this consistent avoids confusion in proof tracking.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@03_implementation/docs/handoffs/GUI_VISUAL_E2E_COMPLETION_LEDGER_2026-05-10.md`
at line 37, Update the screenshot count in the "Primary Tabs A
(Autopilot/Design/Gen3D/Jobs)" entry in
GUI_VISUAL_E2E_COMPLETION_LEDGER_2026-05-10.md: change the phrase "4 screenshots
in `proof/screenshots/w15-a14/`" to "6 screenshots in
`proof/screenshots/w15-a14/`" so it matches the six files listed later; ensure
the updated sentence remains in the same entry that starts with "Primary Tabs A
(Autopilot/Design/Gen3D/Jobs)".

Comment on lines +100 to +101
stage {workflow.active_stage + 1}/{workflow.stages.length} · started{" "}
{workflow.started_utc ? new Date(workflow.started_utc).toLocaleTimeString() : "—"}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Guard stage progress rendering against empty/out-of-range stage data.

Line 100 assumes workflow.stages.length > 0 and a valid active_stage. If the backend returns stages: [] or an out-of-bounds index, the UI can show invalid progress like 1/0.

Proposed fix
-                stage {workflow.active_stage + 1}/{workflow.stages.length} · started{" "}
+                {(() => {
+                  const total = workflow.stages.length;
+                  const current =
+                    total > 0
+                      ? Math.min(Math.max(workflow.active_stage, 0), total - 1) + 1
+                      : 0;
+                  return `stage ${current}/${total}`;
+                })()} · started{" "}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
stage {workflow.active_stage + 1}/{workflow.stages.length} · started{" "}
{workflow.started_utc ? new Date(workflow.started_utc).toLocaleTimeString() : "—"}
{(() => {
const total = workflow.stages.length;
const current =
total > 0
? Math.min(Math.max(workflow.active_stage, 0), total - 1) + 1
: 0;
return `stage ${current}/${total}`;
})()} · started{" "}
{workflow.started_utc ? new Date(workflow.started_utc).toLocaleTimeString() : "—"}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@03_implementation/ui/src/components/autopilot/PlannerQueue.tsx` around lines
100 - 101, The UI assumes workflow.stages is non-empty and workflow.active_stage
is in-range, causing outputs like "1/0" when stages is [] or active_stage is
invalid; in PlannerQueue (the JSX that renders "stage {workflow.active_stage +
1}/{workflow.stages.length}"), guard rendering by checking workflow.stages &&
workflow.stages.length > 0 and that workflow.active_stage is a number within [0,
workflow.stages.length - 1]; compute a safe displayActive and totalStages (or
render a fallback like "—" or "0/0") before interpolation and use those safe
values in place of the current expression so out-of-range or empty stage arrays
don't produce invalid UI.

Comment on lines +10 to +17
const present = {
planner: await page.locator('[data-testid="autopilot-planner-queue"]').count(),
agents: await page.locator('[data-testid="autopilot-agent-activity"]').count(),
freezeThaw: await page.locator('[data-testid="autopilot-freeze-thaw"]').count(),
freezeBtn: await page.locator('[data-testid="autopilot-freeze-button"]').count(),
thawBtn: await page.locator('[data-testid="autopilot-thaw-button"]').count(),
};
console.log("DOM presence:", JSON.stringify(present, null, 2));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Turn presence logging into hard assertions.

Right now the script only logs counts and can exit successfully even if freeze/thaw UI is missing. A verification script should fail when required selectors are absent.

Proposed fix
   const present = {
     planner: await page.locator('[data-testid="autopilot-planner-queue"]').count(),
     agents: await page.locator('[data-testid="autopilot-agent-activity"]').count(),
     freezeThaw: await page.locator('[data-testid="autopilot-freeze-thaw"]').count(),
     freezeBtn: await page.locator('[data-testid="autopilot-freeze-button"]').count(),
     thawBtn: await page.locator('[data-testid="autopilot-thaw-button"]').count(),
   };
   console.log("DOM presence:", JSON.stringify(present, null, 2));
+  for (const [key, count] of Object.entries(present)) {
+    if (count < 1) {
+      throw new Error(`Missing required element: ${key}`);
+    }
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const present = {
planner: await page.locator('[data-testid="autopilot-planner-queue"]').count(),
agents: await page.locator('[data-testid="autopilot-agent-activity"]').count(),
freezeThaw: await page.locator('[data-testid="autopilot-freeze-thaw"]').count(),
freezeBtn: await page.locator('[data-testid="autopilot-freeze-button"]').count(),
thawBtn: await page.locator('[data-testid="autopilot-thaw-button"]').count(),
};
console.log("DOM presence:", JSON.stringify(present, null, 2));
const present = {
planner: await page.locator('[data-testid="autopilot-planner-queue"]').count(),
agents: await page.locator('[data-testid="autopilot-agent-activity"]').count(),
freezeThaw: await page.locator('[data-testid="autopilot-freeze-thaw"]').count(),
freezeBtn: await page.locator('[data-testid="autopilot-freeze-button"]').count(),
thawBtn: await page.locator('[data-testid="autopilot-thaw-button"]').count(),
};
console.log("DOM presence:", JSON.stringify(present, null, 2));
for (const [key, count] of Object.entries(present)) {
if (count < 1) {
throw new Error(`Missing required element: ${key}`);
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@03_implementation/ui/tests/screenshots/w15-a14-verify-freeze-thaw.mjs` around
lines 10 - 17, The current DOM presence check only logs counts (present object)
and can silently pass; replace these logs with hard assertions that fail the
test when required elements are missing by asserting the locator counts for
freezeThaw, freezeBtn, thawBtn (and optionally planner and agents) are > 0; use
Playwright's expect/assert (e.g., expect(await
page.locator(...).count()).toBeGreaterThan(0)) or your test framework's
equivalent and import expect if not already present so the test fails when
selectors are absent.

Comment on lines +21 to +23
await page.screenshot({ path: "G:/Github/Hermes3D/03_implementation/proof/screenshots/w15-a14/autopilot-freeze-thaw-detail.png", clip: await el.boundingBox().then((b) => ({ x: Math.max(b.x - 12, 0), y: Math.max(b.y - 12, 0), width: Math.min(b.width + 24, 1536), height: Math.min(b.height + 24, 1024) })) }).catch(async (e) => {
console.error("bbox screenshot failed:", e.message);
await page.screenshot({ path: "G:/Github/Hermes3D/03_implementation/proof/screenshots/w15-a14/autopilot-after-scroll.png" });

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Replace hardcoded Windows screenshot paths with repo-relative output paths.

Lines 21–23 use machine-specific absolute paths (G:/...), which breaks on other environments and contributors’ machines.

Proposed fix
+import fs from "node:fs";
+import path from "node:path";
+import url from "node:url";
+
+const HERE = path.dirname(url.fileURLToPath(import.meta.url));
+const REPO_ROOT = path.resolve(HERE, "../../../..");
+const OUT_DIR = path.join(REPO_ROOT, "03_implementation/proof/screenshots/w15-a14");
+fs.mkdirSync(OUT_DIR, { recursive: true });
...
-  await page.screenshot({ path: "G:/Github/Hermes3D/03_implementation/proof/screenshots/w15-a14/autopilot-freeze-thaw-detail.png", clip: await el.boundingBox().then((b) => ({ x: Math.max(b.x - 12, 0), y: Math.max(b.y - 12, 0), width: Math.min(b.width + 24, 1536), height: Math.min(b.height + 24, 1024) })) }).catch(async (e) => {
+  await page.screenshot({ path: path.join(OUT_DIR, "autopilot-freeze-thaw-detail.png"), clip: await el.boundingBox().then((b) => ({ x: Math.max(b.x - 12, 0), y: Math.max(b.y - 12, 0), width: Math.min(b.width + 24, 1536), height: Math.min(b.height + 24, 1024) })) }).catch(async (e) => {
     console.error("bbox screenshot failed:", e.message);
-    await page.screenshot({ path: "G:/Github/Hermes3D/03_implementation/proof/screenshots/w15-a14/autopilot-after-scroll.png" });
+    await page.screenshot({ path: path.join(OUT_DIR, "autopilot-after-scroll.png") });
   });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
await page.screenshot({ path: "G:/Github/Hermes3D/03_implementation/proof/screenshots/w15-a14/autopilot-freeze-thaw-detail.png", clip: await el.boundingBox().then((b) => ({ x: Math.max(b.x - 12, 0), y: Math.max(b.y - 12, 0), width: Math.min(b.width + 24, 1536), height: Math.min(b.height + 24, 1024) })) }).catch(async (e) => {
console.error("bbox screenshot failed:", e.message);
await page.screenshot({ path: "G:/Github/Hermes3D/03_implementation/proof/screenshots/w15-a14/autopilot-after-scroll.png" });
import fs from "node:fs";
import path from "node:path";
import url from "node:url";
const HERE = path.dirname(url.fileURLToPath(import.meta.url));
const REPO_ROOT = path.resolve(HERE, "../../../..");
const OUT_DIR = path.join(REPO_ROOT, "03_implementation/proof/screenshots/w15-a14");
fs.mkdirSync(OUT_DIR, { recursive: true });
await page.screenshot({ path: path.join(OUT_DIR, "autopilot-freeze-thaw-detail.png"), clip: await el.boundingBox().then((b) => ({ x: Math.max(b.x - 12, 0), y: Math.max(b.y - 12, 0), width: Math.min(b.width + 24, 1536), height: Math.min(b.height + 24, 1024) })) }).catch(async (e) => {
console.error("bbox screenshot failed:", e.message);
await page.screenshot({ path: path.join(OUT_DIR, "autopilot-after-scroll.png") });
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@03_implementation/ui/tests/screenshots/w15-a14-verify-freeze-thaw.mjs` around
lines 21 - 23, The screenshots use hardcoded absolute Windows paths in the
page.screenshot calls (see page.screenshot and the fallback screenshot) which
will fail on other machines; update both calls to build repo-relative output
paths instead (use process.cwd() or __dirname with path.join/path.resolve) and
ensure the target directory is created before calling page.screenshot; modify
the path arguments in the page.screenshot invocations and any related error
handler so they reference the repo-relative
"03_implementation/proof/screenshots/w15-a14" location rather than "G:/...".

@Ghenghis
Ghenghis force-pushed the claude/w15-a14-tabs-a branch from 2daf04b to 7271056 Compare May 10, 2026 22:51
…/thaw

Wave 15 — Agent 14 (Primary Tabs A). Adds three new components for the
Autopilot tab matching the Images-GUI reference for
`02-primary-pages/primary-tabs-autopilot-design-gen3d-jobs.png`:

- `components/autopilot/PlannerQueue.tsx` — read-only feed of active
  workflows from `adapters.getActiveWorkflows()` (live
  `/api/workflows/active`). Empty/error states are explicit, no fake
  fallback data; auto-refresh every 15s.
- `components/autopilot/AgentActivityFeed.tsx` — live agent roster from
  `adapters.getAgents()` (live `/api/agents`); sorts active first, shows
  task count + model provider + last activity. 20s refresh.
- `components/autopilot/FreezeThawControls.tsx` — POSTs to
  `/api/autopilot/freeze` and `/api/autopilot/thaw`. The current backend
  has not implemented these endpoints (verified against
  `src/hermes3d/api/routes/autopilot.py` 2026-05-10); a 404/405 surfaces
  an explicit "Blocked: /api/autopilot/<path> is not implemented on this
  backend (W15 A20 owns the endpoint)." No fake "frozen" state ever; W15
  A20 owns the backend route work.

Autopilot tab layout switches from a single column of three sections to
a 12-column grid: left col (lg:col-span-7) keeps READINESS / SAFE
ACTIONS / GUARDRAILS; new right col (lg:col-span-5) stacks PLANNER QUEUE
/ AGENT ACTIVITY / FREEZE-THAW.

Design / Gen3D / Jobs tabs already FULLY_WIRED per W15_A3 audit —
unchanged here, verified by re-running tsc + build + capturing 4
screenshots at 1536x1024 (`proof/screenshots/w15-a14/`).

Self-audit
- `npx tsc --noEmit` PASS
- `npm run build` PASS (vite 1.14s)
- 4 PNG screenshots captured per tab (autopilot, design, gen3d, jobs)
  plus autopilot-1536x1400 and autopilot-freeze-thaw-detail for the
  full Autopilot view including freeze/thaw card.
- Honest "blocked" / "loading" / "unreachable" empty states for every
  data path; no MOCK_PRINTERS/MOCK_JOBS imports introduced.

Sources cited
- Official React composition: small read-only components with their own
  `useEffect` polling, similar to the existing AutopilotConsole +
  AutopilotTab pattern in this repo.
- Cross-project: GitHub Actions runs UI — table-with-status-pill pattern
  used in `AgentActivityFeed` (one row per agent, status dot, sortable
  by status).

Refs: W15 24-agent loop, A14 Primary Tabs A; Images-GUI ref
`02-primary-pages/primary-tabs-autopilot-design-gen3d-jobs.png`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Ghenghis
Ghenghis force-pushed the claude/w15-a14-tabs-a branch from 7271056 to adc2ec0 Compare May 10, 2026 23:15
@Ghenghis
Ghenghis merged commit 35af649 into develop May 10, 2026
16 checks passed
@Ghenghis
Ghenghis deleted the claude/w15-a14-tabs-a branch May 10, 2026 23:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant