Commit Graph

8187 Commits

Author SHA1 Message Date
Katia Bulatova 2e23a098de fix(webapp): keep the other Anthropic options when the step breakpoint rolls off 2026-08-06 13:04:08 +00:00
Katia Bulatova 49a1504310 docs: cut the release note back to what a user notices 2026-08-06 13:01:12 +00:00
Katia Bulatova 44b4e57003 docs: say the investigation card closes while the panel is open 2026-08-06 12:46:39 +00:00
Katia Bulatova 37c56aaa15 test(webapp): pin the settlement failure window and the open panel
Covers the two halves the earlier pass left open. Against a real database, a
stale card that cannot be rendered now proves the sweep rolls the settle back
with it: the row stays `in_progress` at revision 0, the chat stays empty, and
the row is still in the next run's selection.

The panel half is covered over `liveProgress`, the code that decides whether
"Working…" is shown: a mounted panel holding the unconcluded card re-reads the
stored transcript, merges by stable id, and the progress line goes away without
a reload. Re-reading repeatedly cannot add a second copy of the card.
2026-08-06 12:42:27 +00:00
Katia Bulatova 5bf3612ecf fix(webapp): settle an investigation and its closing card in one write
The row settle, the transcript and the session state were three separate
operations. Once the row was terminal, a failed transcript write left a card
that read `in_progress` forever: the stale sweep only selects `in_progress`
rows, so nothing was left to repair it.

Both lanes now commit the pair atomically. The live turn hands its pending
settlements to `persistTurn`, which upserts the revisions, appends their cards
and writes the session in one transaction; the process-local entry survives
until that commits, so a retried `onTurnComplete` still settles. The sweep goes
through `settleInvestigationAndCloseCard`, whose rollback restores the
`in_progress` row the sweep already selects.

That also removes the last reader of the per-run `chatOwners` map, which had no
`delete` and grew for the life of the worker: the failure record now travels in
the transcript write, which needs no userId.

Separately, the consented watch investigation gets the rolling step cache. Its
ten-step `streamText` re-sent every accumulated tool output uncached; the
breakpoint helper and the per-step cache telemetry now live in `step-cache.ts`
and both lanes use them, wrapping any `prepareStep` the resolved options carry.
2026-08-06 12:42:27 +00:00
Katia Bulatova 29de34f912 style(webapp): drop the imports the merge left unused 2026-08-06 12:19:30 +00:00
Katia Bulatova 657f11daf0 docs(webapp): say which UAT flow the project-wide answer is preserved for 2026-08-06 12:18:36 +00:00
Katia Bulatova 1759618b7f fix(webapp): keep the project-wide answer for an environment-agnostic user-actor token
Binding a delegated token to its environment claim on the project-wide
routes also refused any token that carries no claim at all, which the
public PAT exchange used by MCP and the CLI is allowed to issue. Line the
project-wide helper up with its neighbours: a claimless dashboard-agent
token is still refused, everything else stays project-wide.
2026-08-06 12:18:35 +00:00
Katia Bulatova e62d8c66f3 style(webapp): format the route image CSP audit 2026-08-06 12:18:15 +00:00
Katia Bulatova 60a958414b test(webapp): fail if a route sets an over-broad image CSP 2026-08-06 12:18:14 +00:00
Katia Bulatova 07b83da609 docs: note the agent's closed investigations, watch email honesty and image sources 2026-08-06 11:39:00 +00:00
Katia Bulatova 26f93da1a9 fix(webapp): have the stale-investigation sweep close the card it settles
The sweep settled the row and appended nothing, so it visibly fixed nothing: the
chat kept rendering the last card it had, which was still "Working…". The settle
now returns the state and revision it wrote, and the sweep appends that as the
closing card revision on the chat — id-deduped on
`investigation-settlement:{id}:{revision}`, so a retried run can neither stack a
second card nor open a second investigation.

The append is scoped by chat id: a sweep runs off any session and has no user in
context, unlike the turn lane.
2026-08-06 11:34:59 +00:00
Katia Bulatova f7b8374792 fix(webapp): put a turn's settled investigation card in the transcript
Settling the investigations row was invisible to the user. The panel builds the
winning revision from the transcript's own `tool-render_view` parts and never
reads that table, so a turn that ran out of steps left the card at
`in_progress` forever: the database believed the investigation had finished
while a refresh still showed "Working...".

`settleOpenInvestigations` now returns the revisions it committed, and
`onTurnComplete` appends each as one more card revision — after the transcript
write and id-deduped on `investigation-settlement:{id}:{revision}`, so a failed
append leaves the card visibly unclosed rather than silently lost, and a retry
can't stack a second card.

The card-building and the latest-revision reader move out of the watch lane and
into the runtime both lanes share, so there is one shape, not two. The watch
lane keeps its own message id: it dedupes on the action, not the revision.
2026-08-06 11:34:58 +00:00
Katia Bulatova 7b2f9c6933 chore(dashboard-agent-db): drop the submission's external-notification patch
A recorded outcome is immutable now, so nothing calls it.
2026-08-06 11:31:33 +00:00
Katia Bulatova 49e8fb578c fix(webapp): tell a watch's creator about their own email alerts, not a colleague's
The create-watch response matched any watch-alert channel in the project, so a
second member was told they were subscribed while the mail went to the first.
The channel's deduplication key is the only record of whose it is, so state
resolution, subscribe and unsubscribe now share one owner lookup.
2026-08-06 11:27:43 +00:00
Katia Bulatova c4d3f585e3 fix(webapp): replay a watch submission's recorded email outcome instead of re-deciding it
replay() re-ran subscribe() for an already-recorded `created` submission. A retry that
succeeded could flip the ledger to `enabled`, but the confirmation in the transcript is
append-once, so the user kept being told email was unavailable while the system believed
it was on. The replay now reads recordedExternalNotification() and takes no external
decision. An attempt that dies before subscribing or before its outcome is recorded
leaves the row `pending`, and the normal creation path subscribes on the retry.
2026-08-06 11:27:42 +00:00
Katia Bulatova d646809b0c chore(rbac): keep the delegated-token invariant, drop the essay 2026-08-06 10:49:06 +00:00
Katia Bulatova 79482dea37 chore(webapp): drop the comments the tests already say 2026-08-06 10:49:05 +00:00
Katia Bulatova 7a645e5149 chore(webapp): drop the comments the code already says 2026-08-06 10:49:04 +00:00
Katia Bulatova 3336a47d1e test(webapp): give the container-backed user-actor scope tests their own timeout 2026-08-06 10:32:58 +00:00
Katia Bulatova f700174b44 fix(webapp): ceiling an exchanged environment JWT by what the delegated token can do
A user-actor token declaring no scope cap could mint an environment JWT with any
scopes it asked for. The exchange now clamps the minted scopes to the actor's own
ability, so a capless token is read-only, and only mints for its claimed environment.
2026-08-06 10:32:56 +00:00
Katia Bulatova a7fc406781 fix(webapp): keep a delegated token's claims on the authenticated identity
The direct PAT authentication path returned identity only, so a user-actor token
reaching it (admin routes and other direct callers) lost its environment scope. The
claims now ride on the authentication result itself.
2026-08-06 10:32:55 +00:00
Katia Bulatova d00b1266e4 fix(webapp): bind a delegated token's environment claim on the project-wide routes
The environments and runs listings are project-wide, so an environment-scoped
user-actor token could read every environment its user can reach. Both routes now
resolve the claim into a mandatory filter, and a conflicting request filter is
refused rather than overridden.
2026-08-06 10:32:54 +00:00
Katia Bulatova 4e00b7952f style(webapp): format the sweep's authorization helper 2026-08-06 10:29:14 +00:00
Katia Bulatova 478b30cc2c chore(dashboard-agent): drop the test comments the assertions already say 2026-08-06 10:28:07 +00:00
Katia Bulatova 240799d0aa chore(dashboard-agent): drop the comments the code already says 2026-08-06 10:28:06 +00:00
Katia Bulatova 210863ea76 fix(webapp): separate a watch's last look from its last check in the batch order
A tick that could read nothing now moves the group's fairness key only, so a watch
with a permanently broken reader stops crowding out the rest of an over-cap group.
Dueness and the streak facts still follow the last real check.
2026-08-06 10:28:05 +00:00
Katia Bulatova 22bf6d919a fix(webapp): cancel the watch a losing submit's winner does not name
A refusal that won the race kept the reserved watch id, so the user was told
nothing was created while that watch stayed active.
2026-08-06 10:28:04 +00:00
Katia Bulatova 09d1b55e22 fix(webapp): require the watch card's request id instead of falling back to its condition
A per-condition fallback identified the condition rather than the submit, so a
re-watch could replay a stale terminal outcome from the retention window.
2026-08-06 10:28:03 +00:00
Katia Bulatova 9daa8f92eb docs(dashboard-agent): tell the judge the error category is derived, the message withheld
Also reuse the policy's errored-output check instead of a second copy of it.
2026-08-06 10:28:02 +00:00
Katia Bulatova fb99526809 feat(dashboard-agent): tell the eval judge a failure's kind without its message
Classify a failed tool result locally into one of seven categories and send only
the label; the message is dropped with every other free-text field. Unrecognised
failures are unknown rather than guessed, and a bare string error field is now
withheld too.
2026-08-06 10:28:01 +00:00
Katia Bulatova 5adba81b9b docs: document CSP_IMG_SRC_ALLOWLIST for self-hosted image hosts 2026-08-06 10:28:00 +00:00
Katia Bulatova cd112ba2a3 test(webapp): assert the document img-src has no wildcard host 2026-08-06 10:27:59 +00:00
Katia Bulatova 48d0d4a707 fix(webapp): drop the img-src wildcard host for a validated origin allowlist
Replaces https://*.googleusercontent.com (a host with public write access)
with CSP_IMG_SRC_ALLOWLIST: exact origins only, https outside development,
deduplicated, bad entries warned about instead of failing the boot.
2026-08-06 10:27:58 +00:00
Katia Bulatova d73f3f5c61 chore: ignore the agent worktrees directory 2026-08-06 10:27:43 +00:00
Katia Bulatova 05b3472801 Merge branch 'main' into feat/dashboard-agent-flows
Route conflicts were the tab-title work meeting the agent page-context handle: both
sides kept, duplicate meta exports resolved to pageMeta, duplicate imports merged
with unused bindings dropped. Lockfile regenerated from the merged manifests.
2026-08-06 10:27:43 +00:00
Katia Bulatova 933aeb9ea4 test(webapp): stub the agent proxy's environment lookup, not a Prisma row
The hand-built row stopped satisfying every column the authenticated-environment
mapper reads, so both proxy cases failed. Stubbing the lookup keeps the fixture
independent of the row's columns.
2026-08-06 09:44:50 +00:00
Katia Bulatova 82f4a73b9d style(webapp): drop a needless escape in the image regex 2026-08-06 09:42:47 +00:00
Katia Bulatova d9ff853f09 style(webapp): format the agent eval and step-cache tests 2026-08-06 09:42:46 +00:00
Katia Bulatova 32553b903d style(webapp): format the agent markdown test 2026-08-06 09:42:46 +00:00
Katia Bulatova 488621e033 perf(webapp): cache the agent's accumulated tool results between steps
A step-level 5-minute cache breakpoint rolls onto the growing history once it is large enough for the write to pay for itself, and each step logs the provider's cache write and read counts.
2026-08-06 09:42:45 +00:00
Katia Bulatova 1aee9cac35 fix(webapp): send the eval judge only the turn's structural facts
The judged turn now passes an allow-list of structural fields instead of a deny-list of known-sensitive names, unfolds the tool-output envelope so error text is redacted too, truncates inputs as well as outputs, and caps the whole turn.
2026-08-06 09:42:45 +00:00
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