Repository navigation
feat(frontend): add the Friction Log page - #2484
Conversation
roborev: Combined Review (
|
ad4eb36 to
ae8b6b4
Compare
roborev: Combined Review (
|
ae8b6b4 to
6338d6c
Compare
roborev: Combined Review (
|
6338d6c to
8b50345
Compare
roborev: Combined Review (
|
8b50345 to
ac7aee5
Compare
roborev: Combined Review (
|
ac7aee5 to
626d34e
Compare
roborev: Combined Review (
|
626d34e to
7d7d3a2
Compare
roborev: Combined Review (
|
7d7d3a2 to
67c2941
Compare
roborev: Combined Review (
|
67c2941 to
ddf4de4
Compare
roborev: Combined Review (
|
ddf4de4 to
b02b9f9
Compare
The Friction Log could be read only from the API, CLI or MCP. This page shows a day's digest in the app: P0 alerts and new or recurring patterns first, then each kind of finding with a link to the session message. It can also build missing days when the server allows it. The session signal panel lists the findings for the open session, and Quality links to the page. This is #1937 rebuilt on the CLI layer. The merged review stores a smaller summary than the one #1937 was written against, so the spend and persona panels are gone. Their data is not in the stored summary. The empty-state copy now says that review is opt-in, which matches main. The Markdown export reports a new `friction_markdown` export format to telemetry, so these downloads are counted apart from session exports. The screenshot capture from #1937 is left for the release screenshot pass. Listing an image that the assets branch does not have yet would stop the docs build from hydrating its assets.
The URL and the open digest could disagree. After a build, the page opened the latest digest but kept the old date in the URL. Browser history did not change the open digest. A date picked while the list was refreshing could be overwritten. The URL now owns the selected date. The page follows URL changes and writes back the date it settles on. The headline now uses the patterns that come with the digest. Before, the page paged through up to 5,000 patterns since that date, and the digest's own patterns could fall past that cap. Digest links now point at `/friction?date=`, the form the page reads, and are offered only now that the page exists. The session findings list scrolls inside a fixed height and marks a partial list with "+". Two tests that only repeated a literal URL and static copy are removed.
Reopening the page with a date in the URL could open the date kept from an earlier visit instead, because the URL sync ran before the page read the URL. The page now reads the URL first and syncs back only after the first load settles. While a newly picked date loaded, Markdown reads followed the new date but Download followed the digest still on screen, so the two could name different days. Markdown now follows the digest on screen. pg serve reports read_only for sessions but can still build digests, so Build now follows friction_available alone. Test cases for response shapes the generated types rule out are removed.
The header, mobile navigation, and Quality card checked friction_available, which says the server can build digests. A PostgreSQL hub without a review runner still serves stored digests, and the page was unreachable there. They now check friction_readable; Build now still needs a runner. Switching digests could leave the previous digest's Markdown on screen if it loaded while the next digest was on its way. Showing a new digest now drops that Markdown.
Navigation now shows the Friction Log when the server can read digests, so the mocked version response needs friction_readable for the navigation test to find the tab.
Friction review runs in the background after sync, so a session's panel could keep showing no findings after review found some. The open panel now rechecks every minute while the tab is visible, keeping the current list on screen until the new answer arrives, and stops when it closes.
vp check could not resolve a named export from the Svelte module once the formatter wrapped the combined import past the single-line ts-ignore.
The refresh test already mounts the panel with no findings and checks the empty-state message before new findings arrive. The standalone test repeated that check and added no coverage. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
b02b9f9 to
7292d12
Compare
roborev: Combined Review (
|
When the first load of a bookmarked older digest failed, no digest was selected yet, so Retry asked for the latest digest and replaced the date in the URL. Retry now falls back to the URL's date until a digest loads. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The page test renders a diagnostic finding and checks that it has no session link, which is the only behavior isDiagnosticSubject controls. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
roborev: Combined Review (
|
…led load The store keeps the last selected date across visits. When the first list load failed on a plain /friction visit, the page still treated the load as settled and wrote that old date into the URL, so Retry opened it instead of the latest digest. The page now settles only after a list load succeeds. Until then, Retry asks for what the page opened with: the URL's date, or the latest digest. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
roborev: Combined Review (
|
The web app reports a screen view for every route, including /friction, but the daemon's screen allowlist did not include it. Those events were dropped, so Friction Log use never appeared in usage counts. The configuration guide lists the new value with the other screens. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The page waited for its own list load to succeed before it kept the URL in step with the digest on screen. Build now reloads through the store, so after a failed first load a successful build showed the latest digest while the URL still named the old bookmark, and Refresh went back to it. The store now counts successful list loads from any caller. The page settles once that count rises after it mounts, whichever action loaded the list. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The server starts a friction build only for a direct localhost request or when it requires auth. Behind a managed proxy without auth, the page still showed Build now, and every click failed with a 403. /api/v1/version now reports friction_build_allowed, computed per request with the same check as the run route. The page shows Build now only when it is true. When it is false and no digests exist yet, the empty state says to open the page on the machine that runs AgentsView or to turn on require_auth. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
roborev: Combined Review (
|
Digest findings and P0 alerts identify sessions only by ID. Real IDs are long opaque strings, so a reader could not tell which conversation a finding came from without opening it. The digest response now carries a sessions map with each named session's agent, project, custom name, and the start of its first message. Sessions no longer in the archive are left out, and diagnostic identities are not sessions. The lookup goes through the store's GetSession, so SQLite and PostgreSQL hubs both answer it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The page printed the digest's raw data. Every row led with an agent tag and an opaque session ID. Pattern links showed the issue-filing title format, labels appeared in snake_case with literal backticks, and P0 was unexplained jargon. An empty day rendered seven "No ... detected" lines. Rows now lead with what happened: a quoted correction, a tool and its error, or a named pattern with its evidence. The second line names the session by title, project, agent, and message. A row of counts opens the digest. "Needs attention" replaces the P0 and headline cards, and its pattern rows use the finding's own text. Kinds with no findings are hidden, and a day with none shows one empty state. The disclaimer banner becomes a docs link in the digest's meta line. The session panel uses the same finding text in place of detector names. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
roborev: Combined Review (
|
Adds a Friction Log page at
/friction, so people can see where their agent sessions went wrong on a given day without reading the Markdown digest. The page shows one day's digest in the order a reader needs it:Kinds with no findings are hidden, and a day where nothing was flagged shows a single empty state. The session signal panel lists the open session's findings with the same wording, and Quality links to the page. Navigation follows
friction_readable, so a server that stores digests but cannot build them still shows the page.Screenshots use the e2e fixture archive with synthetic session titles.
To name sessions, the digest response gains a
sessionsmap: agent, project, custom name, and the start of the first message for every session the digest's findings and P0 alerts name. It goes through the store'sGetSession, so SQLite and PostgreSQL hubs both answer it. Sessions no longer in the archive fall back to their ID.Users can step between dates, copy or download the stored Markdown, and choose Build now when the server has a friction runner and accepts builds from this caller, which
/api/v1/versionreports asfriction_build_allowed. That holds onpg serve, which reportsread_onlyfor sessions, but not behind a proxy on a server without auth, where the run route answers 403; there the empty state says to open the page on the machine that runs AgentsView or turn onrequire_auth.The URL owns the selected date (
/friction?date=YYYY-MM-DD). The page follows history and shared links while it is open, and writes back the digest it settles on after the first successful list load, so a failed load cannot replace the requested date. Digest links from the API and MCP use the same form. The session findings list scrolls inside a fixed height, shows "500+" when it holds a partial list, and rechecks every minute while the tab is visible, because review runs in the background after sync.This page shows only what main stores, so it has no spend or persona panels. When review is off, the empty state tells users to set
[friction] enabled = true. The Markdown download reports a newfriction_markdownvalue for theexport_runtelemetry event, and page views reportfrictionforscreen_viewed; the allowed lists and the configuration docs are updated to match.About half the diff is component and store tests, and the message keys are in all eight locales. Row rendering lives in
components/friction/FrictionFinding.svelteandFrictionSessionRef.svelte; page state is infrontend/src/lib/stores/friction.svelte.ts. The release screenshot capture is left for the release screenshot pass, because the docs build fails when the assets branch lacks a listed image.Part 3 of 5. Rebuilt from #1937 by @salmonumbrella.
🤖 Generated with Claude Code