Breeze RMM v0.110.0 — restart prompts end users can postpone, contracts billed by device set, QuickBooks payments, and a customer portal that shows customers what they are paying for.
This is another large one: ~270 commits, ~1,900 files and 54 migrations since v0.109.0. Six multi-wave programs land together (reboot deferral, device-set billing, QuickBooks Phase C/D, portal visibility, AI budget alerts, AI agent graduation and impact), plus a 52-row pre-release browser sweep that found and fixed seven defects before the tag, and a real-endpoint check of the restart prompt on Windows 11, Ubuntu and macOS. Read the upgrade notes before you pull: the migration set is large but every index on a big table is built CONCURRENTLY, and there is no breaking change.
Summary
- End-user restart prompts with deferral — when a patch job needs a reboot, the signed-in user gets a native dialog (Windows, macOS, and now Linux via zenity) and can postpone it a policy-set number of times within a deadline. The device page shows the scheduled restart and the postponement count. Off by default (#4686, #4699, #4728, #4733, #4737).
- Device-set billing — contract lines billed by device role or device group, with included quantities and overage, editable lines, per-device billing evidence on every generated invoice, an optional "Billed devices" PDF appendix, and quote lines priced by device set (#4585, #4694, #4745, #4808, #4731, #4854, #4838, #4901).
- QuickBooks Online Phase C + D — push issued invoices to QuickBooks and pull payments back automatically via webhook plus a 15-minute reconcile sweep (#4492, #4531, #4800, #4795, #4827).
- Customer portal visibility — Dashboard, Security, Backups, Devices (with CSV export), Tickets with SLA badges and support usage, and Reports, each behind a per-organization toggle that fails closed server-side (#4626, #4627, #4647, #4740, #4744, #4749, #4750, #4734, #4804, #4815, #4836, #4850).
- Script cancellation foundation — the cancellation schema and the
script_cancelagent command are registered, and every execution and automation-run status now has a badge (#4788, #4799). The Cancel button itself lands in a later release. - AI budget alerts and AI agent graduation — threshold ladder with email delivery and partner fan-out, credit balance on the usage page; graduation evidence ledger, partner-key ceiling, four-eyes promote, an AI Impact page with estimated time saved, and a platform-admin AI kill switch (#4487, #4496, #4517, #4529, #4490, #4533, #4565, #4486, #4504, #4704).
- Scripts — selectable run context (System or logged-in user) everywhere, write device custom fields from script output, clone a script, and "Run again" from a past execution (#4906, #4692, #4722, #4781, #4897, #4895).
- Partner trust probation (hosted only) — new self-serve partners on the hosted service start in probation until a settled card payment ages or an admin approves them. Inert on self-hosted installs (#4567, #4588, #4599, #4603, #4602, #4604).
Added
- Patching — reboot deferral policy settings on the Patch tab (#4686); agent deferral state machine (#4699); Windows and macOS prompt via the desktop helper (#4728); Linux prompt drawn by the daemon as the signed-in user (#4733); scheduled-restart status on the heartbeat and console badges (#4737); unrated patches get an Unrated badge and an explicit opt-in before auto-approval, plus a dashboard callout (#4721, #4787, #4964, #4966).
- Billing — per-device-role lines (#4585), per-device-group lines (#4694), in-place line editing with audit events (#4745), included quantity and overage (#4808), device coverage lookup with deep links from coverage warnings (#4731), device-set quote lines with server-derived quantities and acceptance hash v2 (#4854), billing evidence per invoice (#4838, #4901), change-currency dialog for draft quotes and invoices (#4802), Billing entry in the Settings sidebar (#4636).
- Accounting — QuickBooks invoice push (#4492) and payment pull-back (#4531); reconcile skip reasons surfaced (#4795); voided or remotely deleted invoices refuse a push (#4800).
- Portal — visibility read model and toggles (#4627, #4647), dashboard (#4740), security overview and per-device protection (#4744), backups (#4749), device enrichment columns and CSV (#4734), ticket SLA and support usage (#4750), report foundation and Reports tab with PDF/CSV (#4804, #4815), Guest Ledger design pass (#4850).
- Devices — external device links (
device_external_links) with serial/hostname indexes and a device resolver, groundwork for importing custom fields from another RMM (#3257 W06, #4973); custom-field values validated on both shipped write paths (#4917). - Contacts (#3258 follow-ups) — CRUD and CSV import with a real
add_contactAI tool (#4530), Contacts tab and migration guide (#4546), inbound email requester → contact and portal ownership by contact (#4557), contact linking on Entra and Outlook add-in logins (#4594), invite warning when a contact could not be linked (#4590). - Scripts — run context selectable and visible everywhere (#4906); custom-field write-back from script output (#4692, #4722, #4781); clone/duplicate (#4897); Run again + post-run navigation (#4895); UDF help tooltip (#4703); cancellation schema and
script_cancelcommand registration — no UI yet (#4799). - AI — budget alert thresholds, recipients and delivery worker (#4487, #4496, #4517), partner credit balance on the usage page (#4529); graduation evidence ledger and state machine with four-eyes promote (#4490, #4533), graduation panel with "Approve and always allow" (#4565), impact accounting and the AI Impact page (#4486, #4504), platform-admin kill switch UI (#4704), triage skip reasons and drifted-card deselect (#4691),
ai.agent.circuit.openedevent (#4697), rename AI Workspace chat tabs (#4702),feedbackByon alert verdict badges (#4705). - Auth — org-level Enforce SSO surfaced on the login page (#4860); server-verified platform attestation for L4 authenticators, fail closed (#4724), challenge/verify mobile registration with ES256 (#4793), and an Apple App Attest verifier for iOS approver-key registration (#4968).
- Mobile — native FCM push on Android with a server-side sender (#4723, #4780); New ticket screen (#4560); Reply/Internal composer toggle (#4536); iPhone-only shipping and App Review layout pass (#4508, #4534, #4541).
- Partner API —
POST /partner-api/v1/enrollment-keys(#2826). - Self-hosting — internal-CA option for domains Let's Encrypt cannot reach, with an explained
ERR_SSL_PROTOCOL_ERROR(#4479);CADDY_LOCAL_CERTSwiring backfilled into the release-pinned templates (#4564). - Ops — retention/prune for
ticket_outbox,intent_outboxandmetric_anomaly_incidents(#4400); audit-log retention settings route and UI plus a default policy for new organizations (#4825, #4900); bounded nightly audit-chain verification (#4548); worker/metricsin the Prometheus scrape config (#4689).
Improved
- Performance — device activity feed uses an RLS-promotable two-arm predicate with partial indexes on
audit_logs(#4835); metric rollups roll each source in one pass (#4419); the Activities-tab audit count is capped at 10,000 (#4842); act-verify reads no longer pin a pooled connection across device round-trips (#4849); software-inventory ingest bounds its lock wait (#4411). - Devices — Patches tab links to the device's patch policy (#4701); org name in the breadcrumb links to org settings (#4695); an archiving org stays visible for its whole drain window (#4869); the permanent-delete undo toast names the device and surfaces the agent-unreachable warning (#4394, #4938).
- Remote tools — the Remote Tools tab persists in the URL hash and the terminal fills the viewport (#4641); Connect Desktop no longer revokes every live remote session (#4832); Caps Lock is synced instead of forwarded as a key (#4864); a cold Terminal mount survives a failed xterm stylesheet preload (#4893).
- Agent — Homebrew upgrade batches run
brew cleanup --prune=all(#4914); upload state advances only after confirmed delivery (#4859);secrets.yamlrename retries on a transient lock (#4840); the macOS updater and helper install stop churning the code-signing identity (#4862); helper session ids no longer embed host identity and value shapes are scrubbed from logs (#4876); Windows 10 / Server 2016 declared as the OS floor and the install one-liner forces TLS 1.2 (#4688, #4730). - Extensions — asset URLs are signed so dynamic
import()can load them (#4870). - Alerts — suppressed and dismissed alerts skip baseline notification fan-out (#4684).
- Quotes — quote emails send after the transaction commits with bounded mail transports (#4856); draft values reseed during render (#4819); the line grid no longer scrolls at 1280px (#4698); a failed quiet refetch no longer strands a new line (#4397).
Fixed
- Tenancy / GDPR — device org-move now re-stamps or severs
ticket_email_links,ticket_outbox,ticket_comments.agent_run_id,action_intents.scope_ticket_id,device_vulnerabilities.ticket_idandai_agent_runs.ticket_id(#4736, #4786, #4821, #4831, #4833, #4642); org erasure detaches restore commands (#4898);device_group_membershipsis pinned to its parents' org (#4857); composite tenant FKs ontime_entries/ticket_parts(#4726); org merge honours the canonical ticket lock order (#4823, #4741). - RLS / scope — forced parent-join RLS for
script_versions/script_to_tags(#4493); site scope enforced on maintenance window and DR plan mutations (#4848, #4855); policy compliance reads narrowed to the caller's site allowlist (#4899); partner-level config-policy assignments honoured in warranty and event-log retention (#4846); the partner-wide system-context escalations were removed (#4803); five earlier migrations that wrote rows without system scope are replayed correctly and a contract test now blocks new ones (#4926, #4866). - Auth — a rejected MFA proof or password is a 400 with a stable code, not a 401 that logs you out (#4651, #4739); the caller's session is re-issued when recovery codes rotate (#4646); current-password guesses are rate-limited on change-password and the portal (#4782, #4820); the SSO failure notice outlasts the refresh eviction (#4853).
- Patching — stranded pending
device_patchesrows are flipped by version compare (#4843); three silent-failure paths in patch dispatch and desktop finalization (#4845); per-patch status recorded instead of the batch result (#4407). - Scripts — approved content and execution results are preserved (#4904); parameters are delivered on the run-as-user helper path (#4891); execution history no longer shows an epoch-0 start time or a dead duration column (#4938).
- Activity log —
agent.command.*rows are no longer stamped success at dispatch, and the console renders a dispatched command as "Dispatched" rather than "Success" (#4405, #4938). - Billing — interactive contract-line device evidence is recorded (#4901); an error mapping row persists on a
currency_mismatchpush (#4827); the draft-invoice device appendix opens instead of bouncing to the Editor tab (#4938); WebP images are rejected at the upload boundary for quotes and catalog items (#4408, #4639). - Backup — device backup workloads are serialised per device (#4925); dispatch no longer duplicates child job rows on retry (#4852); an empty watch list is delivered instead of null (#4839).
- Admin — the partner trust queue no longer 500s on an ambiguous column (#4930); the trust queue and AI kill switch pages require platform admin.
- AI — the session allowlist is checked against the exposed MCP tool name (#4892); unknown
onlyToolsnames error instead of being dropped (#4796); actively-processing sessions are never evicted (#4406, #4742); auto-demote always notifies (#4640). - Portal — raw-SQL timestamps that 500ed Devices and Backups (#4836); dev module graph served under
/portalso islands hydrate (#4540). - Mobile — token refresh on every 401 (#4568, #4589), require-cycle fix (#4579), app-lock privacy cover cleared after sign-in (#4727),
ApiErroris a real Error subclass (#4779), approval takeover, chat hang, ticket keyboard and upload error surfacing from iOS testing (#4916). - Integrations — Umbrella reporting API receives epoch milliseconds (#4637); the M365 JWK secret file defaults to a placeholder instead of
/dev/null(#4844). - Plus ~30 further fixes across CI, tests and internal tooling.
Security
- Self-hosters are encouraged to upgrade. Hardening in this range: the RLS-bypassing partner read in the remote-access launcher is a real, audited escalation (#4847);
UPDATE/DELETE/TRUNCATEare re-revoked on append-only tables missing fromensureAppRoleand onperipheral_policy_delivery_events(#4789, #4826);DATABASE_URLno longer appears onpg_dump/pg_restore/psqlargv (#4635); a staletickets.assigned_teamcolumn is dropped (#4865); PAM rules pinned to an unreachable risk tier are flagged (#4877); helper session ids no longer leak host identity (#4876); password-guess rate limits on change-password and the portal (#4782, #4820). - No advisories are pending for this range.
Self-Hosting / Upgrade Notes
No breaking changes. No new required environment variables.
Upgrade command — bump BREEZE_VERSION in /opt/breeze/.env, then:
docker compose pull api web portal && docker compose up -d binaries-init api web portal(portal is a separate container — include it. If you have opted into the worker split, add worker.)
Database — 54 migrations. Take a snapshot first. All are idempotent and auto-apply on API boot via autoMigrate (unless AUTO_MIGRATE=false). They add the reboot-deferral, device-set billing, billing-evidence, QuickBooks, portal-visibility, cancellation, graduation, trust-probation, contact and device-external-link columns and tables; 2026-10-10-100000-device-external-links.sql also adds two plain (non-concurrent) indexes on devices for serial number and hostname, which is a brief write block proportional to your device count. Every index on a table that can be large is built CONCURRENTLY through the no-transaction lane (audit_logs device-feed partial indexes, outbox retention indexes, invoice_lines / contract_billing_periods unique indexes), so writes are not blocked; an interrupted build leaves an INVALID index that the migration reports loudly on the next boot (recovery: DROP INDEX CONCURRENTLY <name> and restart). Backfills that touch existing rows run under breeze.scope=system and log their row counts as Postgres WARNINGs — two to read after the first boot:
cleaned N contract_lines rows whose site belonged to another org(2026-10-05-100100-contract-lines-device-roles.sql): if N > 0, re-scope those lines in the contract editor before the next billing run.- The site-name stamp on
contract_lines(2026-10-08-101400-contract-lines-site-stamp.sql) records how many existing site-scoped lines were protected; a line whose site was deleted before this release stays ambiguous and keeps billing organization-wide until re-scoped (see behaviour changes). 2026-10-09-000600-rls-scoped-replay-v0110.sqlreplays five earlier migrations whose row-writing statements ran without system scope; expect itsrls-scoped replaywarnings with real counts.
Privileged statements were audited against a non-superuser role: the range creates SECURITY DEFINER trigger functions (owned by the migrating role) and nothing else privileged — no CREATE ROLE, ALTER … OWNER TO, CREATE EXTENSION, or schema GRANTs.
New optional environment variables (missing = feature off or default; never fail boot; map any you set in the api compose environment: block, not just .env):
QBO_WEBHOOK_VERIFIER_TOKEN— Intuit app verifier token forPOST /api/v1/webhooks/quickbooks. Without it the endpoint answers 503 and payment pull-back relies on the 15-minuteaccounting-reconcilesweep alone (the sweep is the guaranteed path either way).FIREBASE_SERVICE_ACCOUNT— service-account JSON for native Android push; unset = no FCM sends.BREEZE_AUTHENTICATOR_ATTESTATION_ENFORCED— require server-verified platform attestation before a mobile authenticator counts as L4. Defaults to on (an empty or unrecognised value keeps enforcement on; setfalseto relax it).AUDIT_CHAIN_VERIFY_MODE(incremental, default) andAUDIT_CHAIN_VERIFY_RESCAN_SLICES— nightly audit-chain verification is now bounded: incremental from the last anchor plus a rolling 30-night re-scan, instead of a full-table walk.AUDIT_CHAIN_VERIFY_ENABLED=falsenow stops an in-flight sweep, not just the schedule.TICKET_OUTBOX_RETENTION_DAYS,INTENT_OUTBOX_RETENTION_DAYS,METRIC_ANOMALY_INCIDENT_RETENTION_DAYS(default 14) with*_BATCH_SIZE/*_MAX_BATCHESknobs.PORTAL_STATE_BACKEND=redis— portal rate-limit state; defaults to Redis in production already.PARTNER_TRUST_MODE,IP_CLASSIFY_PROVIDER,IP_CLASSIFY_API_KEY,TRUST_ACTION_TOKEN_SECRET,PARTNER_MEETING_URL— hosted-only;PARTNER_TRUST_MODEresolves tooffunlessIS_HOSTED=trueregardless of value, and with it off no trust code path touches the database, Redis or the network.
New workers and routes. One more BullMQ worker (accounting-reconcile, 15-minute sweep); abuse-signals-sweep moves from hourly to every 15 minutes; new routes include POST /api/v1/webhooks/quickbooks, GET /api/v1/devices/:id/billing (partner or system scope, needs both devices:read and contracts:read), POST /partner-api/v1/enrollment-keys, the audit-retention settings route, and the admin trust queue.
Behaviour changes
- Reboot deferral ships off. Enable per policy on the Patch tab ("Let users postpone the restart"); the deadline is the guarantee, the postponement counter is a UX budget. Linux prompts need
zenityon the endpoint; without it the user still gets anotify-sendwarning but cannot postpone. - Deleting a site used by a site-scoped contract line now fails invoice generation loudly with
409 SITE_DELETEDinstead of silently billing every device in the organization (#4693). Re-scope or remove the line, then generate again. - Contract line API —
DELETE …/lines/:lineIdreturns404 LINE_NOT_FOUNDfor a missing line (was a silent 200) and{"data":{"ok":true}}on success;unitPrice/manualQuantity/sortOrderbounds andcatalogItemIdvalidation now apply on create (400 instead of 500); adding a line with a site from another organization is400 SITE_NOT_IN_ORG; generated invoice lines use deterministic(sortOrder, createdAt, id)ordering. PATCH /quotes/:id/lines/:lineIdreturns 400 for an unrecognised key instead of accepting the request and changing nothing.- Audit retention now runs for every organization. Previously the job pruned per policy row and nothing ever created one, so it never deleted anything. New organizations get a default policy row via a trigger; existing organizations still have no row until an operator saves one under Organization settings → Audit retention (new
audit:managepermission). Nothing is deleted until you do. - New partners get inbound email-to-ticket off on every creation path (#4638); existing partners unchanged.
- Windows 10 / Server 2016 is the declared agent OS floor (#4688); the install one-liner forces TLS 1.2 (#4730).
- Unrated patches are never coerced to Low and are excluded from auto-approval unless a ring opts in (#4721, #4787).
- AI agents, act mode, budget alerts and the kill switch remain off by default;
BREEZE_AI_AGENTS_ENABLEDstill gates the whole subsystem. - QuickBooks payment pull-back is on per connection (
pull_payments, default on) once a connection exists; there is no connection until you complete the OAuth flow.
Full Changelog: v0.109.0...v0.110.0
What's Changed
- feat(api,shared): P2-6a — AI agent impact accounting: daily rollup, partner impact weights, /ai/agents/impact API (#4187) by @ToddHebebrand in #4486
- ci(selfhost): run guided-setup.sh end to end on a runner — systemd unit, packaged Caddy, bootstrap login, SSH-tunnel refresh by @ToddHebebrand in #4478
- feat(selfhost): internal-CA option for domains Let's Encrypt cannot reach; explain ERR_SSL_PROTOCOL_ERROR by @ToddHebebrand in #4479
- fix(mobile): realign iOS deps to Expo SDK 57 so the app compiles again by @ToddHebebrand in #4488
- feat(api,shared): P2-5a1 — graduation evidence ledger, exactly-once evidence writers, intent-anchored fix watches (#4187) by @ToddHebebrand in #4490
- fix(mobile): generate the iOS project in Xcode Cloud via ci_post_clone by @ToddHebebrand in #4494
- feat(accounting): QuickBooks invoice push (Phase C) by @ToddHebebrand in #4492
- feat(web): P2-6b — AI Impact page: daily counters, estimated time saved, weights editor, PDF export (8 locales) (#4187) by @ToddHebebrand in #4504
- docs(integrations): replace the Intuit sandbox sample email — unreds the customer-PII guard on main by @ToddHebebrand in #4509
- fix(rls): forced parent-join RLS for script_versions / script_to_tags (RMM-QA-220) by @ToddHebebrand in #4493
- docs: v0.109.0 sweep (v0.108.0..v0.109.0) by @ToddHebebrand in #4507
- fix(api): align enrollment-key TTL fallbacks with the 30-day default (#4126 follow-up) by @ToddHebebrand in #4506
- feat(api,shared): P2-5a2 — graduation: partner-key ceiling, eligibility + state machine, four-eyes promote (manage_ai_agents), auto-demote, graduation API (#4187) by @ToddHebebrand in #4533
- QuickBooks Phase D: payment pull-back (QBO to Breeze) by @ToddHebebrand in #4531
- fix(mobile): getServerUrl throws on a failed read instead of returning null (#4002) by @ToddHebebrand in #4393
- fix(web): surface permanent-delete's agent-unreachable warning (#4368) by @ToddHebebrand in #4394
- fix(api): escape the request context in the scriptDispatch actor probe (#4299) by @ToddHebebrand in #4395
- fix(mobile): gate ack un-hide on activeAlerts fetch generation (#3782) by @ToddHebebrand in #4396
- fix(web): stop a failed quiet refetch from stranding new quote lines (#4286) by @ToddHebebrand in #4397
- fix(api): desktopWs input schema omits key_press, drops paste-as-keystrokes on WS fallback (#4370) by @ToddHebebrand in #4398
- fix(web,api): jitter throttled-refresh retries, single retry owner, correct rate-limit remaining (#3984) by @ToddHebebrand in #4399
- fix(extensions): record activeVersion only after built-in activation succeeds (#3468) by @ToddHebebrand in #4401
- fix(api): exclude ws-ticket polling from fallback audit logging (#3991) by @ToddHebebrand in #4402
- fix(api): split remote-access launcher availability from issuance (#3402) by @ToddHebebrand in #4403
- fix(api): stop stamping agent.command.* audit rows as success at dispatch (#4225) by @ToddHebebrand in #4405
- fix(ai): don't evict an actively-processing OpenAI session; expire the row on every eviction path (#4384) by @ToddHebebrand in #4406
- fix(quotes): reject WebP quote images at upload (#3483) by @ToddHebebrand in #4408
- fix(ops): make docker-compose.monitoring.yml composable with prod stack (#4362) by @ToddHebebrand in #4409
- fix(api/ai): report LLM stream 'error' events to Sentry (#4329) by @ToddHebebrand in #4410
- fix(api): bound the agent software-inventory ingest's lock wait (#3925) by @ToddHebebrand in #4411
- perf(api): roll up each metric source in one pass instead of once per metric (#4341) by @ToddHebebrand in #4419
- test(api): address review findings on the offboarding lock barrier (#4036) by @ToddHebebrand in #4516
- feat(ai): pre-cap AI budget alerts W01 — schema, threshold ladder, rung evaluator (#4388) by @ToddHebebrand in #4487
- test(devices): bind the ai_agent_runs detach contract to reachability (#4215 review follow-up) by @ToddHebebrand in #4515
- fix(api): record per-patch status instead of collapsing to batch status (#4267) by @ToddHebebrand in #4407
- feat(api): retention/prune job for ticket_outbox, intent_outbox and metric_anomaly_incidents (#4210) by @ToddHebebrand in #4400
- fix(mobile): App Review layout pass (ticket activity, alert detail, onboarding, MFA, status pill) by @ToddHebebrand in #4534
- chore(mobile): ship iPhone-only, and document the App Review reply by @ToddHebebrand in #4508
- feat(contacts): W02 contact CRUD + CSV import + real add_contact AI tool (#3258) by @ToddHebebrand in #4530
- feat(mobile): Reply/Internal toggle on the ticket composer, defaulting to internal by @ToddHebebrand in #4536
- test(api): bracket the fixWatch recovery cutoff instead of asserting it backwards by @ToddHebebrand in #4538
- chore(deploy): map outbox/anomaly retention knobs into droplet compose (follow-up to #4400) by @ToddHebebrand in #4539
- feat(ai): pre-cap AI budget alerts W02 — recipients, email, delivery worker, partner fan-out (#4388) by @ToddHebebrand in #4496
- docs(accounting): Phase D payment pull-back sandbox walk (17-25 PASS) + cursorAfter log fix by @ToddHebebrand in #4537
- feat(ai,web): AI budget alert thresholds UI + /ai/usage alerts (#4388 W03) by @ToddHebebrand in #4517
- fix(portal): serve the dev module graph under /portal so islands hydrate (#3906) by @ToddHebebrand in #4540
- docs: partner trust probation spec + plan (feature #4549) by @ToddHebebrand in #4558
- fix(mobile): pre-submission pass (time-entry labels, empty-activity gate, build 8, privacy manifest) by @ToddHebebrand in #4541
- perf(api): bounded nightly audit-chain verification — incremental from the anchor + rolling 30-night re-scan by @ToddHebebrand in #4548
- feat(ai,web): surface partner AI credit balance on /ai/usage and the usage page (#4388 W04) by @ToddHebebrand in #4529
- feat(mobile): New ticket screen behind a + on the Tickets tab by @ToddHebebrand in #4560
- fix(selfhost): backfill CADDY_LOCAL_CERTS wiring into release-pinned templates by @ToddHebebrand in #4564
- feat(web,contacts): W04 contacts tab, CSV import UI, migration-guide docs (#3258) by @ToddHebebrand in #4546
- fix(mobile): reload the timesheet on focus by @ToddHebebrand in #4566
- ci: non-blocking portal dev-mode e2e job (hydration guard for #3906) by @ToddHebebrand in #4563
- fix(mobile): refresh the access token on 401 for every request by @ToddHebebrand in #4568
- feat(web,api): P2-5b — graduation panel, 'Approve and always allow', partner-ceiling hint, impact promote-eligible tile (8 locales) (#4187) by @ToddHebebrand in #4565
- fix(mobile): break the api.ts and tokenRefresh.ts require cycle by @ToddHebebrand in #4579
- ci: guard every playwright install against the runner apt 403 (composite action) by @ToddHebebrand in #4580
- feat(contacts): W03 inbound email requester → contacts, tickets.requester_contact_id, portal ownership by contact (#3258) by @ToddHebebrand in #4557
- docs(ai-agents): graduation feedback loop and AI impact accounting (#4187) by @ToddHebebrand in #4581
- fix(mobile): refresh on 401 for services that fetch outside the request core by @ToddHebebrand in #4589
- feat(web): warn when a portal invite could not link a contact (#3258 follow-up) by @ToddHebebrand in #4590
- chore(migrations): pre-push guard re-checks migration order against origin/main by @ToddHebebrand in #4591
- fix(db): make the AI-agent graduation composite FKs deferrable; scope the test-side FK repair helper so CI can catch it (#4187 follow-up) by @ToddHebebrand in #4595
- fix(db): same-org composite FK on portal_users.contact_id (#3258 follow-up) by @ToddHebebrand in #4593
- fix(contacts): link a contact on Entra and Outlook add-in logins (#3258 follow-up) by @ToddHebebrand in #4594
- docs(portal): customer portal visibility — Wave 1 spec + plan (#4562) by @ToddHebebrand in #4598
- fix(portal): W01 remove misleading report surfaces (#4562) by @ToddHebebrand in #4626
- feat(trust): partner trust probation foundation (W02, #4549) by @ToddHebebrand in #4567
- feat(trust): command dispatch chokepoints (W03, #4549) by @ToddHebebrand in #4588
- feat(portal): W02 portal visibility read-model foundation (#4562) by @ToddHebebrand in #4627
- chore(deps): pin fast-uri to 3.1.7 for six HIGH advisories by @ToddHebebrand in #4632
- feat(trust): session, distribution and enrollment gates (W04, #4549) by @ToddHebebrand in #4599
- docs(release): draft notes for partner trust probation by @ToddHebebrand in #4625
- fix(web): add Billing to the Settings sidebar section by @ToddHebebrand in #4636
- fix(integrations): send epoch-millisecond from/to to the Umbrella reporting API (#4597) by @ToddHebebrand in #4637
- fix(web): persist Remote Tools tab in the URL hash and let the terminal fill the viewport (#4512, #4510) by @ToddHebebrand in #4641
- chore(deps): override fast-uri to >=3.1.6 (four HIGH CVEs) by @ToddHebebrand in #4631
- feat(trust): promotion, IP classification, hard denies, admin surface (W05, #4549) by @ToddHebebrand in #4603
- feat(trust): probation banner, review request, admin action page (W06, #4549) by @ToddHebebrand in #4602
- feat(billing): contract lines billed by device role (#3205) by @ToddHebebrand in #4585
- chore(trust): rollout tooling and admin trust queue (W07, #4549) by @ToddHebebrand in #4604
- feat(patching): reboot deferral policy settings (#3207 W1) by @ToddHebebrand in #4686
- docs(plan): end-user reboot prompts with deferral (#3207) by @ToddHebebrand in #4666
- fix(tickets): scope AI draft card action lock to its own draft id (#4469) by @ToddHebebrand in #4683
- fix(alerts): skip baseline notification fan-out for suppressed/dismissed alerts (#4123) by @ToddHebebrand in #4684
- fix(ai-agents,approvals): partner ceiling hint in Shadow, collapse per-intent links, client BATCH_MAX guard by @ToddHebebrand in #4687
- fix(agent): declare Windows 10 / Server 2016 as the agent OS floor (#4608) by @ToddHebebrand in #4688
- fix(ops): wire the worker /metrics endpoint into Prometheus scrape config (#4523) by @ToddHebebrand in #4689
- feat(api): partner-wide SELECT branch on the config-policy RLS chain (#2468) by @ToddHebebrand in #4690
- feat(scripts): write device custom fields from a script — API ingest (#4679) by @ToddHebebrand in #4692
- fix(web): link org name in device breadcrumb to org settings page (#3839) by @ToddHebebrand in #4695
- fix(mobile): surface alert category from the rule's template (#4535) by @ToddHebebrand in #4696
- fix(web): quote editor line grid no longer scrolls at 1280px with sidebar open (#4668) by @ToddHebebrand in #4698
- docs(ai-guardrails): document draft-inert / send-gated MCP tier boundary (#2551) by @ToddHebebrand in #4700
- fix(api/auth): a rejected MFA proof is 400 + a stable code, not 401 (#4470) by @ToddHebebrand in #4651
- docs(billing): #3205 waves W03–W07 specs and plans by @ToddHebebrand in #4706
- test(web): scope AiUsagePage test queries to their own render container (#4601) by @ToddHebebrand in #4658
- fix(web): refetch the mounted approximate-total line on a partner currency reset (#4472) by @ToddHebebrand in #4634
- fix(api): apply the new-partner inbound default on every creation path (#4520) by @ToddHebebrand in #4638
- fix(api): reject WebP catalog item images at the upload boundary (#4521) by @ToddHebebrand in #4639
- fix(api/ai): always notify on auto-demote, even with no readable run (#4582) by @ToddHebebrand in #4640
- test(api): guard integration-suite include/exclude coverage (#4522) by @ToddHebebrand in #4649
- fix(api/tenancy): sever ai_agent_runs.ticket_id on a ticket org-move (#4524) by @ToddHebebrand in #4642
- feat(ai-agents): register ai.agent.circuit.opened event type (#4205) by @ToddHebebrand in #4697
- feat(devices): link Patches tab to the device's patch policy (#4671) by @ToddHebebrand in #4701
- feat(workspace): let users rename AI Workspace chat tabs (#4280) by @ToddHebebrand in #4702
- feat(scripts): add help tooltip for UDF (custom field) read/write (#4198) by @ToddHebebrand in #4703
- feat(alerts): surface feedbackBy in the alert verdict badge (#4445) by @ToddHebebrand in #4705
- feat(agent): reboot deferral state machine (#3207 W2) by @ToddHebebrand in #4699
- feat(billing): contract lines billed by device group (#3205 W02) by @ToddHebebrand in #4694
- fix(api): re-issue the caller's session when MFA recovery codes are rotated (#4480) by @ToddHebebrand in #4646
- feat(portal): W03 visibility toggles, fail-closed gates, nav + landing, MSP editor (#4562) by @ToddHebebrand in #4647
- fix(mobile): clear the app-lock privacy cover after interactive sign-in by @ToddHebebrand in #4727
- feat(agent): end-user reboot prompt with deferral, Windows + macOS (#3207 W3) by @ToddHebebrand in #4728
- fix(ops): stop passing DATABASE_URL on pg_dump/pg_restore/psql argv (#4497) by @ToddHebebrand in #4635
- feat(ai-agents): surface ticket-triage skip reasons + deselect drifted batch cards (#4462, #4459) by @ToddHebebrand in #4691
- feat(web): platform-admin UI for the AI kill switch (#4208) by @ToddHebebrand in #4704
- fix(web): force TLS 1.2 in the generated Windows install one-liner by @ToddHebebrand in #4730
- fix(tenancy): composite tenant-integrity FKs on time_entries / ticket_parts (#4596) by @ToddHebebrand in #4726
- feat(auth): require a server-verified platform_bound_basis for L4 — W01 fail-closed (#4708) by @ToddHebebrand in #4724
- W01: Server-side native FCM sender + dispatch wiring (#3639) by @ToddHebebrand in #4723
- feat(api): populate currentPartnerId on agent DB contexts (#4675) by @ToddHebebrand in #4725
- fix(api/auth): change-password and account-deletion 400 a rejected password, not 401 (#4660) by @ToddHebebrand in #4739
- feat(portal): W07 device enrichment columns + CSV export (#4562) by @ToddHebebrand in #4734
- fix(api): stop Number() parsing scientific notation in inboundEmail fixture (#4495) by @ToddHebebrand in #4735
- fix(api): only stamp AI field provenance on a real change (#4466) by @ToddHebebrand in #4738
- feat(devices): report scheduled-restart status on the heartbeat and show it in the console (#3207 W5) by @ToddHebebrand in #4737
- feat(billing): contract line editing (#3205 W03) by @ToddHebebrand in #4745
- fix(api/ai): don't evict an actively-processing Anthropic session; expire the row on both staleness paths (#4514) by @ToddHebebrand in #4742
- fix(patches): stop coercing unrated severity to Low; add Unrated badge (W01) by @ToddHebebrand in #4721
- fix(web): AI agents UI critique pass — approver trust, dark mode, empty states, revoke by @ToddHebebrand in #4667
- fix(mobile): make ApiError a real Error subclass so instanceof narrowing works (#4747) by @ToddHebebrand in #4779
- fix(api/tenancy): re-stamp ticket_outbox.org_id on a device org-move (#4743) by @ToddHebebrand in #4786
- fix(api/ai): dedupe intent outcome notifications by outcome class (#4465) by @ToddHebebrand in #4785
- fix(api/auth): rate-limit current-password guesses on /auth/change-password (#4746) by @ToddHebebrand in #4782
- fix(web): fail closed on a failed advanced-filter preview (#4732) by @ToddHebebrand in #4783
- fix(api): add remediate_vulnerability to DEVICE_COMPLETE_TARGET_TOOLS (#4452) by @ToddHebebrand in #4794
- fix(ai-agents): error on unknown onlyTools names instead of silently dropping them (#4447) by @ToddHebebrand in #4796
- fix(api): log and surface QuickBooks reconcile skip reasons (#4543) by @ToddHebebrand in #4795
- feat(portal): W05 security overview + per-device protection page (#4562) by @ToddHebebrand in #4744
- W02: Script custom-field write-back — web toggle + run-detail panel + docs by @ToddHebebrand in #4722
- fix(api): mirror moveOrg's intent scope tombstone into the device org cascade trigger (#4454) by @ToddHebebrand in #4790
- fix(api): align ticket-triage proposal DTO's draft text with draftsWritten (#4467) by @ToddHebebrand in #4801
- fix(billing): block QuickBooks push on voided/remote-deleted invoices (#4544) by @ToddHebebrand in #4800
- feat(billing): device coverage lookup and coverage-notice deep links (#3205 W06) by @ToddHebebrand in #4731
- fix(web): add change-currency UI for draft quotes and invoices (#4416) by @ToddHebebrand in #4802
- fix(api): wrap loadIntentDecidedVia's per-event SELECT in try/catch (#4464) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4784
- feat(agent): Linux end-user reboot prompt with deferral (#3207 W4) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4733
- feat(reports): W09 portal report foundation — self-service marker, provenance, portal_user authority, contact recipients (#4562) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4804
- feat(portal): W04 dashboard API + landing page (#4562) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4740
- fix(api/tenancy): re-stamp ticket_email_links.org_id on a ticket org-move (#4643) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4736
- fix(web): seed the AI threshold ladder during render, not from an effect (#4659) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4805
- fix(api): re-revoke UPDATE/DELETE/TRUNCATE on append-only tables missing from ensureAppRole (#4371) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4789
- feat(portal): W06 backups overview + per-device backup page (#4562) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4749
- fix(api): make both org-move paths lock ticket_alert_links in one order (#4657) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4741
- feat(portal): W08 ticket SLA, support usage panel, invoice ticket numbers (#4562) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4750
- fix(web): AI agents UI critique pass 2 — run narrative, disable ceremony, weights units, runs list by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4729
- feat(agent): extract custom-field markers from raw script stdout (#2698) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4781
- feat(db,api): cancellation schema + script_cancel command registration (#3525 W02) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4799
- refactor(api/tenancy): remove the partner-wide system-context escalations (#4676) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4803
- W02: Android native FCM token registration + build-time google-services.json by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4780
- feat(patches): autoApproveUnrated opt-in wired into evaluator guards (W02) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4787
- W02: challenge/verify mobile registration protocol + ES256 (#4709) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4793
- feat(billing): contract line included quantity and overage (#3205 W04) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4808
- W01: Phase 0 — partner-wide custom-field UI gate + dropdown options contract fix by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4791
- fix(web): status maps cover every execution and run status (#3525 W01) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4788
- fix(web): deflake QuoteWorkspace superseded-GET and TicketWorkbench resolve-note prefill by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4816
- chore(agent): bump go-m1cpu to v0.2.2 (cgo init segfault on Apple Silicon, Go 1.26+) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4817
- fix(web): reseed quote/invoice drafts during render, not from a passive effect (#4807) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4819
- feat(portal): W10 reports tab — list, generate, PDF/CSV download, badge, e2e (#4562) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4815
- fix(api/portal): rate-limit password-change guesses, stop 401ing wrong ones (#4797) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4820
- fix(api): write an intent_outbox row when cancelActionIntent commits (#4798) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4818
- fix(api): make org merge honor the canonical ticket lock order (#4748) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4823
- fix(api/tenancy): sever ticket_comments.agent_run_id on a device org-move (#4644) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4821
- fix(api): persist an error mapping row on currency_mismatch invoice push (#4498) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4827
- fix(api): add audit-log retention settings route and UI (#4633) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4825
- fix(api): revoke UPDATE on peripheral_policy_delivery_events breeze_app grant (#4806) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4826
- fix(api): widen release-time actor context for approved move_org intents (#4650) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4829
- fix(api/tenancy): tombstone action_intents.scope_ticket_id on device org-move (#4792) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4831
- fix(api/tenancy): sever device_vulnerabilities.ticket_id on either org-move axis (#4645) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4833
- fix(web): stop Connect Desktop from revoking every live remote session (#4090) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4832
- fix(api): register local user-helper binaries (#4682) by @hcaldicott in https://github.com/LanternOps/breeze/pull/4720
- fix(web): AI agents UI critique pass 3 — findings on lists, disable vocabulary, mobile runs, policy-key labels by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4822
- fix(agent): treat a never-provisioned elevation account as clean in PAM cleanup (#4587) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4592
- docs: add model-routing strategy to CLAUDE.md; codex effort default now medium by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4443
- chore(deps): Bump the github-actions group across 1 directory with 6 updates by @dependabot[bot] in https://github.com/LanternOps/breeze/pull/4532
- chore(deps): Bump tauri-plugin-deep-link from 2.4.9 to 2.4.10 in /apps/viewer/src-tauri by @dependabot[bot] in https://github.com/LanternOps/breeze/pull/4809
- chore(deps): Bump tauri-plugin-shell from 2.3.5 to 2.3.6 in /apps/helper/src-tauri by @dependabot[bot] in https://github.com/LanternOps/breeze/pull/4810
- chore(deps): Bump tauri-plugin-shell from 2.3.5 to 2.3.6 in /apps/viewer/src-tauri by @dependabot[bot] in https://github.com/LanternOps/breeze/pull/4811
- chore(deps): Bump tauri-plugin-updater from 2.10.1 to 2.11.0 in /apps/viewer/src-tauri by @dependabot[bot] in https://github.com/LanternOps/breeze/pull/4812
- chore(deps): Bump tauri-plugin-clipboard-manager from 2.3.2 to 2.3.3 in /apps/viewer/src-tauri by @dependabot[bot] in https://github.com/LanternOps/breeze/pull/4813
- chore(deps): Bump tauri-plugin-single-instance from 2.4.3 to 2.4.4 in /apps/viewer/src-tauri by @dependabot[bot] in https://github.com/LanternOps/breeze/pull/4814
- fix(portal): raw-SQL timestamps 500ed Devices and Backups; stamp last_generated_at; label (#4562 QA walk) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4836
- fix(api): deliver empty watch list instead of null on zero enabled watches (#2949) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4839
- fix(agent): retry secrets.yaml rename on transient destination lock (#2772) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4840
- feat(billing): billing evidence per invoice — per-device evidence and per-period outcomes (#3205 W07) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4838
- feat(quotes): device-set quote lines — server-derived quantities, acceptance mapping, hash v2; fixes the deleted-site widening (#3205 W05, #4693) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4854
- perf(api): device activity feed — RLS-promotable two-arm predicate + partial indexes by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4835
- docs(deploy): nginx upstream ports are not published by default (#3229) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4889
- docs(skills): add feature-delivery orchestration skill by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4894
- feat(api/ai): explain runtime parameter delivery in Script Builder prompt (#4884) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4890
- feat(partner-api): add POST /partner-api/v1/enrollment-keys by @obsidiangroup in https://github.com/LanternOps/breeze/pull/2826
- fix(agent): deliver script parameters on the runAs=user helper path (#4882) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4891
- fix(api/ai): check the session allowlist against the exposed MCP tool name (#4883) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4892
- test(api): end-to-end coverage for cascadeDeleteOrg breadth and failure semantics (#3880) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4879
- fix(api): extend non-UTC TZ CI coverage to tokenRevocation.ts (#4059) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4878
- fix(api): flag PAM rules pinned to an unreachable risk tier (#3128) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4877
- fix(shared): promote SweepProposalReason to @breeze/shared (#4458) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4875
- refactor(api/ai): split the run-profile finalizers out of runLoop.ts (#4451) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4874
- fix(api/web): keep an archiving org visible for its whole drain window (#4166) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4869
- refactor(approvals): share the batch-grouping rule via @breeze/shared and extract the inbox helpers (#4457, #4456) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4868
- fix(api): drop dead tickets.assigned_team column (#4463) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4865
- fix(agent/viewer): sync Caps Lock state instead of forwarding it as a key (#3595) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4864
- test(api): contract-test FK ON DELETE actions against org erasure (#4519) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4863
- fix(agent/macos): stop churning code-signing identity in the updater and helper install (#3458, #3457) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4862
- fix(api): pin org_id on the hideAiNoise verdict correlation (#4446) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4861
- feat(auth): surface org-level enforceSSO on the login page (#3229) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4860
- fix(api): accounting captureException tags dropped by Sentry allowlist (#4828) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4858
- fix(api): enforce the site axis on DR plan, group and execution mutations (#3653) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4855
- fix(web): let the SSO failure notice outrun the refresh eviction (#3704) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4853
- fix(api): stop backup dispatch duplicating child job rows on retry (#4137) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4852
- fix(api): make mobile cursor pagination reachable and keyset-safe (#3770) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4851
- design(portal): bring the visibility pages into the Guest Ledger world (#4562 impeccable critique) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4850
- fix(api): stop act-verify reads pinning a pooled connection across device round-trips (#4150) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4849
- fix(tests): preserve current functions after migration replay (#4881) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4896
- fix(api): enforce site scope on maintenance window writes and reads (#3654) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4848
- fix(api/rls): make the remote-access launcher's partner read a real escalation (#3419) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4847
- fix(api): honour partner-level config-policy assignments in warranty + event-log retention (#3963) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4846
- fix(api): three silent-failure paths in patch dispatch and desktop finalization (#3945) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4845
- fix(ops): default M365 JWK secret file sources to a placeholder file, not /dev/null (#2991) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4844
- fix(api): flip stranded pending device_patches rows using version compare (#2736) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4843
- fix(api): cap the device Activities-tab audit count at 10,000 (#4834) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4842
- fix(api): AUDIT_CHAIN_VERIFY_ENABLED=false must stop the sweep, not just the schedule by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4841
- fix(web): survive a failed xterm stylesheet preload on a cold Terminal mount (#4152) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4893
- fix(api): narrow policy compliance reads to the caller's site allowlist (#4880) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4899
- feat(web): Run again + post-run navigation for script executions (#4885, #4886) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4895
- fix(api): pin device_group_memberships to its parents' org (#3182) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4857
- feat(scripts): add clone/duplicate action for scripts (#4887) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4897
- fix(api): send quote emails after the transaction commits, and bound the mail transports (#3905) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4856
- fix(agent): confirm delivery before advancing upload state (#3529) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4859
- fix(api): guard migrations that write rows without system scope (#4518) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4866
- fix(api/web): sign extension asset URLs so dynamic import() can load them (#4164) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4870
- fix(agent/api): stop helper session ids embedding host identity, scrub value shapes in agent logs (#3109) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4876
- fix(tenancy): detach restore commands during org erasure (#4871) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4898
- fix(billing): record interactive contract line device evidence (#4837) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4901
- fix(ci): drop restore_jobs.command_id from the FK ON DELETE burn-down ledger by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4908
- fix(agent): run brew cleanup --prune=all after Homebrew upgrade batches (#4912) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4914
- docs: correct security/feature page claims to match shipped code (#4911) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4915
- feat(scripts): make the script run context selectable and visible everywhere (#4888) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4906
- fix(api): seed audit retention for new organizations (#4824) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4900
- feat(api): validate custom-field values on both shipped write paths (#3257 W04) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4917
- fix(mobile,api,web): approval takeover, chat hang, ticket keyboard, upload errors from iOS test by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4916
- fix(scripts): preserve approved content and execution results by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4904
- fix(db): replay RLS-blind DML from five migrations under system scope + contract test by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4926
- fix(api): qualify columns in admin trust-queue device-count subquery (500: column "id" is ambiguous) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4930
- fix(backup): serialize device backup workloads (#4923) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4925
- qa: pre-release sweep v0.109.0 → main — 10 fixes + tracking doc by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4938
- feat(patches): unrated-patch warning note + opt-in toggle on ring form by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4964
- feat(patches): surface unratedSummary on compliance endpoint + dashboard callout by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4966
- chore(web): What's New entry for 0.110.0 by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4975
- docs(skills): feature-delivery — tag public roadmap label p as features are delivered by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4985
- docs+test(rls): guard partner-wide SELECT branch coverage (#4673 wave 4) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4965
- feat(auth): Apple App Attest verifier for iOS approver-key registration (#4710) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4968
- feat(api): device_external_links + serial/hostname indexes + device resolver (#3257 W06) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4973
- docs: v0.110.0 sweep (v0.109.0..v0.110.0) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4986
- chore(web): What's New 0.110.0 — script cancellation is not user-facing yet by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4987
- fix(installer): WiX comments must not contain '--' (WIX0104) + unit guard by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4988
New Contributors
- @hcaldicott made their first contribution in https://github.com/LanternOps/breeze/pull/4720
- @obsidiangroup made their first contribution in https://github.com/LanternOps/breeze/pull/2826
Full Changelog: v0.109.0...v0.110.0