Repository navigation
Sentryward 0.3.0
Sentryward remains pre-1.0, and this release changes some default behaviour:
review context now follows callers two hops from the changed code, and
changing your password signs out your other sessions. AI findings still need
human verification.
Upgrade notes
- Back up the database and
ENCRYPTION_KEYbefore upgrading. The server
applies this release's migrations on start. review.impact_depthdefaults to 2, so reviews search for callers of
callers (within a cap of 8 code searches per review). Set
review.impact_depth: 1to keep the previous context.REVIEW_RETENTION_DAYSis optional and unset keeps everything, as before.
Once a retention period is set (here or under Instance settings), the worker
deletes and clears older review data hourly, including the findings of
changes with no activity in that period.GET /api/usageno longer returnsrecent; API clients that read it should
useGET /api/usage/recent.
Added
-
list_dirtool for agentic review passes (#144). With
review.context: agentic, a pass can now list a directory at the change's
head revision on GitHub and GitLab, e.g. to find a changed file's tests or
siblings. Paths followread_file's rules (relative, no..), directories
end in/and symlinks in@, a listing shows at most 50 entries, and its
output is marked as untrusted and counted against the pass's tool budget.
A directory larger than the forge returns in one request (100 entries on
GitLab, 1000 on GitHub) is reported as incomplete rather than given a wrong
count. Listings are cached by head sha like file reads. -
Phone layout for the Reviews and Findings lists (#165). Below 640px wide
(phones, or high browser zoom) each review and finding is a stacked card
instead of a table row, so the lists reflow at 320px without scrolling
sideways. Cards keep every column's value, the row menu and click-anywhere
to open; a review's earlier runs expand inside its card, and a finding's
change title is written out rather than left in a tooltip. Findings get a
"Sort by" picker and a direction toggle in place of the sortable headers.
Long active-filter chips truncate instead of widening the page, and the
pagination's "Rows per page" label reads "Rows" on phones so its controls
wrap. -
Command palette and a global "Review a PR" action (#161).
Ctrl+K(Cmd+K
on macOS, where plainCtrl+Kstays the text fields' "delete to end of
line") opens and closes a palette from any dashboard page, also from the top
bar's Search button: it jumps to any page (admin pages only for admins, plus
Settings), lists repositories and opens a repository's reviews, starts a
manual review, and queues a review for a pasted pull or merge request link.
It does not open over another dialog, sheet or menu, says when repositories
are still loading or could not be loaded, and closing it while a link is
being queued leaves you on the page with a "Review queued" toast to open it.
A "Review a PR" button in the top bar opens the manual review sheet from
every page; Home and Reviews open that same sheet. -
Keyboard navigation and severity jump for findings on the review page
(#157).Ctrl+J/Ctrl+Umove between findings in display order,Ctrl+O
orEnterexpands or collapses the focused one,Ctrl+Ccopies its agent
prompt (or the selected text, when there is a selection), andCtrl+?opens
a dialog listing the shortcuts. Shortcuts are ignored while typing in a
field and inside menus and dialogs, andCmdis left to the browser. A sticky
"Jump to" bar under the header shows per-severity counts of the visible
findings and focuses the first finding of a severity; it also opens the
shortcuts dialog. Focus from the keyboard, a jump, Tab or a click shares one
position, and the focus ring stays visible after a mouse-started jump.
Ctrl+OandCtrl+Conly act while a finding has focus, a shortcut with
nothing to act on is left to the browser (so its ownCtrl+JandCtrl+O
still work, whileCtrl+Unever opens view source on the review page),
Ctrl+?follows the active keyboard layout, and a jump clears the bar even
when it wraps on narrow screens. -
Key metrics on Home (#154). Once the workspace has a review, Home shows
four tiles above the setup checklist: open critical/major findings, reviews
and failed runs in the last 7 days, and estimated spend over the last 30
days. Each links to the matching list (open findings sorted worst first,
runs, failed runs, Usage on the 30-day window), loads with its own skeleton,
and shows "-" if its stats fail to load.Stattakes alinkLabelso a
linked tile can name the page it opens. -
Progress for running reviews (#156). The worker records the current stage
on the job (newprogresscolumn onreview_jobs): fetching the change,
preparing, reviewing (withn of mpasses, and planning, context and
walkthrough as details), checking findings and publishing, listing only the
steps the run's config turns on.GET /api/reviews/:idreturns it, and the
review page shows a step list with elapsed time instead of a single spinner
line (queued reviews show how long they have waited, and a job requeued
after its worker stopped says it is waiting to retry). Until the run's
config is known only the current step is listed, so the list only grows.
Writes are best effort, coalesced, and only made by the attempt that holds
the job; a new claim clears them, and every run waits for its last write
before returning. -
Privacy controls (#109). A new "Privacy and data" section of the README
lists what Sentryward stores, what is sent to model providers and forges,
and how long it is kept. Instance admins get an Instance settings page
(GET/PUT /api/admin/settings, newinstance_settingstable) and
workspace admins a Privacy page (GET/PUT /api/privacy, new
workspace_privacytable) to restrict model requests to chosen providers
and hosts (exact names,*.example.comwildcards, optional ports) or to
local endpoints only (hosts that resolve to private or loopback addresses).
A workspace can only narrow the instance policy. The policy is checked
before a review posts anything, for every model it may call, including
ones named in.sentryward.yaml: a refused review, walkthrough or verify
model fails the review with aBlocked by privacy policy:reason, a
refused fallback is skipped with a warning, thread answers post a short
notice instead, and LLM connection save, test and model-list requests to
a refused host are rejected before they are sent (the connection shows as
"Blocked by policy"). Retention is now configurable from the dashboard
(instance period, falling back toREVIEW_RETENTION_DAYS, which workspaces
can shorten) and also purges the findings, posted-comment records and
finished thread replies of changes with no activity for longer than the
period. Every outbound model request (reviews, walkthroughs, verification,
capability probes, thread answers and connection tests) is recorded in a
newllm_request_logsaudit table with its workspace, repository,
purpose, provider, host, model, token counts, latency and outcome, never
prompts, code or error text. Admins can browse, filter and export it as
CSV or JSON on the Privacy page (/api/privacy/audit-log) and, for every
workspace, in the Audit log tab of Instance settings
(/api/admin/audit-log), and an instance audit retention period removes
old entries. -
Cross-file impact analysis (#108). Review context now follows callers of
changed code more than one hop (review.impact_depth, 1-3, default 2, 1 in
thefastprofile; also in the dashboard under Findings > Review context):
each caller's enclosing function becomes the next name searched, within a
shared cap of 8 code searches per review (generic method names such as
runorhandleare not traced), and further hops are the first context
dropped when a pass is out of room. Callers of declarations the diff
changes or removes, including parameters on later lines of a multi-line
signature, are searched first and labelledsignature changed/
removed, and the review prompt asks for broken contracts to be reported
withevidence: contract, the affected callers inimpactand their files
inevidenceFiles, which the summary and inline comments show as
Affected for contract findings. The walkthrough lists risky areas
(authorization checks, database writes and schema changes, API routes, and
route handlers or auth modules reached through callers; test files never
count) in the summary comment and the dashboard's walkthrough card, both
hidden byoutput.walkthrough_blast_radius, and they raise its blast
radius: at leastmediumfor any risky area,largeonly for a removed
auth check. Reviews stored beforereview.impact_depthexisted still allow
an incremental review on the next push. -
Model and review-cost benchmarking (#107). Workspace admins can set their
own model prices under LLM Connections > Model prices (GET/PUT /api/settings/model-prices,DELETE /api/settings/model-prices/:id,
newmodel_pricestable); a review's calls are priced at them when it
runs, ahead of the built-in table. A model nothing prices now records no
cost and is flaggedunpriced, so its cost reads as unknown instead of $0
on the Usage page (totals, table and recent reviews), the Reviews stats
strip and the review sidebar; the digest'susageTotals, review stats
tokens and recent usage rows carryunpricedCallsfor it. Ollama models
stay free unless priced. A workspace price keyed by any prefix-stripped
form of a router id (cx/gpt-5.6-solforopenai/cx/gpt-5.6-sol) applies,
and the price list's models carry thepricereviews get now, so the
"no price" warning clears for them. A saved price's model id can't be
changed when editing. The
review digest now keeps per-model call time and unpriced call counts, and
the number of findings dropped as duplicates. A Benchmarks page (GET /api/benchmarks) compares, over a period and optionally one repository,
cost per review, tokens and mean call time per model, cost, median duration
and duplicate rate per repository, and confirmed and false-positive
findings per model by language and by category, naming the best model
among those with enough decided findings. Rates are over decided findings
(confirmed plus false positives), as in the calibration stats, and cost
per review is over the reviews that called a model. Price overrides are
loaded before a review's model calls. Reviews from before this change have no
call time or duplicate count and are left out of those figures. Closes #107. -
Extended thinking, agentic context and model capabilities (#139).
llm.thinking(off,low,medium,high) andllm.verify_thinking
let review and verification calls reason first, mapped to each provider's
own option on native and proxied endpoints, with the budget added to the
output limit and the prompt ceiling, and temperature left out. Thestrict
profile thinkshigh.review.context: agenticlets a pass read files and
search code through read-only tools at the head revision before reporting
through areport_findingstool, withinreview.agentcaps; what it read
reaches the verifier, and usage records steps and tool calls. What each
model supports on each connection (thinking, tools) is probed when a model
is tested or first used (in parallel, with a timeout, and an inconclusive
probe is retried after a day rather than before every review), corrected at
runtime when an endpoint refuses an option or a custom endpoint ignores
thinking options (one retry without it, a review warning), shown under a
connection's Capabilities, and overridable in Configuration > LLM
(dashboard only). New endpointGET /api/settings/api-keys/:provider/capabilities.
The eval runner gains--thinking,--contextand--compare, and three
cross-file cases. -
Estimated model cost for reviews. Each model call now records its prompt
cache reads and writes and reasoning tokens alongside input and output, and
its cost, computed when the call is made from a built-in price table (exact
model, then the id without its provider prefix or router effort suffix, then
wildcard patterns; a model nothing matches costs $0, as do Ollama models,
which run on the user's own hardware). A model attempt whose reply could
not be used still counts its billed tokens, recorded as a failed call, so
the estimate includes spend a fallback model was needed for. Costs are stored with
the review, so a later price change leaves past reviews as they were, and
reviews from before this record none.GET /api/reviews/statssums them intocost, review
summaries carryusageTotals.costUsdand per-model costs, the stats strip
gains a Tokens tile and the review sidebar an Estimated cost row. Closes #87. -
A Usage page (
GET /api/usage) for code-review model spend: totals with
input, cached and output tokens and the estimated cost, a tokens / calls /
cost chart over 24 hours to all time, usage by provider and top models, the
latest reviews that called a model, and a table by model or by repository
showing costs (input, cached, output) or tokens. The Reviews page's Tokens
tile links to it. Charts use recharts, and the chart colour tokens are now a
colour-blind-checked palette in both themes. -
REVIEW_RETENTION_DAYSto stop review data growing without bound. When set,
the worker hourly deletes superseded, skipped and cancelled reviews older
than the window and clears the stored result, resolved configuration and
publication of older finished ones, keeping their row, verdict and summary so
lists, stats and the findings list are unaffected. The newest completed or
partial review of each change is never cleared, so its findings' details,
inline-thread answers and incremental reviews keep working. Pruning runs in
batches. The review page says when a result has expired and its markdown
export returns 410.
Unset keeps everything. Includes a migration (aresult_expired_atcolumn
and an index on review jobs). Closes #86. -
Notifications for finished reviews. Workspace admins add targets under
Notifications: an outgoing webhook signed with an HMAC-SHA256
X-Sentryward-Signatureheader (the secret is shown once), a Slack
incoming webhook, or email to chosen members through the existing mailer.
Each target picks its events (blocked, failed, completed), can send a test,
and gets one delivery per review. The worker sends them best effort once a
review finishes, fails or times out: a failed delivery is logged and never
fails the job. URLs are stored encrypted and go through the same production
host checks as self-hosted forges. Includes a migration (a
notification_targetstable and anotified_atcolumn on review jobs).
Closes #85. -
Personal API tokens for scripts and CI. Create them under Settings > API
tokens, with a name and an optional expiry. The value is shown once and only
its hash is stored. Requests send it asAuthorization: Bearer <token>and
act as the token's user, with the workspace header choosing the workspace.
A token can read anything its user can and queue or rerun reviews; other
writes, and managing tokens, need a signed-in session. Revoked or expired
tokens get 401, token requests share their user's rate limit, and deleting
the account deletes its tokens. Includes a migration (anapi_tokens
table). Closes #84. -
Password reset. "Forgot password?" on the login page emails a single-use
link that expires after 1 hour, and the request answers the same way
whether or not the email has an account. Without mail configured, the page
asks the user to contact an admin, who can create a reset link (single use,
24 hours) from the user's actions on the Admin page, with or without mail.
Setting a new password signs the user in and ends every other session.
Includes a migration (apassword_resetstable and asession_version
column on users). Closes #83. -
Findings are classified across runs as new, still open, reopened, fixed
or invalidated. Each review after a change's first records this in its
result (lifecycle), and the summary comment opens its findings with a
"Since the last review" line and a list per group, at most 20 entries each
(output.finding_lifecycleturns it off). A finding counts as invalidated
rather than fixed when its file was renamed, deleted or dropped from the
change, or the same problem now appears in a file the change adds or
renames and is the only one of its kind (that finding is still open, not
new). A finding resolved earlier and reported again is reopened. Findings
carry alifecyclecolumn,GET /api/findingsfilters bylifecycle, the
findings page gains a "Last review" filter, and invalidated findings no
longer count as resolved in the stats. Includes migrations (a
finding_lifecycleenum and column, backfilled from each finding's state,
and anend_linecolumn so gone findings keep their line range). Closes
#104. -
Structured evidence on findings. The model now returns a finding's
impact(what breaks, and for whom) andfixRationale(why the suggested
fix works) as separate fields instead of folding them into the body; inline
comments, the summary comment, agent prompts and the dashboard show them
under their own headings. Each finding also records whatreview.verify
made of it (verified,uncertainornot_checked): forge comments mark
verified and uncertain findings, and the dashboard shows a badge for all
three. Results stored earlier have none of these and read as not checked. -
GET /api/findings/calibration?repoId=&days=&groupBy=measures how the
confidence models self-report has matched outcomes: findings bucketed by
reported confidence in tenths, with confirmed (fixed) and false-positive
rates over the findings that were decided, overall or bymodelor
category. The False positives tab gains a card showing it. Includes a
migration adding aconfidencecolumn to findings, backfilled from each
finding's last run (null for tool and rule findings). Closes #105. -
Team rules in
.sentryward.yaml. Aruleslist states a convention once,
with anid,description,severityand optionalcategory,paths
globs andgood/badexamples, read from the base revision like the rest
of the file. A rule with a
pattern(an RE2 regular expression, matched in linear time) is checked
against the change's added lines without a model, so the same diff always
gives the same findings; the rest are given to the model, and a violation it
reports is filed under the rule with the rule's severity. Both are reported
with sourceruleand the rule's id, block atreview.block_on, are
reported whateverreview.categoriesholds, and are marked with the rule in
forge comments and the dashboard. The False positives tab gains a per-rule
table, and a change to the rules makes the next push a full review. Includes
a migration adding arule_idcolumn to findings. Closes #106. -
Team rules in dashboard settings. The global config (every repository in
the workspace) and repository settings can hold aruleslist, edited on
the Configuration page's Guidance tab. Unlike other lists, rules combine
across layers in the order global config, repository settings,
.sentryward.yaml: a later layer can add rules but never remove or override
an earlier one, so a rule reusing an id is ignored with a review warning,
and a layer whose rules would take the combined list past the limits is left
out as a whole, with a warning. Repository settings whose rules clash with
or do not fit beside the global ones are refused on save, and the global
config lists repositories whose rules it leaves out. Dashboard rules keep the
dashboard'sseverity_floorandmin_confidence(a repository file can only
lower them for those rules), and their patterns still run on files only the
repository file ignores. The effective config names each rule's layer
(sources["rules.<id>"]). The editor checks patterns with the server's RE2
as they are typed (POST /api/config/rules/check), and inline comments for
rule findings include the rule's description and paths, since dashboard
rules are not visible in the repository. Closes #140. -
Notification targets can be paused. Admins switch a target off from the
Notifications list (PATCH /api/notifications/:idwithactive) to stop
its deliveries while keeping its name, events, recipients, URL and signing
secret, and switch it back on later. Reviews that finish while a target is
paused are never sent to it, even after it is resumed. The list sorts and
filters by status, paused targets still accept test deliveries, and members
see the switch but cannot change it. Existing targets stay active (migration: anactivecolumn on
notification_targets, default true). Closes #130. -
Actionable states for reviews that did not succeed (#158). A failed,
cancelled or skipped review offers Re-run in its alert (not while the
repository's reviews are off, by hand or after lost access, since the server
refuses it), plus a link to
the page that fixes the cause: LLM Connections for a missing, removed or
mismatched key, the review settings when no connection is selected, the
Installation tab for refused forge credentials or lost access, Repositories
for reviews turned off, Privacy for a blocked model, and the repository's
Triggers tab for a skip (noting when.sentryward.yamlsets the trigger).
GET /api/reviews/:idnow returnserrorKind, derived from the stored
error when read (including errors recorded as a failed review pass), so
older reviews get one too and no migration is needed, and
repository.enabled, which decides whether Re-run is offered.
"Review not found." links to the reviews list. -
Unsaved-changes guard on the Review settings, Privacy and Profile forms
(#163). Leaving a form with unsaved edits (a link, Back, switching the
Review settings scope from the picker or any link, or a Settings or
Instance settings tab that hides the form) asks to keep editing or discard,
and reloading or closing the tab shows the browser's prompt. Switching the
Review settings tabs never asks. While there are edits, the Review settings and Privacy save bars
pin to the bottom of the page, and Review settings gains a Discard button. -
Each Review settings field tags its effective value with where it comes
from:default,profile: <name>,global,repo overrideor the
repository file (#164). In a repository's scope, a field the repository
file sets is locked, with a tooltip saying the file wins over the dashboard. -
Sidebar attention indicators (#162). Reviews shows a count of runs that
failed since you last opened the list (the last 24 hours before your first
visit), counting only a change's latest run, as the list's default view
does, and LLM Connections and Repositories show a warning dot when a
connection is revoked, unreachable, blocked by policy or unreadable. The
sidebar starts no credential checks of its own: it shows stored flags and
the checks those pages and Home already ran. The
state is part of each link's accessible name and tooltip, and a collapsed
sidebar keeps a dot on the icon. NewGET /api/reviews/attentionand
POST /api/reviews/viewedendpoints, backed by a new
memberships.reviews_viewed_atcolumn, track the visit per member and
workspace, so it clears on every device. Leaving the list on a workspace
switch records the visit in the workspace that was open. -
Drag-to-reorder connections. Workspace admins can drag a connection card by
its handle (or move it with the keyboard: Space, arrow keys, Space) to set
the order everyone in the workspace sees. The order is saved by the new
PUT /api/connections/orderendpoint in a newforge_connections.position
column; connections added later go after the ordered ones. Reordering is
off while searching or filtering, since the order belongs to the whole list.
Quick successive drags are saved one after the other, so the last order
chosen is the one stored, and overlapping saves (two admins at once) wait
for each other instead of failing. A save refused because the list changed
says so rather than showing a generic error. -
"Reconnect" on a connection whose credentials the forge rejected. It opens
the connect sheet with that connection's provider, hosting option and host
already filled in, so connecting the same account again resumes automatic
reviews and keeps its repositories and history. -
Drag-to-reorder repositories, the same way as connections. The order is
saved by the newPUT /api/repos/orderendpoint in a new
repositories.positioncolumn.GET /api/reposstill lists by path (the
pickers elsewhere rely on that) and now returns each repository's
position, which the Repositories tab sorts by, with unplaced ones last. -
Each repository card shows its last review: the verdict (or status while it
is queued, running or failed), the pull or merge request number and how long
ago, linking to the review. The newGET /api/repos/last-reviewsendpoint
returns them, read in one query, so pages that only list repositories don't
pay for it; skipped and superseded runs don't count. A new
review_jobs (repository_id, created_at)index serves it.
Changed
-
The Installation tab lists connections as a grid of cards instead of a
table. Each card shows the account, host, connection type, status,
repository count and who added it and when, with "Manage repositories" and
"Details" buttons; the menu keeps Details and Remove. Column sorting and
pagination are gone from this tab, replaced by the saved drag order, and
it shows skeleton cards while loading instead of a blank area. Its search,
filter and "Add connection" controls sit on the left, in that order. -
The Repositories tab lists repositories as a grid of cards instead of a
table, with the same left-aligned search, filter and "Add repository"
controls. Each card shows the path (linking to the forge), account, default
branch, connection status, whether it uses global or custom settings, its
last review and the review switch. Column sorting and pagination are gone
from this tab, replaced by the saved drag order; it shows 24 cards at a
time with a "Show more" button. Turning reviews on or off now only locks
that repository's switch while it saves, not every switch. -
LLM Connections shows every provider as a card, connected or not, instead
of a table of stored keys with search, filters, sorting and pagination. Each
card states what its reviews use (your key, the server's key, or nothing),
explains a problem in visible text and offers the action that fixes it:
"Replace key" for a rejected or unreadable key, "Check again" for one that
could not be verified, and a link to the privacy policy (with "Connect"
disabled) for a provider it blocks. "Connect", "Use my own key" and
"Replace key" open a sheet for that card's provider (no provider picker),
with a link to where the key is created and the custom host under
"Advanced". Testing a model and the capability list move into one Details
sheet per connection. Cards show when the status was last checked and can
check it again, the page header sums up how many providers are connected
and how many need attention, and the page shows placeholders while loading
and a retry on error. The "Inactive" and "Unknown" statuses read "Key
rejected" and "Couldn't verify". The cards are laid out like the
Repositories page's, and workspace admins can drag them by their handle
(or move them with the keyboard) into an order saved for the workspace. -
Redesigned login, sign-up, password reset and invite pages. On wide screens
they split into a product panel (what Sentryward does, light or dark with
the theme) beside the form; on phones only the form shows, under the logo.
Password fields get a show/hide toggle, sign-up and reset show a live
strength meter and a "Passwords match" check (advisory, the 8-character
minimum is still the only rule), inputs carry icons, and the first field
is focused. Errors that aren't about a field, like wrong credentials,
appear as an alert in the form instead of a toast, and the first user's
"you will be admin" note is an info alert. The product panel plays an
example review on a loop: a small diff gets an inline finding (severity,
title typed in, explanation and a suggested change), then the
sentryward/reviewstatus turns into a verdict, across three examples.
Behind it, a slow brand-blue waveform drawn as dithered vertical bars
(wider where it is brighter) drifts across the right of the panel, fading
out under the text. Both only run while the panel is on screen and the tab
is visible, and hold still with reduced motion. -
The review page header groups "Copy prompt for all findings", "Copy
markdown" and "Download markdown" into an Export menu (#155), leaving Re-run
(and Cancel while the review is active) as the only buttons. Items keep
their disabled states, and the Export button shows a spinner while a
markdown copy or download is still running. -
Rows in the Reviews and Findings tables open on a click anywhere outside
their controls (#160), not just on the title. The title stays a real link
(or button), so middle-click and Cmd-click still open a new tab, and the
runs toggle, forge link and row menu do not open the row. Modified clicks
and clicks that end a text selection are left alone. -
The Reviews and Findings lists keep their filters, search, view and sort in
the URL (#159), so Back from a review restores the list and a copied link
reproduces it. Values the page does not know fall back to defaults. Each
Findings tab keeps its own (?fpSeverity=and so on for false positives),
switching tabs keeps both, and a review's "Back to reviews" link returns to
the filtered list it was opened from, also after a re-run from the review. -
The client uses a data router (
createBrowserRouter) so forms can block
navigation; routes still live inApp.tsx. -
Home replaces the status hero with a setup checklist built from live
data: connect GitHub or GitLab, enable a repository, connect an LLM
provider (with the same usability checks the hero had) and run a first
review. Finished steps are ticked, the next one gets the primary button,
and the checklist disappears once every step is done. Only a completed or
partial review counts as the first one (skipped, failed and cancelled runs
don't), and its "Review a change" action waits until the steps before it
are done. A list that fails to load counts its step as done rather than
asking for something that may exist. Suggested actions no longer list
setup steps: "Can't reach your LLM provider" appears while a key fails its
status check (instead of reopening setup), "Review a change" after the
first review, and "Turn on automatic reviews" once setup is done but only
requested reviews run. Closes #153. -
GET /api/settings/api-keysreportsblockedper provider: whether the
privacy policy refuses that provider or its host, whichever key is used. -
The dashboard sidebar is split into labelled groups: Activity (Reviews,
Findings), Insights (Usage, Benchmarks), Workspace (Repositories, LLM
Connections, Review settings, Notifications, Privacy, in setup order) and,
for instance admins, Administration (Users, Instance settings). This
replaces the "User Management" collapsible. The current team's page moved
from the sidebar to a "Team settings" item in the workspace switcher (team
workspaces only). The breadcrumb now starts with the page's group, and the
Configuration page is renamed Review settings (its/configurationURL is
unchanged). -
The Privacy page's Policy tab shows the workspace policy form with an
"In effect" summary beside it (the stricter of the instance and workspace
policies; stacked on narrow screens). The policy form (also used by
Instance settings) is split into "Where code can be sent" and "Data
retention" sections. Allowed providers is a multi-select dropdown in
which providers the instance blocks are disabled, retention has a "days"
unit and presets, retention above the instance limit is caught before
saving, and a Reset button undoes unsaved changes. Members see a note
that only owners and admins can edit. -
Model prices moved to their own tab on the LLM Connections page
(/llm-connections?tab=prices), next to the Connections tab. The
Benchmarks page's "Unknown" cost link opens that tab. -
The Delete account card moved to the bottom of the Profile settings tab
and the Account tab is gone. Old/settings?tab=accountlinks open the
Profile tab. Closes #146. -
Changing your password in Settings now signs you out on other devices,
keeping only the current browser signed in. Existing sessions stay valid
through the upgrade. -
The Reviews page's changes view counts its total with one SQL query
instead of loading every pull/merge request key matching the filters, so
page loads and polls no longer grow with the whole review history. Totals
are unchanged for every filter. Closes #89. -
Copying and downloading a review's markdown share one helper on the
client, so the review page and the Reviews table row menu fetch it, report
failures and track pending state the same way. The row menu's copy now
goes through the same clipboard path as the review page. Closes #95. -
Confidence is labelled as self-reported wherever it appears: the dashboard
shows "Self-reported confidence" instead of a bare percentage, the minimum
confidence setting says it is the model's own estimate, and forge comments
still never show it. -
The Usage page paginates its lists. Recent reviews now pages through every
review that used a model in the period instead of only the latest 10. It is
served a page at a time by the newGET /api/usage/recent(page,limit
up to 100), andGET /api/usageno longer returnsrecent. It and the
Usage by Model / Usage by Repository table page separately
(?recentPage=,?usagePage=). The table sorts across every row before
paging. A new period sends both lists back to page 1, and so does a new
sort, view or Costs/Tokens mode for the table. Each table's rows-per-page control now has
its own id, so two on one page keep their labels. Closes #132.
Fixed
-
The "Sign up" link could disappear from the login page.
GET /api/auth/registrationshared the login rate limit (20 per 15
minutes), and every auth page load reads it, so reloading those pages
could exhaust the allowance; it now uses the general API rate limit. -
The home status no longer says "Reviews are on" when the workspace has no
usable LLM connection: it asks for one first. A server-provided key counts
as usable unless the workspace stored its own key for that provider (reviews
use the stored one, so a revoked stored key counts as missing) or the
privacy policy blocks the provider. A provider that does not answer its
status check gets its own "Can't reach your LLM provider" message instead.
Closes #152. -
An open finding in a file the change later deletes is now resolved (as
invalidated) instead of staying open forever: a deleted file is never
reviewed, so the run never got to say the finding was gone. -
Webhook deliveries for one PR/MR that arrive at the same moment (two quick
pushes, a push and a/sentryward reviewcomment, or a redelivery) queue
one review instead of reviewing the same head twice. Enqueues for a change
are serialized, and the close cancel and stale-job recovery follow the same
rule: a recovered job is superseded when a newer one is already queued.
No migration needed. Closes #82. -
A token or OAuth connection whose credentials the forge refuses (revoked
or expired token, withdrawn OAuth grant, a token the server can no longer
decrypt) no longer queues a failing review on every push. Sentryward
records the refusal, either from the connection status check or from a
review that hits a 401/403 confirmed by an account check. It then stops
queueing reviews from that connection's repository hooks, skips webhook
reviews already queued, and shows "Automatic reviews are paused" on the
Repositories page. Connecting the same account again with a new token (or
signing in again) resumes reviews and keeps the history, as does a status
check that passes. Manual reviews still run. Includes a migration (one
nullable column). Closes #103. -
Searching reviews by title ignores case, like the repository path search,
in both the runs and changes views:fix loginnow finds "Fix login
redirect". Includes a migration that adds atitlecolumn to review jobs
and backfills it from each review's summary. The worker stores the title as
soon as it fetches the change, so skipped, cancelled and failed runs are
found by title and show it in lists too. A second migration adds trigram
indexes (pg_trgm) on review titles and repository paths so the search
does not scan the whole table. Closes #88. -
Client tests for the markdown download: the success test now waits for
Download markdown to be enabled again, so a stuck spinner fails it, and the
object URL stubs are restored after each test instead of leaking into later
ones. Test-only, no behaviour change. Closes #90, closes #91.
Full changelog: v0.2.0...v0.3.0