# Release notes 0.1.163

> 28 October 2026: An outside change and the scanner finding that followed it now meet on the finding.

_Release notes · Updated 2026-10-28 · Describes release 0.1.164_

## 0.1.163 — 28 October 2026 {#0-1-163-28-october-2026}

An outside change and the scanner finding that followed it now meet on the finding. Two Guardrails switches are on by default: an incident stays open while its fix waits for a person, and a change whose before-state cannot be captured does not run on the platform. The scanner pull clears the open findings Security Hub no longer reports or that fall outside the tag scope, and lands Inspector CVEs in a tag-scoped workspace; **Alerts** searches on the server; a built-in alert joins its resource's service. Built-in detection sees a crash loop between back-offs, the estate joins a controller load balancer and a vendor-API firewall to their services, and a release whose quorum lapsed waits for a vote again instead of failing. One additive column (`cloudfinding.failing_since`), one one-shot data fix (`migration:finding-family-v1`), one new setting (`AIOPS_REQUIRE_BEFORE_STATE`, the platform default of `aiops_require_before_state`), two new query parameters on `GET /api/aiops/{tenant_id}/alerts` (`q` and `service`) and four new audit actions (`incident.change_linked`, `change.finding_linked`, `compliance.finding_gone`, `compliance.scanner_out_of_scope`); no new route, permission or chart value. Read the [upgrade row](/help/ops-upgrade-and-verify.md) before upgrading: both default flips change what a workspace that never set them does.

### Behaviour changes in 0.1.163 {#behaviour-changes-in-0-1-163}

- **Two Guardrails switches are now on by default.** `aiops_hold_for_approval` (**Keep an incident open while its fix waits for a decision**) and `aiops_require_before_state` (**Refuse a change when its before-state cannot be captured**) were off and are now on for every workspace that never set them. A workspace that stored an explicit value keeps it: a box ticked or unticked on **Guardrails**, or `true` or `false` sent to `PATCH /guardrails`, wins over the platform default, and only `null` follows it. `switch_state` on `GET /guardrails` shows each switch's stored override and the platform default. On 0.1.162 the page showed an unset before-state switch and a stored `false` the same way (off), so a workspace that unticked it then keeps the rule off until it sends `null` or ticks the box.
- **An incident whose fix waits stays open.** With the hold on, the quiet-window close, and the close of a ticket resolved at its source, leave an escalated incident open while a change request for it was requested (drafted, pending approval, or approved but not run), or while the analysis's proposal matched a certified runbook; the plain proposal every escalated run drafts holds nothing. Each held incident is audited once (`incident.autoclose_held`). A held incident no longer uses up the quiet window's batch, so the closeable incidents behind it are still reached.
- **A step with no before-state reader is manual-only.** With the rule on, a direct write runs only after the platform has read and stored the resource's current state. A step the platform has no before-state read for — a typed step over a CLI connection, or a legacy direct route (`api`, `cli` or `mcp`) that declares no snapshot read — is offered on the manual route only: the review reads *Manual route only: step N (…) has no before-state the platform can capture*, lists the steps to run with your own access, and asks for the outcome to be recorded. An approved or scheduled change on such a step is refused when it fires. A read that fails at release stops before the write (*Nothing was written*, audit `change.prestate_blocked`), and the review then offers the manual route only until the write connection is tested again. Pull requests, backup steps and rollbacks are exempt, and every forward write of the built-in runbooks and step templates has its read. With the rule off, the 0.1.162 default, such a write ran with an honest *none* as its before-state.
- **Alerts searches on the server.** The **Alerts** search box (*Search alert, service or label*) used to search only the page already loaded; it now asks `GET /alerts`, which takes `q` (a case-insensitive part of any label value or key, or of the fingerprint) and `service` (the alert's `service` label, exact in any case). Both are prefilled from `?q=` and `?service=`, at most 200 characters each: the box stops at 200 and the API answers a longer one with `422`. `X-Total-Count` counts the matches.
- **The scanner register clears what Security Hub no longer reports — as no longer reported, not fixed.** When every region was read in full, an open Security Hub finding the hub answers in no region, last seen over 48 hours ago, clears as *no longer reported by the scanner* (audit `compliance.finding_gone`). That applies to the connection's own account and to an account the same pull returned a finding of; a finding of another account — one the webhook feeds, say — clears this way only once it was last seen over 90 days ago, Security Hub's own retention. While every pulling AWS connection has a tag scope, an open finding whose harvested resource carries none of their tags, and that no read re-sent for 48 hours, clears as out of scope (audit `compliance.scanner_out_of_scope`). Neither counts as fixed: the incident's Resources line counts them apart (*N no longer reported by the scanner (cleared, not fixed)*, *N out of scope (cleared, not fixed)*). Their incidents resolve, with the resolve notification and ticket write-back.
- **Inspector findings under a tag scope.** A tag-scoped connection's Inspector read used Security Hub's resource-tag filter, which an ECR image or Lambda finding never matches (it carries no resource tags), so no CVE of a tagged repository or function landed. The read is now filtered after it returns: the finding's own tags decide, else the harvested estate's tags on its resource. A CVE on a tagged ECR repository or Lambda function lands, and a P1 or P2 one may start an analysis (`aiops_auto_investigate_p1p2`); the rest is counted per region as `vulnerabilities_out_of_scope` (at most 5,000 read a region and pull).
- **A built-in alert carries its resource's service.** A built-in metric alert whose metric names no service takes the service its resource's tags name (a `service`, `app`, `application` or `Name` tag, as patch schedules read them), so an R04 alert on an EC2 instance tagged `service=web` joins web's other alerts instead of opening its own incident; its summary keeps the resource name. A resource with none of those tags keeps its name as the service.

### Scanner findings and the outside write {#scanner-findings-and-the-outside-write}

- **An outside write is named on the scanner finding it preceded.** Since the platform's own checks went off (0.1.147), a captured cloud write re-checked nothing on the platform side, and the compliance incident a scanner pull opened never named it. An unmanaged change on a finding's resource — captured by the platform's audit harvest, applied, and accounted for by no platform request, approval or execution receipt — in the 24 hours before the finding started failing, and after it last passed, is now listed under **Changes that triggered this check** on the finding's incident, with **Captured change named on this finding** on its timeline. The change gets a *re-checked by Security Hub · EC2.19 · failed* chip that links to the incident, and **Scanner finding failed after this change** on its timeline. Either side may land second: a write the audit log delivers after the finding is named at the next harvest. This is detection, not proof of cause, and nothing changes status. Only a control finding on a resource names a change (no CVE or threat finding, no subscription, resource group or account scope), a tag-only write only on a tagging control, and a finding the scanner saw failing more than 24 hours before the platform heard of it names none. `GET /findings` carries each row's `failing_since`; the harvest report and the manual pull's answer carry `findings_linked`.
- **Stored findings in their current family.** The one-shot `migration:finding-family-v1` classifies every stored finding again, so the DynamoDB.1, DynamoDB.6, ELB.6, Cognito.6 and RDS.8 rows that 0.1.148 moved out of *backup missing* leave the **Backup** list.
- **A connection's tag scope is checked at save.** A connection's `finding_tag_scope` without exactly one `key=value` pair is refused at save (`400`) instead of failing at the next pull.

### Change requests and approvals {#change-requests-and-approvals}

- **Upgrade warning.** A package, runtime, image or OS-patch upgrade (`aws.ssm.patch_baseline`, `aws.ssm.upgrade_packages`, `aws.lambda.update_runtime`, `aws.ecr.rebuild_image`) carries an **Upgrade warning** in its change request's 2.4 and under **Affected resources & blast radius**: what runs on the target, who calls it and the target version's known breaking changes, as the change management agent wrote them in its existing run, else exactly *unknown, not checked* (`upgrade_warning` on the change detail).
- **Approvals.** A release whose approval quorum lapsed before it ran (a scheduled release, the automatic lane) goes back to waiting for approval instead of being rejected, with each vote listed once and a vote given after a lapse kept. A person's release of an API route no longer writes to a resource only a merged-in alert names. A refused rollback attempt keeps its time, and a backup step no longer shows a *not captured* row after the change.

### Detection and the estate map {#detection-and-the-estate-map}

- **Crash loops between back-offs.** R31 **Pod crash loop** also fires for a container restarted 3 times or more that crashed again since the previous read: between back-offs the kubelet shows it terminated, and a single-replica crash loop went unalerted for 27 minutes. A container lost with its node, as on a reboot, is no crash loop. A workload in alarm whose pods are gone, in a namespace still read and in scope, now clears and can close on the quiet window.
- **A scoped workspace's denied attempts stay in its scope.** On a workspace with a tag scope, an AWS or Azure denied attempt opens a SecOps report only when it was made as one of the workspace's connections or targets an in-scope estate resource; the rest stay on the ledger, counted as `denied_out_of_scope` on the harvest report.
- **Load balancers and firewalls on the service path.** A load balancer the AWS Load Balancer Controller made is joined to the Ingress or Service it serves, so a service group climbs from the workload to it. A firewall read through its vendor's API is joined by address to the cloud instance that runs it, and the instance's firewall row on the service path lists the device's enabled policies (a policy the device no longer lists is left out).
- **Cloud health with no answer.** When the cloud-health triage step or built-in detection's AWS Health read gets no answer, it says what a private network needs: an interface endpoint for AWS Health and STS, or outbound HTTPS.

### Pages and smaller fixes {#pages-and-smaller-fixes}

- **Pages.** The **Alerts** label chips wrap, and an `ingest.batch` audit row reads in words (*received N · stored N · own ticket echoes skipped N*). Every Status and Source count on **Changes** is the total of the list it opens, whichever filter chip is pressed. List tables fit their card, breaking an id, ARN, region or port only after a separator (a long id or checksum with no separator may break anywhere), and a scanner re-check chip and a captured write's title wrap. **Thresholds and why** is its own reference page, with the rows it lacked.
- **Audit.** Model routing and residency audit rows carry the incident's correlation ID.


## Next steps

- Next: [Release notes 0.1.162](/help/release-notes-0-1-162.md)
- [All What's new pages](/help/what-s-new/llms.txt)
- [Documentation home](/help/)
