Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 72 additions & 70 deletions BUILD_REPORT.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,89 +2,87 @@

## sprint objective

Implement Sprint 6F by extending the AliceBot web shell so approved approvals can be executed from `/approvals` and their resulting execution state can be reviewed from `/approvals` and `/tasks` using only the shipped approval-execution and tool-execution read endpoints.
Implement Sprint 6G by turning `/chat` into a dual-mode operator conversation surface with:

- assistant response mode backed by `POST /v0/responses`
- governed request mode retained through `POST /v0/approvals/requests`

The sprint stays inside the shipped backend seams and keeps the two behaviors visibly separate.

## completed work

- extended `apps/web/lib/api.ts` with typed execution support for:
- `POST /v0/approvals/{approval_id}/execute`
- `GET /v0/tool-executions`
- `GET /v0/tool-executions/{execution_id}`
- added fixture-backed execution records in `apps/web/lib/fixtures.ts` so fixture mode now covers:
- approved but not executed
- executed task and execution review
- updated `apps/web/app/approvals/page.tsx` to:
- discover linked execution records for the selected approval
- surface explicit live unavailable state when execution review cannot be loaded
- keep fixture fallback explicit when live API configuration is absent
- updated `apps/web/app/tasks/page.tsx` to:
- read latest execution detail from `task.latest_execution_id`
- fall back to fixture execution detail only when a matching fixture exists
- surface explicit unavailable messaging when a live execution read fails without fixture coverage
- extended `apps/web/components/approval-actions.tsx` to:
- keep approve/reject for pending approvals
- show execute for eligible approved approvals
- show bounded loading, success, failure, and read-only states
- extended `apps/web/components/approval-detail.tsx` and `apps/web/components/task-summary.tsx` with the new bounded `apps/web/components/execution-summary.tsx`
- updated `apps/web/components/task-step-list.tsx` to make execution linkage and blocked reasons clearer inside the existing step timeline
- refined `apps/web/app/globals.css` for the scoped surfaces with stronger containment, calmer grouping, better wrapping behavior, and more stable responsive stacking
- added or updated narrow frontend coverage in:
- updated `apps/web/app/chat/page.tsx` to:
- make assistant mode the default `/chat` state
- add an explicit mode toggle between assistant chat and governed request submission
- seed fixture history only when live API configuration is absent
- keep the side rail mode-specific so supporting guidance stays relevant instead of noisy
- added `apps/web/components/mode-toggle.tsx` as a stable two-state switch with clear labeling and active-state emphasis
- added `apps/web/components/response-composer.tsx` to:
- submit normal assistant questions through `POST /v0/responses`
- keep thread identity explicit
- provide explicit fixture preview fallback when live API configuration is absent
- added `apps/web/components/response-history.tsx` to show bounded assistant history with:
- operator prompt
- assistant reply
- model metadata
- compile and response trace summaries
- direct links into `/traces`
- refined `apps/web/components/request-composer.tsx` so governed mode reads as an intentional approval-gated workflow instead of a chat-like surface
- extended `apps/web/lib/api.ts` with typed assistant-response submission support for `POST /v0/responses`
- extended `apps/web/lib/fixtures.ts` with assistant response fixtures, fixture trace coverage, and deterministic preview entries
- refined `apps/web/app/globals.css` for the scoped `/chat` surface with:
- stronger hierarchy
- calmer spacing
- bounded history panels
- more deliberate prompt/reply grouping
- safer wrapping for long ids, trace references, and body text
- cleaner mobile stacking for the mode switch and chat workspace
- added narrow frontend coverage in:
- `apps/web/lib/api.test.ts`
- `apps/web/components/approval-actions.test.tsx`
- `apps/web/components/execution-summary.test.tsx`
- `apps/web/app/chat/page.test.tsx`
- `apps/web/components/response-composer.test.tsx`
- `apps/web/components/response-history.test.tsx`

## incomplete work

- no scoped sprint deliverables remain incomplete in code
- intentionally not added:
- backend changes
- new routes
- execution mutation beyond the shipped approval execute seam
- execution filtering, search, or pagination
- broader task workflow redesign outside `/approvals` and `/tasks`
- thread browsing or thread creation UI
- auth changes
- new routes outside `/chat`
- hidden tool routing or autonomous action behavior

## files changed
## exact /chat files and components updated

- `apps/web/app/approvals/page.tsx`
- `apps/web/app/tasks/page.tsx`
- `apps/web/app/chat/page.tsx`
- `apps/web/app/chat/page.test.tsx`
- `apps/web/app/globals.css`
- `apps/web/components/approval-actions.tsx`
- `apps/web/components/approval-detail.tsx`
- `apps/web/components/task-summary.tsx`
- `apps/web/components/task-step-list.tsx`
- `apps/web/components/request-composer.tsx`
- `apps/web/components/response-composer.tsx`
- `apps/web/components/response-history.tsx`
- `apps/web/components/mode-toggle.tsx`
- `apps/web/components/status-badge.tsx`
- `apps/web/components/execution-summary.tsx`
- `apps/web/lib/api.ts`
- `apps/web/lib/fixtures.ts`
- `apps/web/lib/api.test.ts`
- `apps/web/components/approval-actions.test.tsx`
- `apps/web/components/execution-summary.test.tsx`
- `apps/web/components/response-composer.test.tsx`
- `apps/web/components/response-history.test.tsx`
- `BUILD_REPORT.md`

## route backing mode

- `/approvals` is:
- live-API-backed for approval list/detail and linked execution review when API configuration is present
- assistant mode in `/chat` is:
- live-API-backed when API configuration is present
- fixture-backed when API configuration is absent
- explicitly unavailable for linked execution review when live execution reads fail
- `/tasks` is:
- live-API-backed for task detail, step detail, and latest execution review when API configuration is present
- governed request mode in `/chat` is:
- live-API-backed when API configuration is present
- fixture-backed when API configuration is absent
- mixed only when a live task falls back to fixture execution detail

## backend endpoints consumed

- `POST /v0/approvals/{approval_id}/execute`
- `GET /v0/tool-executions`
- `GET /v0/tool-executions/{execution_id}`
- existing carried-forward reads already used by the shell:
- `GET /v0/approvals`
- `GET /v0/approvals/{approval_id}`
- `POST /v0/approvals/{approval_id}/approve`
- `POST /v0/approvals/{approval_id}/reject`
- `GET /v0/tasks`
- `GET /v0/tasks/{task_id}`
- `GET /v0/tasks/{task_id}/steps`
- `POST /v0/responses`
- `POST /v0/approvals/requests`

## exact commands run

Expand All @@ -96,19 +94,22 @@ Implement Sprint 6F by extending the AliceBot web shell so approved approvals ca

- lint result: PASS
- test result: PASS
- `4` test files passed
- `20` tests passed
- `7` test files passed
- `28` tests passed
- build result: PASS

## desktop and mobile visual verification notes

- no browser-driven visual QA pass was executed in this turn
- desktop note:
- code inspection indicates `/approvals` and `/tasks` now use stronger internal grouping for action handling and execution review
- ids, badges, and payload snapshots have explicit wrapping and overflow handling inside bounded cards
- assistant mode now presents the composer and bounded response history as two coordinated panels instead of one long undifferentiated form
- the mode switch is visible near the page header and reads as a stable route-level decision rather than an inline afterthought
- response prompt, reply, ids, and trace summaries all use explicit containment styles with overflow wrapping
- live-configured `/chat` now starts empty in both modes instead of showing synthetic fixture history
- mobile note:
- the shared shell still collapses the split layouts to one column below the existing breakpoint
- execution review, action bars, and buttons now stack into full-width rows to preserve containment on narrow screens
- the mode switch collapses to one column below the existing breakpoint
- the assistant workspace collapses from a two-panel layout to one column so the composer remains primary and the history panel follows cleanly
- buttons continue to expand to full width on narrow screens to avoid cramped action rows

## blockers/issues

Expand All @@ -117,14 +118,15 @@ Implement Sprint 6F by extending the AliceBot web shell so approved approvals ca

## recommended next step

Run a browser-based QA pass against a live configured backend to validate:
- the execute transition from approved to executed or blocked
- the exact empty/unavailable messaging in live failure cases
- the density of output snapshots on long real-world payloads
Run a browser-based QA pass against both assistant mode and governed mode to validate:

- real long-form assistant replies in the bounded history panel
- mode-switch readability and perceived hierarchy on tablet widths
- trace-link destinations against a live configured backend

## intentionally deferred after this sprint

- thread browsing, thread create flows, or any broader conversation management UI
- backend changes beyond the shipped `/v0/responses` and `/v0/approvals/requests` seams
- any Gmail, Calendar, auth, runner, or broader workflow expansion
- any execution list filters, sorting controls, or search UI
- any task-step mutation UI beyond existing backend reads
- any redesign outside the scoped `/approvals` and `/tasks` review surfaces
- redesign of unrelated routes outside the scoped `/chat` surface
30 changes: 15 additions & 15 deletions REVIEW_REPORT.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,36 @@ PASS

## criteria met

- The sprint stayed a UI sprint and did not widen backend scope. The implementation remains confined to the web shell and uses only the shipped approval/task/execution seams.
- The UI can trigger `POST /v0/approvals/{approval_id}/execute` for eligible approved approvals through `apps/web/lib/api.ts` and `apps/web/components/approval-actions.tsx`.
- The UI can show resulting execution state using existing execution and task reads in `apps/web/app/approvals/page.tsx`, `apps/web/app/tasks/page.tsx`, `apps/web/components/approval-detail.tsx`, `apps/web/components/task-summary.tsx`, `apps/web/components/task-step-list.tsx`, and `apps/web/components/execution-summary.tsx`.
- `/approvals` and `/tasks` make execution state understandable without widening backend scope. Loading, success, blocked/failure, empty, and unavailable states are all explicitly surfaced.
- When API configuration is absent, execution controls degrade to explicit fixture/read-only behavior rather than broken interaction.
- The sprint stayed within the listed in-scope screens, components, and files.
- `DESIGN_SYSTEM.md` was followed materially. The execution controls and review surfaces remain bounded and consistent with the existing operator-shell tone.
- `BUILD_REPORT.md` is aligned with the implemented sprint scope and now reflects the current verification totals.
- The sprint stayed a UI sprint and did not widen backend scope. The implementation remains confined to the web shell and uses only the shipped seams `POST /v0/responses` and `POST /v0/approvals/requests`.
- `/chat` supports assistant response mode via `POST /v0/responses` through `apps/web/lib/api.ts` and `apps/web/components/response-composer.tsx`.
- `/chat` retains governed request mode via the existing approval-request seam through `apps/web/components/request-composer.tsx`.
- The mode switch is explicit and understandable. `apps/web/components/mode-toggle.tsx` keeps assistant and governed modes visibly separate.
- Assistant replies and trace summaries are visible in bounded history panels via `apps/web/components/response-history.tsx`.
- Fixture fallback is now explicit and correctly scoped to the no-config path. Live-configured `/chat` starts empty in both modes instead of showing seeded synthetic history. This is enforced in `apps/web/app/chat/page.tsx` and covered by `apps/web/app/chat/page.test.tsx`.
- The sprint stayed within the exact in-scope files and components listed in the sprint packet.
- The UI continues to follow `DESIGN_SYSTEM.md` materially. The `/chat` surface remains restrained, bounded, and readable on the inspected responsive layouts.
- `BUILD_REPORT.md` now matches the implemented route-backing behavior and current verification totals.
- Verification passed in `apps/web`:
- `npm run lint`
- `npm test`
- `npm run build`
- current totals: `4` test files, `20` tests
- `next build` did not leave tracked churn in `apps/web/tsconfig.json` or `apps/web/next-env.d.ts`.
- current totals: `7` test files, `28` tests

## criteria missed

- None.

## quality issues

- No blocking quality issues found in the current Sprint 6F implementation.
- No blocking quality issues found in the current Sprint 6G implementation.

## regression risks

- Residual risk is limited to live-data wording and density because the visual notes are still based on code inspection rather than a browser QA pass against a configured backend. That does not block sprint acceptance.
- Residual risk is limited to browser-level presentation because no live browser QA pass was executed in this review cycle. That does not block sprint acceptance.

## docs issues

- No blocking docs issues remain for Sprint 6F.
- No blocking docs issues remain for Sprint 6G.

## should anything be added to RULES.md?

Expand All @@ -47,5 +47,5 @@ PASS

## recommended next action

- Sprint 6F can be considered review-passed.
- Next follow-up should be a browser-based QA pass against a live configured backend to validate the approved-to-executed or blocked transition and the exact operator-facing wording in live failure cases.
- Sprint 6G can be considered review-passed.
- Next follow-up should be a browser-based QA pass against a live configured backend to validate long-form assistant replies, mode-switch hierarchy on tablet widths, and trace-link destinations.
88 changes: 88 additions & 0 deletions apps/web/app/chat/page.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import React from "react";
import { cleanup, render, screen } from "@testing-library/react";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";

import ChatPage from "./page";

const { getApiConfigMock, hasLiveApiConfigMock } = vi.hoisted(() => ({
getApiConfigMock: vi.fn(),
hasLiveApiConfigMock: vi.fn(),
}));

vi.mock("next/link", () => ({
default: ({
href,
children,
className,
"aria-current": ariaCurrent,
}: {
href: string;
children: React.ReactNode;
className?: string;
"aria-current"?: string;
}) => (
<a href={href} className={className} aria-current={ariaCurrent}>
{children}
</a>
),
}));

vi.mock("../../lib/api", async () => {
const actual = await vi.importActual("../../lib/api");
return {
...actual,
getApiConfig: getApiConfigMock,
hasLiveApiConfig: hasLiveApiConfigMock,
};
});

describe("ChatPage", () => {
beforeEach(() => {
getApiConfigMock.mockReset();
hasLiveApiConfigMock.mockReset();
});

afterEach(() => {
cleanup();
});

it("does not seed fixture assistant history when live API configuration is present", async () => {
getApiConfigMock.mockReturnValue({
apiBaseUrl: "https://api.example.com",
userId: "user-1",
defaultThreadId: "thread-1",
defaultToolId: "tool-1",
});
hasLiveApiConfigMock.mockReturnValue(true);

render(await ChatPage({ searchParams: Promise.resolve({}) }));

expect(screen.getByText("Live submission enabled")).toBeInTheDocument();
expect(screen.getByText("No assistant replies yet")).toBeInTheDocument();
expect(screen.queryByText("Fixture response preview")).not.toBeInTheDocument();
expect(screen.queryByText(/What do I need to know about the last Vitamin D request/i)).not.toBeInTheDocument();
});

it("does not seed fixture governed-request history when live API configuration is present", async () => {
getApiConfigMock.mockReturnValue({
apiBaseUrl: "https://api.example.com",
userId: "user-1",
defaultThreadId: "thread-1",
defaultToolId: "tool-1",
});
hasLiveApiConfigMock.mockReturnValue(true);

render(
await ChatPage({
searchParams: Promise.resolve({
mode: "request",
}),
}),
);

expect(screen.getByText("Live submission enabled")).toBeInTheDocument();
expect(screen.getByText("No governed requests yet")).toBeInTheDocument();
expect(screen.queryByText("Fixture preview")).not.toBeInTheDocument();
expect(screen.queryByText(/place_order \/ supplements/i)).not.toBeInTheDocument();
});
});
Loading