Commit Graph

8133 Commits

Author SHA1 Message Date
Katia Bulatova 94ec67fd53 perf(webapp): keep the agent transcript's investigation winners stable
The winners map was rebuilt on every streamed token and handed to the memoized turns as a fresh reference, re-rendering the transcript. The reference is now reused while the winners hold.
2026-08-06 09:42:44 +00:00
Katia Bulatova dd90b6e968 fix(webapp): never render an image the agent's model authored
A remote image in model output fetches on render, so its URL is an exfiltration channel. No image is rendered at all, and the document CSP now names the hosts images may come from.
2026-08-06 09:42:43 +00:00
Katia Bulatova a0640ba248 style(webapp): format the watch tenancy changes 2026-08-06 09:40:30 +00:00
Katia Bulatova a63708c6e6 test(webapp): assert the derived chat id before the submit outcome 2026-08-06 09:40:29 +00:00
Katia Bulatova 5176e3e8c4 test(webapp): pin the watch ledger's tenancy, the once-only alert and the owner-scoped unsubscribe 2026-08-06 09:40:29 +00:00
Katia Bulatova 5f2f5fe241 fix(webapp): scope the watch submission ledger and its alerts to one tenant
The chat id a fresh submit derives, the transcript appends, the create's chat read
and the ledger replay are all owner-scoped now, the fire callback alerts once per
terminal outcome, and a failed email subscription is stated instead of dropped.
2026-08-06 09:40:28 +00:00
Katia Bulatova 012ce0de53 test(webapp): drop an unsafe optional chain from the sweep boundary test 2026-08-06 09:39:17 +00:00
Katia Bulatova 4846cf8ea0 fix(dashboard-agent): finish a wake in the transcript, or don't count it
A settled investigation now lands as one more revision of the same card, so the
in-progress card and its working line end. An empty narration writes nothing and
says so, and only an acknowledged append marks a wake delivered.
2026-08-06 09:39:17 +00:00
Katia Bulatova bd2559a7a8 fix(webapp): record only a real evaluation from a batch tick
An unreadable check is not an observation, so writing it moved the watch down the
rotation for a whole cadence and overwrote the facts a streak lives in.
2026-08-06 09:39:16 +00:00
Katia Bulatova e4852090aa perf(webapp): resolve the sweep's authorization and readers once per group
An incident expires a whole group at once, which is the worst time to repeat the
same authorization read per row. Bounded concurrency caps one tenant's share.
2026-08-06 09:39:15 +00:00
Katia Bulatova d2511bd264 fix(webapp): hand the sweep's final check the previous facts
A stateful condition is a transition across checks, so a boundary evaluation
without the last observation can never see a stall and records a reset.
2026-08-06 09:39:15 +00:00
Katia Bulatova d12e6a85ca style(webapp): merge duplicate imports on the user-actor auth path 2026-08-06 09:24:09 +00:00
Katia Bulatova f58a9dcc89 fix(webapp): only let the browser set the agent's page context
The chat turn's metadata is now a whitelist: the page the user is on is all the browser can set, and every identity, tenancy and token field is filled in by the server.
2026-08-06 09:24:09 +00:00
Katia Bulatova d51cb9a736 fix(webapp): stop the OSS fallback handing a delegated token blanket access
Without an RBAC plugin, a user-actor token got the same permissive ability a personal access token gets. It now gets only what its own scope cap allows, and reads only when it declares no cap. Personal access tokens are unchanged.
2026-08-06 09:24:08 +00:00
Katia Bulatova 9d45284112 fix(webapp): keep the agent token's environment claim on the actor through every route builder
The claim rode beside the authentication result, so a route builder that only forwarded the user id lost it. It now travels on the authenticated actor itself, and a route's resolved org/project/environment is checked against it — a mismatch fails closed.
2026-08-06 09:24:07 +00:00
Katia Bulatova 880bf60f48 test(tsql): pin that no mutating query can pass the query boundary
The agent's run_query path compiles TRQL, which has no write statements, so a
mutation cannot parse. Cover the deny-list evasions a keyword filter would miss
(casing, comments, a statement smuggled after a semicolon) and keep positive
controls so the negatives can't pass by rejecting everything.
2026-08-06 09:10:22 +00:00
Katia Bulatova f5a146b30c fix(webapp): cap the agent's body on any method and on a mixed-case path 2026-08-06 08:50:11 +00:00
Katia Bulatova 85b98ab8dc fix(webapp): mint the agent's token for the caller's own environment, or not at all 2026-08-06 08:20:52 +00:00
Katia Bulatova 62b598da27 docs(webapp): say which layer refuses an oversized agent body
The route-level check only sees a declared content-length; a body without one is
already ended mid-stream by the ingress cap.
2026-08-06 07:14:41 +00:00
Katia Bulatova 1cdf1f087d refactor(webapp): split the dashboard agent's maintenance cron along the watch seam
dashboardAgent.sweepWatches ran the watch sweep, the investigation sweep, the
batch re-arm and eval retention together. Watch is about to ship as its own
stacked PR, so the job is split where the cut will be: dashboardAgent.maintenance
keeps the investigation sweep and eval retention, dashboardAgent.watchMaintenance
takes watch expiry, delivery and the batch re-arm. Same cadence, and each backstop
keeps its own try/catch.
2026-08-06 07:14:41 +00:00
Katia Bulatova 50fd10bf1b fix(webapp): replay a watch submission's recorded outcome instead of re-running it
A retried card submit was only repairable while the first attempt's watch was
still active. Once it had fired, expired, or answered in one shot, the retry
re-evaluated the condition and created a second operation.

A watch_submissions ledger, keyed (chat_id, client_request_id), is now written
before the condition is read and carries the outcome once there is one. A retry
looks it up first: a recorded outcome is replayed, a different draft under the
same id conflicts, and only a pending row proceeds - converging on the watch id
reserved up front rather than creating another.
2026-08-06 07:14:40 +00:00
Katia Bulatova 4ff8859e1d fix(webapp): keep the agent's alert delete to channels the watch type is on 2026-08-06 01:54:46 +00:00
Katia Bulatova cbc2edc879 test(webapp): pin the watch submit's ordering, its retry repair and its refusal record 2026-08-06 01:54:45 +00:00
Katia Bulatova 49a953871a fix(webapp): record a watch request before the watch starts, and repair a retried submit 2026-08-06 01:54:44 +00:00
Katia Bulatova 28b1f3896c fix(webapp): cap the agent's request body while it streams, not after
The message-size checks ran after the body had been read, so a request without a
content-length was buffered and parsed in full before being refused. An ingress
cap on the agent's paths now counts the bytes as they arrive, and the chat proxy
reads its body with a ceiling instead of reading it whole first.
2026-08-06 01:53:17 +00:00
Katia Bulatova d719c9b2d3 fix(webapp): start the wake poll for a browser that has only an active watch
The page load reported unread wakes only, so a fresh browser whose watch was
created elsewhere and hasn't fired yet never started polling: the wake landed
without a toast or a dot until a reload. The loader now returns the active-watch
presence too, in one read per page load.
2026-08-06 01:53:16 +00:00
Katia Bulatova e599f1299c fix(dashboard-agent): rotate an over-cap watch group instead of starving it
The batch took the 500 soonest-expiring watches of a group every tick, so a group
larger than the cap could leave the rest unchecked until the first 500 expired.
The group is now ordered least-recently-checked first, with a generated
cadence_minutes column and an index so the due predicate no longer re-parses the
spec JSON per tick.
2026-08-06 01:53:15 +00:00
Katia Bulatova a3be7bda6b fix(dashboard-agent): cap the output of the summariser and the wake narration 2026-08-06 01:41:05 +00:00
Katia Bulatova 4e39228be1 fix(dashboard-agent): pin only a live investigation into a compacted context 2026-08-06 01:41:04 +00:00
Katia Bulatova ddc6d25a66 fix(dashboard-agent): describe a value at the redaction depth cap instead of passing it to the judge 2026-08-06 01:41:04 +00:00
Katia Bulatova 6c993f213b chore: note the summarised long conversations in the release note 2026-08-06 00:49:02 +00:00
Katia Bulatova 0c41a70fa4 perf(dashboard-agent): cap search_docs to a few short excerpts 2026-08-06 00:49:01 +00:00
Katia Bulatova 42a76fb93d perf(dashboard-agent): say a settled watch outcome without a model, and narrate the rest with Haiku 2026-08-06 00:49:01 +00:00
Katia Bulatova 1d083f3ea9 test(dashboard-agent): budget the real prompt prefix with ceilings and a committed snapshot 2026-08-06 00:49:00 +00:00
Katia Bulatova 99850acc2d feat(dashboard-agent): summarise an oversized conversation, keeping live investigations and watches 2026-08-06 00:48:59 +00:00
Katia Bulatova f96361452a chore(webapp): restore the dashboard agent's flag gate 2026-08-06 00:38:40 +00:00
Katia Bulatova fc32fc61e2 refactor(webapp): split the suggested-prompt registry by responsibility
The chip factory and slot vocabulary, the evergreen docs chips, the per-page slot
table and the signal chips each get their own module; registry.ts is now the
public face that re-exports them. A pure move.
2026-08-06 00:13:25 +00:00
Katia Bulatova 4876e074ed refactor(webapp): give each watch condition family its own module
dashboardAgentWatchChecks.ts keeps the dispatcher, the failure envelope and the
previous-facts reader, and re-exports the run, queue, error and health families
plus the shared reader contract. A pure move; every import path is unchanged.
2026-08-06 00:13:25 +00:00
Katia Bulatova fea1a29220 refactor(dashboard-agent): split the watch tick into delivery, condition, batch and adapters
watch-tick.ts keeps the two task definitions and the per-watch check; the wake
delivery, the condition lifecycle, the group tick and the db/session/callback
adapters each move to their own module. A pure move: watch-tick.ts re-exports
everything it exported before.
2026-08-06 00:13:24 +00:00
Katia Bulatova 31698fa0db refactor(dashboard-agent): split the tool set into one module per responsibility
tools.ts now only assembles ready adapters, in the same frozen key order: the
HTTP/JWT client, result curation, the docs client, the source-read ledger,
evidence canonicalisation, investigation persistence, and the api/navigation/
watch/alert tool groups each own their own module. A pure move.

The prompt-prefix fingerprints are unchanged, which is what keeps the head-start
and agent prefixes byte-identical.
2026-08-06 00:13:23 +00:00
Katia Bulatova 29d9a8e423 chore: note the conversation scoring in the release note 2026-08-06 00:11:26 +00:00
Katia Bulatova 99b89338c3 docs(dashboard-agent): make the eval docs match the code
The docs claimed every turn is judged; the sampled rate, the redaction rule, the code-mode
skip, the opt-out and the retention period are now written down in one place.
2026-08-06 00:11:26 +00:00
Katia Bulatova 263b32467d feat(dashboard-agent): give the golden runs their own eval sample rate
The CI lane reads its own variable and defaults to every turn, so neither lane can change
the other's rate.
2026-08-06 00:11:25 +00:00
Katia Bulatova a4b4ef1b55 feat(webapp): let an organization turn off judging of its agent turns
A per-org feature flag the agent checks before every judged turn, and a turn is judged only
on an explicit yes.
2026-08-06 00:11:23 +00:00
Katia Bulatova 3c5b2d5d6b feat(dashboard-agent): never judge a turn that read source 2026-08-06 00:11:22 +00:00
Katia Bulatova 42ddcffef0 feat(dashboard-agent): keep customer data out of the judged-turn row and the judge
Payloads, outputs, query rows and file contents are replaced by their shape before a turn
reaches the judge, and the row now keeps the derived verdict only.
2026-08-06 00:11:22 +00:00
Katia Bulatova 7f13add1a0 feat(webapp): retire judged-turn rows after 30 days
The table is append-only quality data with no reader, so the sweep now drops rows past
the period in one bounded statement per run.
2026-08-06 00:11:21 +00:00
Katia Bulatova 08dc7ba732 fix(webapp): keep the watch card in step with its draft, and frozen while it submits 2026-08-05 23:48:03 +00:00
Katia Bulatova c3ee6a4dbe perf(webapp): resolve the agent card's links in one request 2026-08-05 23:48:02 +00:00
Katia Bulatova ebad471b43 fix(webapp): cap the size of a message to the agent 2026-08-05 23:48:01 +00:00