Commit Graph

8009 Commits

Author SHA1 Message Date
Katia Bulatova cbeee6716f feat(dashboard-agent): a batch chain registry, one per environment and cadence 2026-08-05 15:41:05 +00:00
Katia Bulatova 4dedd60b3f chore: drop the working notes and the stray diff from the repo root 2026-08-05 14:57:49 +00:00
Katia Bulatova ac1fdfd29b chore(dashboard-agent): say why the title gate is the transcript length
Follows the title write moving to onBeforeTurnComplete: the gate reads as a
magic number without the note that a later turn cannot re-title anyway,
because setChatTitleIfDefault only writes over the default name.
2026-08-05 14:52:30 +00:00
Katia Bulatova d3d33a6aef chore: oxfmt the generated drizzle snapshot and the presenter test import 2026-08-05 14:52:29 +00:00
Katia Bulatova 37e4c234c2 fix(webapp): the chat name is on the row before the turn settles
The panel reloaded its chat list twice per turn — once on settle, then
again on a 5s timer — purely because the generated name landed after the
first reload and the list would otherwise sit on "New chat".

The name is now written before the client settles instead. Generation
starts in onTurnStart, so it runs alongside the model answering, and is
awaited in onBeforeTurnComplete — the last hook before the turn-complete
chunk closes the stream. onTurnComplete cannot do this: it fires after
that chunk, which is exactly why the write used to miss.

Costs nothing in practice (the cheap title model finishes long before the
answer does) and a failure only loses the generated name. The delayed
reload and its timer are gone, and a test pins the ordering — it fails if
the await is dropped.
2026-08-05 14:52:28 +00:00
Katia Bulatova 4606b94e0f feat(webapp): the watch sweep retires watches that ended a week ago
A terminal watch is read by nothing once its wake has landed — the chip is
gone, dedup only looks at active rows, and the outcome's facts live in the
chat transcript from then on. So the row was pure accumulation.

The sweep now drops terminal rows whose last event was over 7 days ago, in
one guarded statement bounded to 500 per run. Guards: terminal status only,
delivery already settled (a row that still owes a wake is never taken), and
the age measured from the newest timestamp on the row so a late delivery
restarts the clock. Watches only — chats, messages and investigations are
untouched.
2026-08-05 14:52:28 +00:00
Katia Bulatova 0b66440e99 perf(webapp): a finished report is reusable for 90s
A report is ~9 ClickHouse queries, and the callers that dominate its
volume are periodic rather than interactive: every watch tick in an
environment asks for the same health verdict, so one sweep recomputed it
once per watch.

Caches the interpreted view model per (report, environment, period) for
90s — under the tick cadence, well over a burst. In-process and keyed by
environment id, so nothing crosses a tenant. The single-flight map stays:
it is what holds the first callers of a cold key to one load, and a
rejected load is still never cached.
2026-08-05 14:52:27 +00:00
Katia Bulatova 0045062261 perf(webapp): the wake poll sleeps in hidden tabs and no longer runs in lockstep
A background tab has no dot the user can see and nowhere to put a toast,
so it stops asking; becoming visible triggers one immediate catch-up and
restarts the cadence from there. Each delay carries fresh jitter, so many
open tabs stop hitting the same second.
2026-08-05 14:52:27 +00:00
Katia Bulatova 1bc6a019c7 perf(webapp): the wake feed reads a tenant-scoped partial index
The dot's count and the toast's list both run on every poll of a closed
panel, and both drove off a full scan of the watches table: the tenant
predicates sat on the joined chat, so nothing narrowed the watch side
first.

Adds a partial index on (organization_id, user_id, resolution time desc)
over delivered wakes only, and asserts the same org + user on the watch
row so the planner can use it. That pair is redundant, not a new tenancy
rule — a watch snapshots its chat's owner at creation and the create path
rejects a chat from another org.

On 200k watches: the count goes 20.5ms -> 0.5ms and the recent list
21ms -> 0.02ms, with the parallel seq scan replaced by an index scan that
also absorbs the recency bound.
2026-08-05 14:52:26 +00:00
Katia Bulatova 814b527aeb docs(dashboard-agent): one guidebook replaces the playbook and scenarios 2026-08-05 14:43:18 +00:00
Katia Bulatova 95fa1b64b5 chore(webapp): drop the agent-examples review seeder 2026-08-05 14:43:17 +00:00
Katia Bulatova 75aba7f24c feat(webapp): the scenario kit runs against any local project and environment 2026-08-05 14:43:17 +00:00
Katia Bulatova ef65f468a2 chore: one release note for the dashboard agent, one short changeset 2026-08-05 13:23:36 +00:00
Katia Bulatova e740c16184 fix(webapp): give the remix build the same heap headroom as typecheck
The webapp outgrew the default heap on CI runners — both E2E workflows died
in webapp:build with allocation failures.
2026-08-04 23:43:22 +00:00
Katia Bulatova 2b5a705ac4 fix(webapp): the tick re-authorization user read moves off the replica
Same boundary rule as the membership read above it: replica lag must not
extend access a background check should have revoked.
2026-08-04 21:42:33 +00:00
Katia Bulatova 331f80e7f9 fix(webapp): watches container tests follow the org-scoped chat queries and the recent-wakes toast feed
Also drops the tracked review-diff artifact from the repo root.
2026-08-04 21:38:11 +00:00
Katia Bulatova 7b16385a24 feat(webapp): a scenario kit for the Watch and Investigate flows
Every Watch condition was proven by hand-run Redis and ClickHouse surgery. Now
each one is a verb:

  pnpm --filter webapp run scenarios:watch -- queue:fill email-sends 400
  pnpm --filter webapp run scenarios:watch -- queue:drain email-sends
  pnpm --filter webapp run scenarios:watch -- error:recur
  pnpm --filter webapp run scenarios:watch -- run:fail 90
  pnpm --filter webapp run scenarios:watch -- health:degrade | health:recover

Each verb is idempotent, runs on top of the seeded agent-examples stand, refuses
a non-local Redis or ClickHouse, and prints the dashboard step that follows it.
Prerequisites fail with the command to run.

SCENARIOS.md walks every scenario end to end — the command, the clicks, the
wording that arrives and the tick cadence — including the two run tasks, whose
source lives in the references repo and is carried here as a snippet.
2026-08-04 21:34:28 +00:00
Katia Bulatova cca0d536ff chore(webapp): drop the seeder's --heartbeat stand mode
The heartbeat kept a review stand from ageing by appending a minute of fresh
telemetry every 30s. It was a crutch for demos, not something a developer needs,
and it carried a state file, a tag-and-prune cycle and a per-tick Redis top-up
with it. All of it goes; --degrade / --recover / --showcase and the base seed
stay.

The Redis key shapes and the depth staging move to seed-agent-examples-redis.mts
so the scenario kit can stage the same keys the same way.
2026-08-04 21:34:27 +00:00
Katia Bulatova 3ed1c1f38e fix(webapp): name the tenant on the dashboard agent routes' failure paths
The routes this branch adds logged their failures without saying whose request
they were, and several catch clauses answered every error the same way.

- every failure-path log now carries the tenant ids the route has in hand
  (userId / organizationId / projectId / environmentId)
- the body-parse try blocks guard only the parse; the shape check moved out
- the boundary catches rethrow a thrown Response instead of turning it into a 500
- routes that relied on the central handler get a log-and-rethrow boundary, so
  the response is unchanged and the failure is named
- the advisory watch email-alert state moved to the alerts service, where the
  rest of that logic lives
2026-08-04 21:34:10 +00:00
Katia Bulatova 2e01a49597 fix(webapp): primary popover trigger keeps white ink on the light theme 2026-08-04 21:00:58 +00:00
Katia Bulatova b9033f3474 fix(webapp): the wake-toast dedupe survives reloads
The toast source is recent deliveries, so an in-memory dedupe re-toasted
every wake younger than the window on every refresh.
2026-08-04 20:56:34 +00:00
Katia Bulatova 70559be991 fix(webapp): attribute env-authed API calls to the acting user (TRI-11095)
The env JWT exchange now stamps a signed `act` claim (acting user + client
kind), auth surfaces it as `actor`, and the tenant context prefers it over
`orgMember`, which only exists on dev environments. Identity only — the JWT
still authorizes as the environment.
2026-08-04 20:36:10 +00:00
Katia Bulatova 17758f72f6 chore(webapp): drop the section-id label from gallery tiles 2026-08-04 20:32:24 +00:00
Katia Bulatova 555b77e764 refactor(webapp): split the agent gallery into pages and prune its states
The card catalogs move out of Chat UI onto their own storybook pages (view blocks, report view, investigation card, watch card), all sharing the manifest and the page shell. Cuts near-duplicate states: 97 sections down to 52, section ids unchanged. The screenshot script now walks every page.
2026-08-04 20:28:32 +00:00
Katia Bulatova 6650b946d9 fix(webapp): switching organizations resets the open panel
Crossing orgs re-renders the layout without remounting, so the previous
org's open chat and history lingered in the panel.
2026-08-04 19:04:43 +00:00
Katia Bulatova d5d821d695 fix(webapp): chat access is organization-scoped everywhere
Chats belong to (organization, user); several queries enforced only the user,
so a user's own chat from another org could be opened, renamed, pinned or
appended to through a different org's route.
2026-08-04 19:00:25 +00:00
Katia Bulatova 93c4a02f4e feat(webapp): a consented watch investigation conducts itself
The wake seeded the card and said it had started looking, then nothing ran
it — the findings were left to a turn only the user could start. The watcher
now reports a delivered consented wake to the webapp, which mints the same
delegated user-actor token a turn gets and sends a `watch.investigate` action
into the chat; the agent conducts a real investigating turn on that card and
delivers the findings as its own message. Best-effort throughout: nothing here
can retry or invalidate the wake.
2026-08-04 18:44:06 +00:00
Katia Bulatova 4aa9abce62 fix(webapp): wake toasts fire on delivery, not unread state; agent toast surface matches Ask Trigger on dark themes
A wake read on screen before the next poll never toasted. The toast list is
now recent deliveries (15 min, id-deduped client-side); the dot still counts
unread only.
2026-08-04 18:42:12 +00:00
Katia Bulatova 0c39e7a190 fix(webapp): run inspector Watch button goes primary, matching Investigate 2026-08-04 18:34:23 +00:00
Katia Bulatova 6c8e5ef7b7 fix(webapp): watch card confirms with one Watch button, no Done collapse step 2026-08-04 18:19:51 +00:00
Katia Bulatova 12cdc67190 fix(webapp): closing the agent panel drops fullscreen — reopen is always the side panel 2026-08-04 18:11:29 +00:00
Katia Bulatova e19049b90f fix(webapp): Toaster inherits the app theme
Sonner stamps data-theme="light" (its default) on the toast list; since the
theme system remaps tokens by that attribute, every custom toast rendered
light regardless of the page's theme.
2026-08-04 18:06:07 +00:00
Katia Bulatova 6172c7f878 fix(webapp): storybook toast page double-mounted a second Toaster
The root already mounts one; a fired toast rendered in both and the two
copies stacked.
2026-08-04 17:59:15 +00:00
Katia Bulatova d5ec3d47c7 chore(webapp): drop the unused agent callout variant; fix a renamed gallery section id
The wake toast moved to the standard toast's agent status, leaving the
Callout variant with no consumer.
2026-08-04 17:51:38 +00:00
Katia Bulatova 0a05d3a898 chore(webapp): storybook button to fire the agent toast 2026-08-04 17:43:10 +00:00
Katia Bulatova f928fb00bb feat(webapp): agent status for the standard toast; wake toast uses it
Third ToastUI variant: success's layout with the agent glyph and the Ask
Trigger border. The wake toast drops its Callout composition for it.
2026-08-04 17:41:16 +00:00
Katia Bulatova 39e9ed3cb1 fix(webapp): the agent callout (wake toast) dresses like the Ask Trigger button
Agent logo instead of the indigo bubble, the button's own surface (charcoal
on dark, white on light) and softened green border.
2026-08-04 17:33:42 +00:00
Katia Bulatova 97a8e16ada feat(dashboard-agent): the watch offer becomes a button
New "actions" view block: a row of 1-3 buttons the model may emit. A watch
action opens the watch configuration card pre-filled; ask sends the labelled
question as the user's next message; a navigate target that doesn't parse is
dropped at render time, as on chart actions.
2026-08-04 17:30:40 +00:00
Katia Bulatova 2030c3356d fix(webapp): agent badges keep their tone colour on system themes
The Badge primitive's small variant paints a blue tinted chip on system
themes, which overrode the severity/confidence tones — Degraded and Medium
confidence rendered blue instead of amber.
2026-08-04 17:23:27 +00:00
Katia Bulatova f22310a30e fix(dashboard-agent): the watch offer is mandatory when the answer's headline is an unresolved recurring error 2026-08-04 17:02:12 +00:00
Katia Bulatova f20eef3ed9 feat(dashboard-agent): the agent offers a watch when its answer points at something worth monitoring 2026-08-04 14:14:50 +00:00
Katia Bulatova c858b2589d fix(webapp): trigger:// links in prose resolve to dashboard paths
Markdown renderers won't link an unknown scheme, so a cited trigger:// target
rendered dead. Prose links now rewrite through the panel's resolver; while
unresolved they degrade to their plain label.
2026-08-04 13:44:14 +00:00
Katia Bulatova 7a700453a3 feat(dashboard-agent): validate chart queries when render_view runs
A chart block's TRQL query used to run only in the panel, after the turn, so a
bad query left a broken chart the model never learned about. render_view now
runs each chart query through the query API first and fails by name with the
query error, so the model fixes it in the same turn. The rows are discarded —
the panel stays the runner. Skipped when the turn has no delegated token or the
validation request itself fails.
2026-08-04 13:32:54 +00:00
Katia Bulatova 52cb895f3d chore(webapp): drop unused import flagged by lint 2026-08-04 13:24:50 +00:00
Katia Bulatova 14170648f0 fix(webapp): settle investigation cards left in progress between turns
A card opened by a turn that died, or opened for a later turn that never
came (a wake's narration does this), sat in_progress forever — a spinner on
the card and an Investigating marker in History. A new sweep on the existing
dashboard-agent cron settles anything untouched for 30 minutes to
inconclusive, with the same wording the turn-level settle uses, guarded on
the row still being in_progress so a live turn always wins.
2026-08-04 13:23:56 +00:00
Katia Bulatova 767b754b16 fix(dashboard-agent): the runs time column is triggered_at — correct the prompt's example 2026-08-04 13:23:33 +00:00
Katia Bulatova 4e392c336b fix(dashboard-agent): prompt pins TRQL columns to snake_case for chart queries
A chart block's query runs after the turn, so the model never sees its
error — a camelCase column produced a permanently broken chart.
2026-08-04 13:14:40 +00:00
Katia Bulatova a65c460d1a fix(webapp): Watch tooltip in the Investigate form — 'Get notified when…' 2026-08-04 13:11:00 +00:00
Katia Bulatova a9fe736673 fix(webapp): Watch button tooltip defaults to the recommendation's note 2026-08-04 13:06:43 +00:00
Katia Bulatova e69e13eee1 fix(webapp): queue page button order Period-Investigate-Watch-Override-Pause, secondary Investigate there 2026-08-04 13:03:44 +00:00