Skip to content

chore: sync upstream e364a7ee (64 commits) - #117

Merged
rhlsthrm merged 69 commits into
mainfrom
sync/upstream-2026-10-05
Oct 5, 2026
Merged

rhlsthrm merged 69 commits into
mainfrom
sync/upstream-2026-10-05

Conversation

@rhlsthrm

@rhlsthrm rhlsthrm commented Oct 5, 2026

Copy link
Copy Markdown
Collaborator

Syncs upstream ColeMurray/background-agents b8c9a80b..e364a7ee (64 commits) into the fork.

Conflict resolutions that change behavior

Fixtures and dependencies

  • Route catalog: 232 + (220 − 207) = 245 routes, 176 + (167 − 156) = 187 unique paths; snapshots regenerated, the 13 added admission rows are exactly the fork's routes.
  • @vitest/coverage-v8 returns to ^4.1.11 (it peers on the exact vitest version and vitest is held below 5); @vitest/coverage-istanbul from upstream added at the same version; dependabot now holds @vitest/coverage-* with vitest. Prettier follows upstream to 3.9.9.
  • package-lock.json is rebuilt from the fork's lock, with npm's dropped optional platform entries (workerd, nested esbuild) restored and vitest 4 hoisted for @testing-library/jest-dom. npm ci from a clean tree and an optional-dependency integrity check both pass.
  • Upstream tests deleted by test: reduce redundant suites while preserving coverage ColeMurray/background-agents#2230 that held fork-only cases are kept, trimmed to those cases.

Verification (local, sequential)

typecheck; control-plane unit and integration; web, github-bot, slack-bot, linear-bot, shared, mcp-server, docs; sandbox-runtime node + pytest; modal-infra and sandbox-images pytest; terraform test (production + modal-app); eslint; prettier on tracked files; SQL-portability, workflow-contract, d1-migrate and coverage-gate script tests. Knip is advisory in CI (--no-exit-code) and fails identically on pristine upstream.

ColeMurray and others added 30 commits October 2, 2026 11:36
…ay#2213)

## Summary

Supersedes ColeMurray#2191, taking over its original fix at `eec0f170` and
resolving conflicts against current `main` (`4664486`). Credits the
original author as a co-author.

PR ColeMurray#2191 authorized team-owned child creation using
`promptAuthor.canonicalUserId ?? parentSession.userId`. An unresolved
author could therefore borrow the parent owner's current team membership
and create a team-owned child using the parent sandbox token.

- Require the active prompt author's own canonical identity and current
membership in the parent's owning team before resolving the child
repository, acquiring an admission lease, or creating the child.
- Return `403 { error: "Not a team member", code: "not_member" }` for
unresolved or nonmember authors in every `TEAMS_ENFORCEMENT` mode.
- Preserve existing parent-owner fallback for workspace-owned child
ownership, including private sessions; it is not used for team
authorization.
- Preserve newer repository permission/grant checks, fresh SCM
repository-ID resolution, and inherited environment ownership checks
when resolving the original merge conflicts.
- Update successful team/environment test fixtures to use canonical
member authors while retaining coverage of inheritance without human
environment-use permission.

## Regression Coverage

- Real workerd/D1 integration tests reject removed and unresolved prompt
authors in `off`, `shadow`, and `on`, even when the parent owner remains
a team member and the repository grant is valid.
- Rejections leave no child or admission lease and do not reach SCM
repository resolution.
- Unit tests distinguish the request caller, parent owner, and active
author, cover absent/null canonical identities and membership in another
team, and permit a member author even when the parent owner is no longer
a member.
- Existing private/workspace ownership and credential-identity
regressions remain passing.

## Verification

Before correcting the original PR's fallback-based gate, the
unresolved-author integration regression failed in all three modes with
**expected 403, received 201**. With this fix, all targeted integration
suites pass.

- `npm run build -w @open-inspect/shared`
- `npm test -w @open-inspect/control-plane -- --maxWorkers=1 --silent
--reporter=dot`: **6,176 tests passed across 362 files**.
- `npm run test:integration -w @open-inspect/control-plane --
test/integration/spawn-children.test.ts
test/integration/session-environment-ownership.test.ts
test/integration/child-session-ops.test.ts
test/integration/session-access-routes.test.ts
test/integration/rbac-routes.test.ts --maxWorkers=1 --silent`: **126
tests passed across 5 files**.
- `npm run typecheck -w @open-inspect/control-plane`: passed, including
integration test types.
- `npm run build -w @open-inspect/control-plane`: Worker and Node builds
passed.
- ESLint and Prettier checks on all four changed files, `git diff
--check`, and commit hooks passed.

The full integration suite was not run locally. Membership lookup and
child persistence remain separate operations, as in existing session
creation; this change addresses missing or revoked membership before the
request, not concurrent revocation during an authorized request.

---
*Created with
[Open-Inspect](https://open-inspect-prod.vercel.app/session/cff7c2e448e88bb119050ab1c6b3c491)*

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Team-owned child sessions are now created only when the active prompt
author is a member of the parent’s team. Requests from authors who are
not members or cannot be identified are rejected with a 403 response
before a child session is created.
* When spawning is allowed, the child session reflects the active
author’s team membership and canonical user identity.
* For non-team child sessions, the parent’s user identity remains the
fallback when the prompt author has no canonical identity.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Cole Murray <2492022+ColeMurray@users.noreply.github.com>
Co-authored-by: Rahul Sethuram <rahul.eth@icloud.com>
Co-authored-by: waclaude <colemurray.cs+ghwaclaude@gmail.com>
## Summary

Supersedes ColeMurray#2190 by taking over its slug-rename fix on the current
`main` branch. The original PR branch is unchanged, and @rhlsthrm's
commit authorship is retained.

- Keep the displayed team resolved by its ID while the team list
revalidates after a slug rename, then replace the URL with the team's
current encoded slug.
- Resolve the `TeamPage` conflicts while preserving the shared
workspace-admin check, automation permission checks, and
repository/environment/automation tabs added on `main`.
- Update the regression test's authorization mock and complete
capability fixture for the current APIs.

## Verification

- `npm run build -w @open-inspect/shared`
- `npm test -w @open-inspect/web -- src/components/teams/
src/components/settings/teams-settings.test.tsx
src/components/settings/teams-settings-cache.test.tsx --maxWorkers=1`: 7
files, 109 tests passed.
- `npm run typecheck -w @open-inspect/web`
- `npm run lint -w @open-inspect/web`
- Prettier check on all three changed files and `git diff --check`
passed.
- Browser verification against the local Next.js app with mocked API
responses: renaming from Settings updates the route and keeps the team
available at desktop (1440x1000) and mobile (390x844) sizes. Mobile
Settings can be reopened with the saved slug, with no horizontal
overflow.

---
*Created with
[Open-Inspect](https://open-inspect-prod.vercel.app/session/c671ab008b98ba858c7f1896c0bee706)*

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* After a team is renamed, its page remains visible and the URL updates
to the team’s new slug, even if the directory is stale, refresh fails,
or the old slug is reused by another team.
* Archived teams are not treated as active matches when resolving a team
page. Navigating to a missing or archived team slug continues to show
“Team not found” without redirecting.
* Team lists now reflect successful team updates without waiting for a
refresh.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Rahul Sethuram <rahul.eth@icloud.com>
Co-authored-by: waclaude <colemurray.cs+ghwaclaude@gmail.com>
…leMurray#2202)

## Summary

Fixes COL-227.

- Commit the local archive status through `beginTransition()` before
invoking preservation. A local persistence failure throws synchronously
and skips the save; the existing async `transition()` API retains its
promise-rejection behavior.
- Start preservation before awaiting the D1 status projection. The
synchronous `archived` and `draining` writes remain in the same Durable
Object turn, so a bridge reconnect receives HTTP 503 while saving still
needs its sandbox.
- Keep archive eligibility checks and final index confirmation
unchanged. Missing/legacy shutdown records still receive HTTP 410. No
migrations or persisted fields are added.
- Cover the delayed projection and failed local write with integration
regressions. Restore the projection spy before awaiting rejection-safe
archive settlement, including when the gate is never reached.

## Verification

- The original reconnect regression failed with HTTP 410 before the
initial fix and passes with HTTP 503.
- The new SQLite-abort regression failed because a rejected archive
write still moved the sandbox to `draining`; it now leaves the shutdown
record and session status unchanged.
- `npm run test -w @open-inspect/control-plane -- --maxWorkers=1`
passed: 6,115 tests.
- `npm run test:integration -w @open-inspect/control-plane --
--maxWorkers=1 test/integration/sandbox-shutdown.test.ts
test/integration/session-lifecycle.test.ts
test/integration/session-batch-archive.test.ts
test/integration/websocket-sandbox.test.ts` passed: 75 tests.
- `npm run typecheck -w @open-inspect/control-plane` passed.
- Targeted ESLint, Prettier, and commit hooks passed.

---
*Created with
[Open-Inspect](https://open-inspect-prod.vercel.app/session/6d30e15bbef91458fcc84af0a844cc3f)*

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Session archiving now proceeds while sandbox preservation is underway,
while still confirming the archived status before completing.
* Sandbox reconnect attempts receive a temporary “Sandbox is being
saved” response while archiving is pending.
* Reconnect attempts for archived sessions with missing or legacy
shutdown records receive a “Session is terminal” response.
* If updating a session’s local status fails during archiving, sandbox
shutdown state remains unchanged.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Cole Murray <2492022+ColeMurray@users.noreply.github.com>
Co-authored-by: waclaude <colemurray.cs+ghwaclaude@gmail.com>
…lds (ColeMurray#2019)

`ImageBuildReaper.reconcileUnresolvedOperations` can clear the
provider-operation reference of a
capture that is still running.

## Mechanism

The `absent` branch settles on a `created_at`-anchored estimate:

```ts
if (outcome.type === "absent" && now - row.created_at <= DEFAULT_STALE_BUILD_MAX_AGE_MS) {
```

while the row carries the exact bound the comment directly above it
appeals to. The two are anchored
to **different clocks**:

- `DEFAULT_STALE_BUILD_MAX_AGE_MS` is 75 min measured from `created_at`
= `registerBuild`
(`src/image-builds/maintenance.ts:20-21`,
`src/image-builds/timeouts.ts:6-13`). Its own comment
(`maintenance.ts:14-18`) says the clock "starts at row registration, not
sandbox start, so dispatch
latency and provider queueing eat into the grace budget" — that budget
is
  `IMAGE_BUILD_STALE_DISPATCH_GRACE_MS`, 5 min.
- `provider_operation_deadline_at` is stamped at **reservation** time
against the source's remaining
lifetime (`src/image-builds/daytona-adapter.ts:209-223,333-339`), and is
documented as a "Fixed
wall-clock deadline (ms) for that operation; never extended by a retry"
(`src/db/image-build-finalization.ts:73-74`). The capture attempt itself
treats exhaustion as
  `now >= operation.deadlineAt` (`daytona-adapter.ts:305-313`).

A build dispatched later than the 5-minute registration grace allows
therefore holds a live deadline
that outlasts the estimate. The reaper could not even see it:
`UnresolvedProviderOperationRow` had no
such field and `UNRESOLVED_PROVIDER_OPERATIONS_SQL` did not select the
column
(`src/db/image-builds.ts:179-185,227-233`).

A row reaches that query while its deadline is still live via
`supersedeScopeBuilds`, which flips
`building` → `superseded` with no regard for a reserved operation
(`src/db/image-builds.ts:786-793`),
or via `markFailed`, which deliberately leaves the ref and deadline in
place — unlike `recordArtifact`
and `quarantineArtifact`, which NULL them
(`src/db/image-build-finalization.ts:399-414` vs
`:316-322,431-438`). Clearing the reference there drops the only handle
to a capture still running.

## Fix

Select the persisted deadline and retain the obligation while **either**
bound still holds. A row
that recorded no deadline (`?? 0`) is treated as already exhausted, so
the estimate alone decides
exactly as before — no behaviour change for rows predating the column.

## Verification

`npm test -w @open-inspect/control-plane --
src/image-builds/reaper.test.ts` → 19 passed.

The three new cases were falsified against the unfixed source: older
than the max age but within a
live deadline is **not** reaped (this one fails without the fix), an
expired deadline **is** reaped,
and a null deadline keeps today's behaviour.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **Bug Fixes**
- Prevented operations from being settled as absent before their
reserved capture deadline has elapsed.
- Operations without a recorded deadline continue to use the existing
stale-age handling.
- Improved reconciliation behavior and reporting for operations that may
still be running.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Cole Murray <colemurray.cs@gmail.com>
)

## Summary
- Add a **Session origins** card directly below the Analytics session
summary, showing ranked source counts and shares for Slack, GitHub,
Linear, user/app, agent sub-sessions, and automations.
- Select a source to see its attributed users, session counts, and
within-source shares; reset to all sources or change the existing
date/scope controls.
- Extend the existing dashboard snapshot with source-by-user counts in
its single database batch. Reuse date-window, source-scope, and
visibility predicates; private sessions remain excluded.
- Preserve canonical user identities, separate same-name users, and
include legacy-login and unknown-user buckets. Explain attribution
limitations in the UI and correct outdated summary/scope copy.
- Include responsive layouts, accessible source controls, a
keyboard-focusable user list, loading/empty/cached states, and selection
resets.

## Scope and Data Semantics
This measures **session creation origins**, not subsequent message
activity. Existing attribution can identify integration actors or
automation owners rather than a direct human creator. Historical source
defaults remain under User / app; no speculative backfill or schema
migration is introduced. The existing Human default scope is retained;
All includes agent and automation sessions.

## Verification
- Shared package build passed.
- Control-plane and web typechecks passed.
- Repository ESLint and SQL portability checks passed.
- Targeted web analytics tests: **38 passed**.
- Targeted control-plane analytics tests: **54 passed**.
- Real-D1 analytics integration tests: **16 passed**, including
source/user grouping, all scopes, exact date boundaries, legacy/unknown
attribution, and visibility.
- Browser-tested the real `/analytics` page with mocked auth/API
responses at **1440×1100** and **390×844**: source filtering, All
sources reset, date/scope resets, and all six source categories. No
browser errors. Backend correctness was checked separately with real D1.
- Reviewed changes and fixed keyboard scrolling and
stale-source-selection issues. `git diff --check` passed.

## Visual Evidence
Viewport screenshots uploaded to the Open-Inspect session (mocked data,
`http://localhost:3000/analytics`):
- Desktop, all sources, 1440×1100: artifact
`a10c57ac73c91449d85436c35bad1030`
- Mobile, Slack selected, 390×844: artifact
`f82481b838e0b10c8e664783129d2d62`

---
*Created with
[Open-Inspect](https://open-inspect-prod.vercel.app/session/6b804adda7bf204945bdb55de6c5cc80)*

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added a Session Origins card to analytics, showing session counts and
percentages by source and attributed user.
* Added source filtering, with the selection resetting when the date
range or scope changes and reverting to all sources if the selected
source is no longer available.
* Session origin data follows the selected date range and scope, and
includes unattributed sessions.
  * Expanded active-user attribution to include legacy logins.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Cole Murray <2492022+ColeMurray@users.noreply.github.com>
Co-authored-by: waclaude <colemurray.cs+ghwaclaude@gmail.com>
Closes [COL-208](https://linear.app/colemurray/issue/COL-208).

## Summary

- Add provider-keyed channel binding storage, capability-protected team
routes, Slack-only service lookup, and atomic `team.binding_added` /
`team.binding_removed` audit events.
- Validate bindings through the Slack bot's authenticated
`conversations.info` endpoint. Refuse channels the bot has not joined
and externally shared channels.
- Resolve the channel's team before classification, scope
repository/environment memory and KV caches, preserve scope through
clarification interactions, and send `teamId` with session creation.
- Preserve membership and repository-grant denial details. A forbidden
follow-up reports lack of access without closing the thread for other
users; unavailable sessions close rather than silently creating
replacements.
- Gate completion, tool progress, activity, automation completion, and
`slack-notify` posts against the authoritative session row and current
channel binding. Private and cross-team publication is refused,
including workspace-visible sessions.
- Add signed `channel` scope to completion reads. Queued publication
also sends signed `purpose=slack-post`, applying the stricter outbound
check at content/media reads without changing ordinary workspace-read
semantics. Failed protected reads never publish queued error text or
previously fetched content.
- Persist thread closure independently of mapping/checkpoint writes,
including early callbacks and automation threads without interactive
mappings.
- Enforce Slack automation/channel ownership at writes and candidate
selection, while preserving workspace-owned automations in unbound
channels.
- Add the team's Channels tab, global Slack `unboundChannels` setting,
and audit labels. The obsolete move warning and its provenance read
contract have been removed. Update the changelog and both sandbox tool
denial-guidance maps.

## Storage And Enforcement

D1 migration `0083` already contains the binding and ownership schema;
DO migration `56` is unchanged. No migrations, columns, or new
deployment secrets are added. Bot endpoint authentication reuses the
existing service callback signing credentials.

Ordinary session reads preserve `off` / `shadow` / `on`: non-private
team visibility is bypassed in `off`, audited in `shadow`, and enforced
in `on`. Every non-read action on a team-owned session now requires
current team membership in all modes, including for Owners and
Administrators. Private restrictions remain active in every mode.
Binding management and outbound publication checks enforce independently
of that flag. The D1 session row is authoritative; the thread's stored
`teamId` is only a cache.

## Checkpoint Report

### Commands And Results

Validation ran sequentially with one Vitest worker. The control-plane
and web suites below were rerun after rebasing onto `70b8ca4`.

| Command | Final result |
| --- | --- |
| `npm run build -w @open-inspect/shared` | Passed |
| `npm run typecheck` | All workspaces passed |
| `npm run lint:fix` | Passed |
| `npm run lint:sql-portability` | Clean; unchanged portability baseline
|
| `npm test -w @open-inspect/control-plane -- --maxWorkers=1 --silent` |
343 files, 5,774 tests passed |
| `npm run test:integration -w @open-inspect/control-plane --
--maxWorkers=1 --silent --reporter=dot` | 129 files, 1,704 tests passed;
1 existing skip |
| `npm test -w @open-inspect/web -- --maxWorkers=1 --silent` | 261
files, 2,607 tests passed |
| `npm test -w @open-inspect/slack-bot -- --maxWorkers=1 --silent` | 41
files, 593 tests passed |
| `npm test -w @open-inspect/shared -- --maxWorkers=1 --silent` | 65
files, 1,115 tests passed |
| `uv run --extra dev pytest tests/test_claude_tools.py
tests/test_tool_installation.py -q` in `packages/sandbox-runtime` | 40
tests passed |
| `uv run --extra dev ruff check
src/sandbox_runtime/harness/claude_tools.py` | Passed |
| `uv run --extra dev ruff format --check
src/sandbox_runtime/harness/claude_tools.py` | Passed |
| `git diff --name-only -z origin/main...HEAD \| xargs -0 npx prettier
--check --ignore-unknown` | Passed |
| `git diff origin/main...HEAD --check` | Passed |

Targeted integration runs verified binding refusals, service audience
restrictions, signed cross-team concealment before any runtime call,
outbound refusal for every posting path, automation ownership, and
originating-thread snapshot enrichment. Admission/catalog snapshots were
regenerated and verified after the rebase, retaining the merged Teams
follow-ups.

Initial red tests and validation failures were resolved, not ignored.
Selected verbatim diagnostics:

```text
Error: Cannot find module './channel-scope' imported from /workspace/background-agents/packages/control-plane/src/authorization/channel-scope.test.ts
Error: D1_TYPE_ERROR: Type 'undefined' not supported for value 'undefined'
AssertionError: expected 201 to be 409 // Object.is equality
AssertionError: expected 200 to be 404 // Object.is equality
AssertionError: expected [ 'workspace', 'matching', 'other' ] to deeply equal [ 'workspace' ]
TypeError: (intermediate value).hasCompatibleBindings is not a function
AssertionError: expected 'user-or-service' to be 'service' // Object.is equality
AssertionError: expected 1 to be less than 0
src/classifier/environments.test.ts(74,78): error TS2345: Argument of type 'string[]' is not assignable to parameter of type 'string'.
src/classifier/repos.test.ts(201,78): error TS2345: Argument of type 'string[]' is not assignable to parameter of type 'string'.
src/completion/delivery.test.ts(223,44): error TS2709: Cannot use namespace 'ExtractorModule' as a type.
AssertionError: expected [Function] to throw error including 'Missing events pagination cursor' but got 'Invalid events response'
shell tool terminated command after exceeding timeout 600000 ms.
```

The initial integration fixture omitted required `joinPolicy`; that
fixture was corrected before confirming the behavioral red cases. Other
fixes included adapting existing mocks and route counts, making lookup
authentication service-only, updating the status-order assertion for the
new async closure check, correctly modeling SWR reset revalidation, and
removing a redundant pagination check already enforced by the response
schema. The first full integration run exceeded the 10-minute shell
timeout; both subsequent full runs passed with a 30-minute budget,
taking about 12 minutes each.

### Verified Facts And Drift

Initial inspection was on `main` at `19e7993`; the branch was
subsequently rebased onto `70b8ca4`, preserving both Teams follow-ups.

- `slack-bot/src/events/message-handler.ts:326-330` and
`sessions/session-launcher.ts:194-203` still classified and launched
without ownership scope. `sessions/control-plane-client.ts:74-81`
discarded create denial details, and the follow-up path treated non-404
failures as transient. These are now scoped and denial-aware.
- `slack-bot/src/events/dispatcher.ts:27-65` routes ordinary
watched-channel messages through the separate actorless automation
trigger path, rather than the interactive handler. Existing ingress is
preserved; automation candidate selection now enforces channel
ownership.
- `control-plane/src/session/types.ts:36-67` shows that the callback
service's local DO row lacks ownership/visibility. Gates use injected D1
index/binding reads, not that local row or participant records.
- `slack-bot/src/target-clarification.ts:164-179` and
`interactions/target-selection.ts:181` reloaded unscoped catalogs.
Pending request scope now survives those paths, and
suggestions/selection recheck the live binding.
- Completion delivery uses a durable queue. A callback-time check alone
could become stale, and ordinary service reads intentionally allow
workspace-visible sessions. Publication-purpose reads close that gap
while preserving the access resolver's existing contract.
- `control-plane/src/session/snapshot-reader.ts:94-128` previously
exposed no originating Slack channel. That enrichment was initially
added for the move warning and has now been removed with ownership
moves.
- Existing callback signing uses `SERVICE_AUTH_SECRET_SLACK_BOT` and the
bot's `SERVICE_AUTH_SECRET`; no additional Slack signing-secret
configuration was needed.

### Deliberately Excluded

- No migration, per-channel auto-response policy, or later-phase
credential/token changes.
- Repository-grant and environment-ownership catalog filters are not
implemented here; they landed on main separately. This PR scopes Slack
catalog reads with a signed `channel=slack:<id>` coordinate, from which
the control plane derives the channel's current team.
- Slack posting and KV persistence are not an atomic exactly-once
protocol. Closure markers prevent stale mapping writes from reopening
threads, but existing distributed delivery/propagation races remain. A
scope change after the final successful authority read cannot recall an
already-in-flight Slack post.
- Browser verification used fixture data and mocked APIs, not a live
Slack workspace or production authentication.

## Follow-up Fixes

- **Team-owned Slack automations at create (`0940757ef`).** `POST
/automations` checked watched channels against workspace ownership
instead of the automation's owner team. A team automation watching its
own team's bound channel was refused with `channel_team_mismatch`. One
watching an unbound channel was accepted, although candidate selection
would never fire it. Creation now checks against the owner team, as
update and candidate selection already did. New integration tests cover
a bound channel (created, and selected as a candidate), an unbound
channel (409) and another team's channel (409). The first two fail with
the old check.
- **Steering fixtures (`4408da48c`).**
`scheduler-slack-team-steering.test.ts`, added on main with team-owned
automations, seeded team automations in an unbound channel. This PR's
candidate rule excludes that by design, which caused the 10 failures in
control-plane integration 1/2. The fixtures now give each team
automation the channel's team, and use an unbound channel for the
workspace case; no runtime code changed.
- **Closed threads reopen (`94253ebcb`).** A thread closed by a binding
change or a private session used to stay closed until its marker
expired, even after the binding or visibility was restored. Only threads
that saw activity during the change were affected. A reply in a closed
thread now re-checks the channel binding and the `slack-post`
publication read. When both allow it, the bot clears the closure
tombstone and notice marker and delivers the reply; otherwise the thread
stays closed. The control plane still enforces scope on every prompt and
post. Tests cover reopening, staying closed for another team's channel
or denied publication, and a closure that lands during a reopen.

| Command | Result |
| --- | --- |
| `npm run typecheck -w @open-inspect/control-plane` | Passed |
| `npx prettier --check` and `npx eslint` on the changed files | Passed
|
| `npm test -w @open-inspect/control-plane -- --maxWorkers=2 --silent` |
365 files, 6,240 tests passed |
| `npm run test:integration -w @open-inspect/control-plane` on the
automation, scheduler and Slack files (final head) | 16 files, 282 tests
passed |
| `npm run typecheck -w @open-inspect/slack-bot` | Passed |
| `npm test -w @open-inspect/slack-bot -- --silent` | 39 files, 621
tests passed |

## Visual Verification

Real changed components and repository styles were verified in local
component previews with fixture data. Binding/unbinding, primary/source
selection, saving the unbound policy, move-warning conditions, and
mobile fit were exercised. The corrected warning has 15.00:1 light-theme
text contrast.

All captures are viewport screenshots; URLs record local capture
provenance and the preview server has been stopped.

| Capture | Viewport | Source | Uploaded artifact ID |
| --- | --- | --- | --- |
| Channels desktop | 1440x1000 | `http://127.0.0.1:5173/channels` |
`3ad98e81fe8e054b0930b52c95d41def` |
| Channels mobile | 390x844 | `http://127.0.0.1:5173/channels` |
`dcaf42617faf4aacb67e7a1f30869901` |
| Slack settings desktop | 1440x1000 | `http://127.0.0.1:5173/slack` |
`bd25ac2aa2443b82650960885228491f` |
| Slack settings mobile | 390x844 | `http://127.0.0.1:5173/slack` |
`4ebfe6cc73b82a7b3223d04891ffbc06` |
| Historical move preview desktop (removed) | 1440x1000 |
`http://127.0.0.1:5173/move` | `f1f6e4c6888eaa6ccf0620d8c3d20da5` |
| Historical move preview mobile (removed) | 390x844 |
`http://127.0.0.1:5173/move` | `1edfda15f09e9773408c2435eab18419` |

---
*Created with
[Open-Inspect](https://open-inspect-prod.vercel.app/session/f9d5970ec4d60dc821b243d734ac1f4b)*

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Team administrators can manage Slack channel bindings from a Channels
tab, assign primary or source channels, and review binding changes in
the audit log.
* Slack settings let administrators choose whether unbound channels
create workspace-level sessions or reject requests.
* Slack routing and automations respect channel team ownership, with
clearer feedback when access or posting is denied.
* **Bug Fixes**
* Prevented notifications and completion content from being posted to
private sessions or channels bound to another team.
* Closed threads no longer trigger replacement sessions or receive later
updates.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Cole Murray <2492022+ColeMurray@users.noreply.github.com>
Co-authored-by: waclaude <colemurray.cs+ghwaclaude@gmail.com>
…ages/locks/python-tools in the uv group across 1 directory (ColeMurray#2231)

Bumps the uv group with 1 update in the
/packages/sandbox-images/locks/python-tools directory:
[urllib3](https://github.com/urllib3/urllib3).

Updates `urllib3` from 2.7.0 to 2.8.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/urllib3/urllib3/releases">urllib3's
releases</a>.</em></p>
<blockquote>
<h2>2.8.0</h2>
<h2>🚀 urllib3 is fundraising for HTTP/2 support</h2>
<p><a
href="https://sethmlarson.dev/urllib3-is-fundraising-for-http2-support">urllib3
is raising ~$40,000 USD</a> to release HTTP/2 support and ensure
long-term sustainable maintenance of the project. If your company or
organization uses Python and would benefit from HTTP/2 support in
Requests, pip, cloud SDKs, and thousands of other projects <a
href="https://opencollective.com/urllib3">please consider contributing
financially</a> to ensure HTTP/2 support is developed sustainably and
maintained for the long-haul.</p>
<p>Thank you for your support.</p>
<h2>Security</h2>
<p>Fixed the following security issues:</p>
<ul>
<li>The TLS configuration for HTTPS proxies could be ignored or
overridden. (High severity, GHSA-8988-9cw3-xx77)</li>
<li><code>HTTPResponse.stream()</code> and <code>read_chunked()</code>
could buffer a chunk-size line of unbounded length in memory. (High
severity, GHSA-vxq7-64xx-v4gw)</li>
<li>Chunked Deflate streaming could enter an infinite loop. (Medium
severity, GHSA-gh4c-6fx4-qh6g)</li>
</ul>
<blockquote>
<p>[!IMPORTANT]
urllib3 2.8.0 fixes HTTPS proxy TLS configuration being ignored or
overridden by destination settings. Configurations relying on that
behavior may require changes.</p>
<p>Configure proxy CA certificates and client certificates in
<code>proxy_ssl_context</code>, and proxy identity checks with
<code>proxy_assert_hostname</code> or
<code>proxy_assert_fingerprint</code>. Destination client certificates
and identity overrides no longer apply to HTTPS forwarding proxy
connections.</p>
</blockquote>
<blockquote>
<p>[!NOTE]
CVE IDs had not yet been assigned to these advisories at the time of
release due to a backlog at GitHub's CNA.</p>
</blockquote>
<h2>Deprecations &amp; Removals</h2>
<ul>
<li>Deprecated using an empty collection as the <code>Retry</code>
option <code>allowed_methods</code> to retry any verb. (<a
href="https://redirect.github.com/urllib3/urllib3/issues/5044">#5044</a>)</li>
</ul>
<h2>Features</h2>
<ul>
<li>Added <code>Url.auth_decoded</code> and
<code>Url.auth_decoded_joined</code> convenience properties to the
result of <code>parse_url()</code>. (<a
href="https://redirect.github.com/urllib3/urllib3/issues/4945">#4945</a>)</li>
<li>Added <code>basic_auth_encoding</code> and
<code>proxy_basic_auth_encoding</code> parameters to
<code>urllib3.util.make_headers()</code>. (<a
href="https://redirect.github.com/urllib3/urllib3/issues/5092">#5092</a>)</li>
</ul>
<h2>Bugfixes</h2>
<ul>
<li>
<p>Fixed response header handling to replace obsolete folded header
lines (<code>obs-fold</code>) with spaces in accordance with RFC 9112,
preventing raw CRLF sequences from appearing in header values such as
<code>Set-Cookie</code>. (<a
href="https://redirect.github.com/urllib3/urllib3/issues/1362">#1362</a>)</p>
</li>
<li>
<p>Fixed usage of <code>proxy_ssl_context</code> with
<code>ProxyManager</code> when
<code>use_forwarding_for_https=True</code>. Passing
<code>ssl_context</code> instead of <code>proxy_ssl_context</code> for
HTTPS proxies in this configuration now emits a
<code>FutureWarning</code> and will raise an error in v3.0. (<a
href="https://redirect.github.com/urllib3/urllib3/issues/2577">#2577</a>)</p>
</li>
<li>
<p>Changed behavior of the default <code>ConnectionPool.pool</code>
initialization. <code>LifoQueue</code> is now resolved from the
<code>queue</code> module after the <code>ConnectionPool</code> is
instantiated instead of using the default cached <code>QueueCls</code>
class property. This is done because sometimes the
<code>queue.LifoQueue</code> is monkey-patched late in the program, such
as by gevent. (<a
href="https://redirect.github.com/urllib3/urllib3/issues/3289">#3289</a>)</p>
</li>
<li>
<p>Raised <code>UnrewindableBodyError</code> instead of
<code>ValueError</code> when retrying a request whose body had
<code>tell()</code> but not <code>seek()</code>. (<a
href="https://redirect.github.com/urllib3/urllib3/issues/3779">#3779</a>)</p>
</li>
<li>
<p>Decoded percent-encoded SOCKS proxy credentials before authenticating
with the proxy server. (<a
href="https://redirect.github.com/urllib3/urllib3/issues/3785">#3785</a>)</p>
</li>
<li>
<p>Fixed <code>HTTPResponse.drain_conn()</code> to discard unread
response data in 64 KiB chunks (same as the default <code>amt</code>
when doing <code>HTTPResponse.stream(...)</code>). (<a
href="https://redirect.github.com/urllib3/urllib3/issues/5019">#5019</a>)</p>
</li>
<li>
<p>Fixed <code>is_ipaddress()</code> to detect non-standard IPv4 forms
accepted by <code>socket.connect</code>, such as hex
(<code>0x7f000001</code>), octal (<code>0177.0.0.1</code>), and decimal
integers (<code>2130706433</code>), ensuring SSL certificate
verification uses the correct mode for these addresses. (<a
href="https://redirect.github.com/urllib3/urllib3/issues/5029">#5029</a>)</p>
</li>
<li>
<p>Fixed <code>HTTPConnectionPool.urlopen</code> raising a misleading
<code>FullPoolError</code> instead of <code>ValueError</code> when
called with an invalid <code>timeout</code> argument on a pool created
with <code>block=True</code>. (<a
href="https://redirect.github.com/urllib3/urllib3/issues/5059">#5059</a>)</p>
</li>
<li>
<p>Fixed port-zero handling to preserve explicit <code>:0</code> values
instead of substituting the default ports 80 or 443 in URL parsing, pool
selection, proxy configuration, <code>connection_from_url()</code>, and
HTTP/2 request authority. (<a
href="https://redirect.github.com/urllib3/urllib3/issues/5071">#5071</a>,
<a
href="https://redirect.github.com/urllib3/urllib3/issues/5101">#5101</a>)</p>
</li>
<li>
<p>Fixed a bug where <code>PoolManager</code> passed the
<code>assert_hostname</code> and <code>assert_fingerprint</code>
parameters to HTTP connection pools. (<a
href="https://redirect.github.com/urllib3/urllib3/issues/5077">#5077</a>)</p>
</li>
<li>
<p>Fixed <code>HTTPConnectionPool.urlopen()</code> and HTTP proxy
forwarding to strip URL fragments from absolute request targets before
sending requests. (<a
href="https://redirect.github.com/urllib3/urllib3/issues/5079">#5079</a>)</p>
</li>
<li>
<p>Added safeguards to the proxy tunneling code to prevent potential
security issues when handling invalid characters in the proxy host and
HTTP headers. This change affects users of Python 3.10, Python 3.11, and
Python 3.12 when the standard library does not contain the fix; those on
newer Python versions should upgrade to 3.13.14+ or 3.14.5+ to get the
same security fixes. (<a
href="https://redirect.github.com/urllib3/urllib3/issues/5091">#5091</a>)</p>
</li>
<li>
<p>Fixed <code>HTTPSConnection.connect()</code> overriding
<code>ProxyConfig.ssl_context</code>'s certificate policy and proxy
identity checks with the target connection's TLS settings when
forwarding through an HTTPS proxy.</p>
<p><code>HTTPSConnection</code> no longer applies target SNI,
assertions, or client credentials to forwarding proxy handshakes and
continues to use its <code>ssl_context</code> as a fallback when an
HTTPS proxy forwards an HTTP target. (<a
href="https://redirect.github.com/urllib3/urllib3/issues/5093">#5093</a>)</p>
</li>
<li>
<p>Fixed URL parsing to more strictly enforce RFC 3986 host syntax,
rejecting invalid host input such as raw spaces and control characters,
malformed percent-encodings, and percent-encoded control characters in
HTTP(S) hosts and IPv6 zone identifiers, including proxy CONNECT tunnel
targets. Host normalization now also follows RFC 3986 normalization
rules for percent-encoded octets by decoding percent-encoded unreserved
characters and uppercasing the hexadecimal digits of retained
percent-encoded octets. (<a
href="https://redirect.github.com/urllib3/urllib3/issues/5095">#5095</a>)</p>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/urllib3/urllib3/blob/main/CHANGES.rst">urllib3's
changelog</a>.</em></p>
<blockquote>
<h1>2.8.0 (2026-09-15)</h1>
<h2>Security</h2>
<p>Fixed the following security issues:</p>
<ul>
<li>The TLS configuration for HTTPS proxies could be ignored or
overridden.
(High severity, <code>GHSA-8988-9cw3-xx77
&lt;https://github.com/urllib3/urllib3/security/advisories/GHSA-8988-9cw3-xx77&gt;</code>__)</li>
<li><code>HTTPResponse.stream()</code> and <code>read_chunked()</code>
could buffer a chunk-size
line of unbounded length in memory. (High severity,
<code>GHSA-vxq7-64xx-v4gw
&lt;https://github.com/urllib3/urllib3/security/advisories/GHSA-vxq7-64xx-v4gw&gt;</code>__)</li>
<li>Chunked Deflate streaming could enter an infinite loop. (Medium
severity,
<code>GHSA-gh4c-6fx4-qh6g
&lt;https://github.com/urllib3/urllib3/security/advisories/GHSA-gh4c-6fx4-qh6g&gt;</code>__)</li>
</ul>
<p>.. caution::</p>
<pre><code>urllib3 2.8.0 fixes HTTPS proxy TLS configuration being
ignored or
overridden by destination settings. Configurations relying on that
behavior may require changes.
<p>Configure proxy CA certificates and client certificates in
<code>proxy_ssl_context</code>, and proxy identity checks with
<code>proxy_assert_hostname</code> or
<code>proxy_assert_fingerprint</code>.
Destination client certificates and identity overrides no longer
apply to HTTPS forwarding proxy connections.
</code></pre></p>
<h2>Deprecations &amp; Removals</h2>
<ul>
<li>Deprecated using an empty collection as the <code>Retry</code>
option
<code>allowed_methods</code> to retry any verb.
(<code>[#5044](urllib3/urllib3#5044)
&lt;https://github.com/urllib3/urllib3/issues/5044&gt;</code>__)</li>
</ul>
<h2>Features</h2>
<ul>
<li>Added <code>Url.auth_decoded</code> and
<code>Url.auth_decoded_joined</code> convenience
properties to the result of <code>parse_url()</code>.
(<code>[#4945](urllib3/urllib3#4945)
&lt;https://github.com/urllib3/urllib3/issues/4945&gt;</code>__)</li>
<li>Added <code>basic_auth_encoding</code> and
<code>proxy_basic_auth_encoding</code> parameters to
<code>urllib3.util.make_headers()</code>.
(<code>[#5092](urllib3/urllib3#5092)
&lt;https://github.com/urllib3/urllib3/issues/5092&gt;</code>__)</li>
</ul>
<h2>Bugfixes</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/urllib3/urllib3/commit/b1d30ab61fe0db8f11092805e8c5ac43e091064a"><code>b1d30ab</code></a>
Release 2.8.0</li>
<li><a
href="https://github.com/urllib3/urllib3/commit/9016d7e8afc68185496ef07f3c3a4a743d04922e"><code>9016d7e</code></a>
Skip <code>test_read_chunked_with_trailing_data_does_not_hang</code> for
brotlicffi (<a
href="https://redirect.github.com/urllib3/urllib3/issues/5258">#5258</a>)</li>
<li><a
href="https://github.com/urllib3/urllib3/commit/9101f581a8b3659af23b6ff335ae77200ca33533"><code>9101f58</code></a>
Fix <code>nox -s docs</code> warning (<a
href="https://redirect.github.com/urllib3/urllib3/issues/5256">#5256</a>)</li>
<li><a
href="https://github.com/urllib3/urllib3/commit/cd770b059b543be29298ea5c52afb0b1b090f5ed"><code>cd770b0</code></a>
Merge commit from fork</li>
<li><a
href="https://github.com/urllib3/urllib3/commit/ea2ad7b21a80da3632f80016526a18864586077f"><code>ea2ad7b</code></a>
Merge commit from fork</li>
<li><a
href="https://github.com/urllib3/urllib3/commit/0716e31534345dc1599ea95d903c79f276239bd8"><code>0716e31</code></a>
Fix loading unencrypted client keys with a password in pyOpenSSL (<a
href="https://redirect.github.com/urllib3/urllib3/issues/5255">#5255</a>)</li>
<li><a
href="https://github.com/urllib3/urllib3/commit/43c68c8b43a9dcb44ed2cf4ec91384ca0d46b37d"><code>43c68c8</code></a>
Test pickling of <code>InvalidChunkLength</code> (<a
href="https://redirect.github.com/urllib3/urllib3/issues/5247">#5247</a>)</li>
<li><a
href="https://github.com/urllib3/urllib3/commit/308b279b3fb28e7bee952e152ec5baeb5bfd0817"><code>308b279</code></a>
Share security policy between GitHub and Read the Docs (<a
href="https://redirect.github.com/urllib3/urllib3/issues/5253">#5253</a>)</li>
<li><a
href="https://github.com/urllib3/urllib3/commit/53fa0731b27d4b71ab0755ea5b896422d005d706"><code>53fa073</code></a>
Add policy on duplicate pull requests (<a
href="https://redirect.github.com/urllib3/urllib3/issues/5252">#5252</a>)</li>
<li><a
href="https://github.com/urllib3/urllib3/commit/5f2a6a843d0100d1351c3f94d58581ca98d17267"><code>5f2a6a8</code></a>
Assert on the ALPN extension in test_tunnel_sets_http_11_alpn (<a
href="https://redirect.github.com/urllib3/urllib3/issues/5232">#5232</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/urllib3/urllib3/compare/2.7.0...2.8.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=urllib3&package-manager=uv&previous-version=2.7.0&new-version=2.8.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/ColeMurray/background-agents/network/alerts).

</details>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Cole Murray <2492022+ColeMurray@users.noreply.github.com>
…urray#2232)

## Summary
Removes the Save button from the session visibility control. Each
control now saves on its own:

- **Visibility dropdown** — choosing a different visibility saves right
away. If child sessions are included and the new visibility isn't
private, the existing confirmation dialog appears first. Cancelling
leaves the visibility unchanged.
- **Include child sessions checkbox**
- **Checking it** applies the session's current visibility to its child
sessions (the server already supports a same-visibility cascade). This
also asks for confirmation when the visibility isn't private.
- **Unchecking it** saves nothing, because there's no persisted setting
to revert. It only means later visibility changes affect this session
alone.
- An "Updating..." label replaces the button label while a save is in
flight, and all controls are disabled until it finishes.
- If a save fails, the dropdown goes back to the previous visibility,
unless "Retry without child sessions" is offered; then it keeps the
failed choice so the retry can use it.
- The team owner-membership warning also shows while the confirmation
dialog is open for a change to team visibility.

## Testing
- `vitest run src/components/session-controls.test.tsx` (27 passed),
rewritten for autosave behavior
- `tsc --noEmit`, eslint, prettier

---
*Created with
[Open-Inspect](https://open-inspect-prod.vercel.app/session/ad4b14f9cdc0e17614c06cdb8b2e82af)*

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Session Visibility**
* Visibility changes save immediately when selected; a separate Save
action is no longer needed.
  * Applying visibility changes to child sessions requires confirmation.
* Controls are unavailable during refreshes, when permission to change
visibility is unavailable, or when the required owner is missing.
* After a retryable failure, retry the selected visibility change
without applying it to child sessions. Other failed changes revert to
their previous settings.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Cole Murray <2492022+ColeMurray@users.noreply.github.com>
Co-authored-by: waclaude <colemurray.cs+ghwaclaude@gmail.com>
)

## Summary

Remove **3,414 test cases and 278 complete test files** across eight
packages, reducing the measured suites from **14,587 to 11,173 cases
(23.4%)**. The reduction primarily targets mocked SQL, handler
delegation, orchestration, helper tests, and repeated parameter
combinations.

Every measured coverage metric remains within **three percentage points
of its baseline, per package**. The largest observed decrease is **2.38
percentage points**, and all coverage denominators are unchanged between
the before/after measurements.

| Package | Tests Removed | Largest Coverage Drop |
| --- | ---: | ---: |
| Control Plane | 2,075 | 2.36 pp |
| Web | 827 | 2.38 pp |
| Shared | 190 | 2.25 pp |
| Slack Bot | 115 | 2.27 pp |
| Linear Bot | 39 | 1.85 pp |
| GitHub Bot | 12 | 0.57 pp |
| Sandbox Runtime | 126 | 0.90 pp |
| Modal Infrastructure | 30 | 0.00 pp |

## Retained Coverage

- Keep all **140 control-plane workerd integration files**, using real
D1 and Durable Object storage.
- Keep all Node-host and storage conformance suites, and web
component/hook integration suites.
- Keep core authentication, signature, cookie identity, migration,
architecture, and type contracts.
- Retain focused manager signature, spawn-admission, and
late-provider-result race regressions.
- Preserve real local-process, Git, shell, socket, and tool tests in the
sandbox runtime.

## Coverage Tooling

- Run control-plane Node and workerd coverage together using Istanbul;
V8 coverage cannot run inside workerd.
- Add shared-package coverage commands and Python `pytest-cov`
dependencies.
- Add JSON summaries and TypeScript coverage floors based on baseline
minus three percentage points.
- Document full before/after metrics, methodology, tradeoffs, and
reproduction commands in `docs/TEST_REDUCTION.md`.
- Ignore generated Python coverage data. No production application code
changes.

The existing CI test commands are unchanged and do not automatically
enable the new coverage floors. Python coverage is measured but has no
new automatic threshold.

## Validation

- Affected suites: **11,169 passed, four unchanged skips**.
- Combined control-plane unit/integration coverage passes; the ordinary
Node test command also passes all 4,057 remaining cases.
- All affected TypeScript and Python coverage suites pass, including
standalone sandbox-runtime environment verification.
- Docs tests and native Node runtime tests pass.
- Repository ESLint, TypeScript typechecks, and Prettier checks pass.
- Python Ruff lint/format checks and `git diff --check` pass.
- Commit hooks pass without being skipped.

## Tradeoffs

Coverage overlap is not assertion equivalence. Some isolated input
permutations, error wording, provider error-classification matrices, and
interleavings no longer have dedicated assertions. Retained integration
tests cover their broader behavior; this PR does not claim to preserve
every old assertion or provide a mathematically optimal minimum test
set.

The coverage comparison is against the session baseline at `d343cac`;
full metrics are recorded in the documentation.

---
*Created with
[Open-Inspect](https://open-inspect-prod.vercel.app/session/f244b739ed5b9f7f15ce35fc004131d3)*

---------

Co-authored-by: Cole Murray <2492022+ColeMurray@users.noreply.github.com>
Co-authored-by: waclaude <colemurray.cs+ghwaclaude@gmail.com>
## Summary
When an artifact (screenshot/video) is expanded in the media lightbox,
you can now press **←/→** to move to the previous/next artifact without
closing and reopening.

## Design
- `MediaLightbox` now owns navigation: it takes the ordered `artifacts`
list, `selectedArtifactId`, and `onSelectArtifact(id | null)` (null
closes) instead of a single `artifact` + `open`/`onOpenChange`. The
session page passes `mediaArtifacts`, which uses the same filter/order
as the sidebar Artifacts section, so left/right matches the visual
order.
- Arrow keys are handled by a `window` keydown listener while the
lightbox is open, so navigation keeps working even if focus lands on a
disabled button at either end.
- Navigation stops at the first/last artifact (no wrap-around).
- Arrow keys are left alone when focus is in a `<video>` (native
seeking) or a text field, and modified arrows (Alt/Ctrl/Meta/Shift) are
ignored.
- For discoverability and pointer/touch users, prev/next buttons and an
"N of M" counter (`aria-live="polite"`) appear when there is more than
one artifact.
- Adds `ChevronLeftIcon` to the shared icons.

## Testing
- `npx vitest run src/components/screenshot-media.test.tsx
src/app/(app)/(sidebar)/session/[id]/page.test.tsx`: 15 tests pass,
including new tests for arrow-key navigation, end-of-list behavior, the
buttons, and the video-focus/modifier cases.
- Web package `tsc --noEmit` and ESLint pass.

---
*Created with
[Open-Inspect](https://open-inspect-prod.vercel.app/session/7ff662ef5d768fbc1e4ca9cd646548a1)*

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Navigate between session media artifacts using previous and next
buttons or the left and right arrow keys. A position indicator appears
when multiple artifacts are available.
* Arrow-key navigation respects editable fields, video controls, and
modified key presses.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Cole Murray <2492022+ColeMurray@users.noreply.github.com>
Co-authored-by: waclaude <colemurray.cs+ghwaclaude@gmail.com>
…eMurray#2225)

## Summary

- Add a signed, actorless `github-bot` routing lookup using numeric
repository identity: linked PR session team, sender's granted active
team memberships, then workspace ownership. Multiple eligible
memberships use the sender's most recently created session in that
repository.
- Match GitHub event automations by repository ID and
repository/installation grants. Each matching automation executes with
its own executor and team. Revoked grants produce a deduplicated,
terminal `unauthorized` run with `repo_not_granted`, without creating a
session or sandbox.
- Carry repository IDs through webhook validation and normalization. Use
current webhook display names for renamed repositories and refuse a
different numeric identity returned during launch resolution.
- Resolve routing after existing bot allowlist checks, send explicit
`teamId` on creation, preserve membership/grant rechecks, and post
explanatory refusal comments. Failed refusal posts use the existing
delivery retry path.
- Keep legacy auto-review workspace-owned, mark both settings
deprecated, and link the existing **Review new PRs** automation
template. Render grant-denied automation history distinctly.

Closes https://linear.app/colemurray/issue/COL-209

## Checkpoint Report

### Validation

Heavy validation ran sequentially with one Vitest worker. The branch was
created from `main` at `756d0dc` and rebased onto `b8c9a80` before the
final control-plane validation.

| Command | Result |
| --- | --- |
| `npm run build -w @open-inspect/shared` | Passed |
| `npm run typecheck` | Passed across all workspaces; repeated after
rebase |
| `npm run lint:fix` | Passed; repeated after rebase |
| `npm run lint:sql-portability` | Passed; repeated after rebase |
| `npm test -w @open-inspect/control-plane -- --maxWorkers=1` | 6,180
passed after rebase |
| `npm run test:integration -w @open-inspect/control-plane --
--maxWorkers=1` | 1,948 passed, 1 skipped after rebase; 671.81 seconds |
| `npm test -w @open-inspect/web -- --maxWorkers=1` | 2,785 passed |
| `npm test -w @open-inspect/github-bot -- --maxWorkers=1` | 249 passed
|
| `npm test -w @open-inspect/shared -- --maxWorkers=1` | 1,138 passed |
| Focused final run-history tests | 11 passed |
| Scoped Prettier check and `git diff --check` | Passed |

Visual verification used the actual `/settings/integrations/github`
application route with mocked browser API fixtures, at desktop
`1512x982` and mobile `390x844`. Both deprecation notices fit the
existing layout. Clicking the template pointer opened
`/automations/new?template=review-new-prs` with the expected name,
instructions, and PR-opened trigger. This verifies rendering and
navigation, not real OAuth or persistence.

### Red Tests And Tool Failures

Before implementation, the new pure status test had 1 failure and 1
pass. The new automation-routing integration tests had 6 failures and 3
passes. A subsequent late-revocation regression test also failed before
its fix. Representative failure messages, verbatim:

```text
AssertionError: expected 'completed' to be 'unauthorized' // Object.is equality
AssertionError: expected { triggered: +0, skipped: +0, …(1) } to deeply equal { triggered: 3, skipped: 1, …(1) }
AssertionError: expected [] to deeply equal [ ObjectContaining{…} ]
```

These cases are green in the final suites, including real D1 and
SessionDO coverage for fanout, executor/team ownership, numeric-ID
rename routing, revocation at candidate selection and guarded admission,
and sessionless denied history.

The first full integration attempt used a ten-minute shell timeout and
did not complete:

```text
shell tool terminated command after exceeding timeout 600000 ms. If this command is expected to take longer and is not waiting for interactive input, retry with a larger timeout value in milliseconds.
```

It passed when rerun with a 1,800,000 ms shell timeout, and passed again
after rebase.

An initial broad Prettier file list included generated Vitest snapshots,
which Prettier cannot parse:

```text
[error] No parser could be inferred for file "/workspace/background-agents/packages/control-plane/test/integration/__snapshots__/hono-route-catalog-conformance.test.ts.snap".
[error] No parser could be inferred for file "/workspace/background-agents/packages/control-plane/test/integration/__snapshots__/route-admission-matrix.test.ts.snap".
```

The corrected check targeted changed TypeScript/TSX/Markdown files and
passed; snapshot correctness is covered by integration tests.

### Verified Facts And Contract Changes

- Team-owned environments and automations are merged. Candidate lookup
has moved to `scheduler.ts:1114-1122` and
`automation-store.ts:1535-1551` on the inspected base; the old query
still matched owner/name without grants. GitHub now has an
ID/grant-aware query; Linear retains its existing path. Route inventory
becomes 208 routes and 157 paths.
- Numeric IDs existed in `automation_repositories.repo_id` and
`team_repository_grants.repo_external_id`, but both shared webhook
validation and normalized GitHub event contracts omitted them. Those
contracts and all supported GitHub normalizers now preserve the numeric
ID.
- The merged firing pipeline returned internal `unauthorized` results
but persisted no denied event run. Its existing grant reason was
`target_team_missing_grant`, and the public status unions did not
include `unauthorized`. This PR implements the requested literal
terminal run status, adds atomic denial persistence, and updates
SQL/TypeScript derived invocation status and UI rendering. Other firing
sources retain their existing denial behavior.
- D1 `sessions` has no scalar `repo_id` column. Sender-session
tie-breaking uses numeric IDs from `session_repositories`, including
secondary repositories, with no display-name fallback.
- Actorless environment reads cannot read team-owned environments.
Routed-team bot lookups therefore use the existing sender-actor
authorization path; incompatible environment ownership falls back to the
trigger repository.
- This uses existing D1 migration `0083`; there are no D1 or DO
migrations, new tables, or columns. Enforcement defaults are unchanged.
Routing/grant and creation membership checks apply in every mode;
existing session `off`, `shadow`, and `on` behavior is untouched.

### Deliberately Left Out

- Autofix routing, Linear bindings, and Slack routing are unchanged.
- Auto-review removal is not included. The existing automation template
is reused rather than introducing a replacement template here.
- `requireTeamOnCreate` is not bypassed: workspace fallback and legacy
auto-review remain subject to the existing creation policy.
- Legacy GitHub automation selections without resolved IDs do not fall
back to names. The changelog explains reselection and saving to resolve
IDs, and the required coordinated bot/control-plane upgrade.
- No numeric-ID index migration was added. The existing automation
selection schema lacks that index; schema/index changes remain outside
this PR.

---
*Created with
[Open-Inspect](https://open-inspect-prod.vercel.app/session/93c11db4019aaaaabe6bc03e48e955b9)*

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* GitHub events route to teams based on repository access and pull
request context, with workspace routing as a fallback.
* Automation history shows repository-access denials as “Unauthorized,”
with an explanatory message and no session link.
* The “Review new PRs” template can require team ownership when opened
from GitHub auto-review settings.
* **Bug Fixes**
* GitHub automation matching uses repository IDs, so repository renames
don’t misdirect events. Events without a valid repository ID are
rejected.
* Grant changes during event processing are retried, and failed event
forwarding can be retried without repeating completed processing.
* **Documentation**
* GitHub auto-review settings are marked deprecated and link to the
template. Existing auto-review continues to create workspace-owned
sessions.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Cole Murray <2492022+ColeMurray@users.noreply.github.com>
Co-authored-by: waclaude <colemurray.cs+ghwaclaude@gmail.com>
…ay#2219)

## Problem

Found in review. A mounted automation list keeps showing previously
loaded automations after the list refetch is denied. Example: a user is
viewing a team's automations, leaves the team (or loses access to it),
and the next revalidation of `/api/automations?teamId=…` returns 403.
`useAutomations` reports the 403 as `error`, but `automations` still
contains the team's automation names, so the list and its row actions
stay on screen.

The detail and invocation hooks in the same file already hide cached
data on 401/403/404 via `isTerminalAutomationError`; the list hook only
applied that guard to its own `retained` copy.

## Cause

`packages/web/src/hooks/use-automations.ts:71-75`:

```ts
const pages =
  data ??
  (retained && retained.key === listKey && !isTerminalAutomationError(error) ? retained.pages : undefined);
```

SWR keeps `data` when a revalidation throws, so after a terminal refetch
failure `data` is still the last successful pages and wins the `??`
before the terminal-error check is reached.

## Fix

Check `isTerminalAutomationError(error)` before either cached source.
Transient failures (network, 5xx, contract errors) still keep the last
loaded pages, as the existing comment describes.

## Verified

- New test `after a %i refetch shows %j for a loaded list` (403 / 404 /
500) in `use-automations.test.tsx`: the 403 and 404 cases fail on `main`
(`expected [ { id: 'auto-2', … } ] to deeply equal []`, with `error`
already set to the 403); all pass with the fix. The 500 case pins that
transient failures still keep the list.
- `npm run typecheck` exits 0.
- `packages/web` vitest: 270 files / 2778 tests pass.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Automation lists no longer display previously loaded results after an
authentication or access error (401 or 403) or when the requested
resource is not found (404).
* Previously loaded automations remain visible if a temporary server
error occurs (500), so the list isn’t unnecessarily cleared.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
…leMurray#2221)

## Problem

When editing, the environment form always submits the current repository
list, even when it is unchanged. The update route treats a present
`repositories` field as a replacement and always re-resolves and
re-authorizes it. Edits the API accepts with the field omitted are
therefore rejected from the UI:

- **Revoked team grant.** A team environment's grant for one of its
repositories is revoked. Disabling prebuilds is how ColeMurray#2205 says to handle
this ("disabling prebuilds on an environment with revoked grants still
works"). From the form it returns `409 target_team_missing_grant`, and
so does renaming or re-describing an environment whose prebuilds are
already off. `PUT /environments/:id` with `{ "prebuildEnabled": false }`
(or a name/description change while prebuilds stay off) succeeds.
- **No `repositories.use`.** A team lead who manages the environment but
lacks `repositories.use` gets `403 permission_required` on every save
from the form. The route lets that user edit metadata while leaving
repositories alone (`allows granted unchanged members without
repositories.use or replacing them` in
`environments-target-denied.test.ts`).

## Cause

`packages/web/src/components/settings/environment-form.tsx:129-143`
builds `repositories` from the current selection on every submit. In
`packages/control-plane/src/routes/environments.ts:328-344`, a present
`repositories` field goes through `resolveAuthorizedRepositories` (the
`repositories.use` preflight plus the team grant check) whatever the
prebuild state. An omitted field only re-checks stored repositories when
prebuilds stay enabled on a team environment.

## Fix

In edit mode, the form leaves out `repositories` when the selection is
unchanged: same repositories, same order (the order sets the primary
repository) and same base branches. Names compare as lowercase full
names, matching the selection keys. Create submissions and changed
selections are unaffected. `EnvironmentFormValues.repositories` becomes
optional to match `updateEnvironmentInputSchema`.

## Verified

- New `environment-form.test.tsx` case: renaming a team environment
without touching its repositories submits `{ name, description,
prebuildEnabled }` with no `repositories`. The stored owner is
mixed-case. Before the fix it fails because the submitted values include
the unchanged `repositories` array. After the fix it passes.
- Edit-mode changes still send the full selection. A new case changes
only one repository's base branch (nested `group/subgroup` owner) and
expects both repositories with the new branch. With the branch
comparison replaced by `true` it fails, and it passes as written. The
existing reorder case still sends the new order. Two edit-mode tests
asserted the unchanged list as a side effect. The ownership test drops
that assertion, and the nested-namespace parsing test now submits
through create mode, where the list is always sent.
- Control-plane behaviour, checked with the route test harness (not part
of this PR). Prebuild-disabled team environment with no grant: `{ name,
description, prebuildEnabled: false }` returns 200, and the same body
plus the unchanged `repositories` returns 409
`target_team_missing_grant`. With only `environments.manage`, the resent
list returns 403 `permission_required`.
- `npm run typecheck` passes. The `@open-inspect/web` vitest suite
passes.
…#2233)

## Summary
Reorganizes the analytics page into a one-row header and five tabs. The
page opened with a hero card that filled most of the first screen
(title, a caveat paragraph, three badges, and the two filters with five
lines of help text), then ran to about 8,000px of cards at 1440×900,
with usage, cost, tokens and people interleaved and a heading only on
the pull request section.

- **Header**: one toolbar row with the title, the window ("Sep 3 – Oct
2"), a freshness indicator, and the scope and range filters as segmented
controls. The caveats move behind **About this data** (an icon on
phones) and the scope descriptions behind an info button.
- **Overview**: headline numbers grouped by what they're scoped to
(**Human sessions**: sessions, active users, spend, completion rate;
**Pull requests · every source**: PRs merged, cost per merged PR),
sessions-per-day and PRs opened/merged charts, and top-five lists for
repositories, models and people that link into their tabs. About one
screen at 1440×900.
- **Usage**: sessions per day, where sessions start (source → attributed
users, keeping the attribution notes from ColeMurray#2218), how sessions ended,
repositories, and automations for the Automations and All scopes.
- **Cost**: spend, cache hit ratio, subscription-billed share, tokens,
and private-session spend for Owners and Administrators (the API already
returned `privateSessionsCostUsd`; the page never showed it); cost by
model, provider and harness; most expensive runs; token totals.
- **Pull requests**: the existing PR metrics, plus the outcome mix and
cost per merged PR by model or harness. The scope control is disabled on
this tab because PR metrics ignore scope.
- **People**: the sortable per-person table, with a daily-sessions
sparkline per person in place of the "Sessions Over Time" chart, which
drew one overlapping area per user.

Behavior changes:
- Range, scope and tab are in the URL
(`/analytics?days=7&scope=automation&tab=cost`), so a view can be linked
and survives a reload. Defaults are left out. Changes go through
`window.history.replaceState`, which Next syncs into `useSearchParams`;
each change builds on the live URL, so quick successive changes compose
instead of overwriting each other, and no server render is involved.
- `useAnalyticsDashboard` uses SWR `keepPreviousData` and returns `{
dashboard, loading, stale, validating, error }`. While a new range or
scope loads, the previous snapshot stays on screen, dimmed and
`aria-busy`, and the header reads "Loading…". If that request fails, the
page says the selected range failed to load and the header reads
"Showing the previous selection" instead of a fresh "Updated" time.
- Daily series are zero-filled across the window. The API omits days
without activity, and the old charts drew straight across them.
- **PRs merged** on the overview counts merges during the window, the
same population as its daily-merges sparkline and the average time to
merge. Cost per merged PR stays on the PRs opened in the window, as
before.
- Completion rate is "—" until a session finishes, everywhere
(previously tables showed "0%"); sessions per person divides attributed
sessions by attributed people, leaving out sessions with no recorded
user.
- Costs show cents below $1,000 and whole dollars above; sub-dollar
values used to show four decimals ("$0.8565 per session"). Analytics has
its own `formatAnalyticsCost`; `formatSessionCost` is unchanged.

API change:
- The session timeseries (dashboard `timeseries` and `GET
/analytics/timeseries`) now keys each day's groups by the same user key
as the user breakdown (user ID, else SCM login, else `__unknown__`)
instead of by display name. Two people with the same name were merged
into one series, which was fine for the old chart's name legend but
wrong for per-person sparklines. The removed chart was the only
consumer. The integration tests that pinned name grouping now pin
identity grouping.

Code:
- One sortable `AnalyticsTable` replaces the dimension table, harness
cards, repository and model bar charts, and the user table. Sort values
may be `null`; those rows sort last in both directions, so callers no
longer invent sentinels. `AnalyticsKpiStrip`/`AnalyticsKpiGroups`,
`AnalyticsRankedBars`, `AnalyticsTrendChart` and `AnalyticsPanel`
replace the other card styles. `SegmentedControl` is added to
`components/ui` as a thin `ToggleGroup` wrapper.
- Removes the 11 components the tabs replace, with their tests. Their
behaviors are covered by the new tests: origin attribution and duplicate
display names, subscription "—" vs 0, completion over finished sessions,
sorting, and the PR-funnel-only rule for PR counts in the headline.
- `DEFAULT_ANALYTICS_DAYS` moves to `@open-inspect/shared` beside
`DEFAULT_ANALYTICS_SCOPE`, so the page default and the API default are
one constant.
- The new styles avoid Tailwind opacity modifiers on theme colors. Theme
colors are bare `var()`s, so classes like `bg-destructive/60` emit no
CSS; that is why the old "Cancelled" status bar never rendered. The same
pattern exists elsewhere in the web app and is left for a separate
change.
- `administration/analytics.mdx` is rewritten for the tabbed page.

## Testing
- `npm test -w @open-inspect/web` (2,847 passed), `npm run typecheck`,
eslint, prettier, `npm run build -w @open-inspect/web`
- `npm test -w @open-inspect/shared` (1,133 passed); control-plane
typecheck, `src/db/analytics-store.test.ts`,
`src/routes/analytics.test.ts`, and `test/integration/analytics.test.ts`
(16 passed in workerd)
- `npm test -w @open-inspect/docs` (44 passed), `npm run build -w
@open-inspect/docs`
- Manually against synthetic dashboard data in a local preview: every
tab at 1440px and 390px, light and dark; two filter clicks without
waiting both land in the URL and the page re-renders; tabs and overview
links; reload keeps the view; per-person sparklines for every row; About
this data on phones; no console errors.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Redesigned Analytics as five tabs: Overview, Usage, Cost, Pull
requests, and People, with metrics, charts, tables, and breakdowns
tailored to each view.
* Added URL-persisted time range, session scope, and tab selections.
Previous results remain visible while new filters load.
* Added sortable, expandable analytics tables and clearer session
attribution, cost, and pull-request details.

* **Documentation**
* Updated Analytics guidance with tab contents, filtering behavior,
calculations, refresh details, and troubleshooting information.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
…leMurray#2216)

## Problem

With `web_platform = "cloudflare"`, every page of the web app logs
`ReferenceError: __name is not defined` in the browser console.

By default wrangler bundles the worker with esbuild's keep-names, which
wraps named functions in `__name(fn, "name")`. next-themes serializes
its theme function into an inline `<script>`. That script then carries
the `__name(...)` call into the browser, where `__name` does not exist.
The script throws before it applies the saved theme. React applies the
theme only after hydration, so users whose saved theme is not the
default see a flash of the wrong theme.

This is the known OpenNext issue
[opennextjs/opennextjs-cloudflare#1249](opennextjs/opennextjs-cloudflare#1249).
OpenNext's guidance is to set `keep_names = false`:
https://opennext.js.org/cloudflare/howtos/keep_names.

## Fix

Set `keep_names = false` in the two places that produce the web worker's
wrangler config:

- `terraform/environments/production/web-cloudflare.tf`, which generates
the production config;
- `packages/web/wrangler.toml`, the checked-in local config.

The only documented downside is less readable function names in
debugging tools.

## Verified

- Dry-run bundle with the repo's wrangler (4.141.0) of a worker that
serializes a function containing a named function into an inline script,
the same shape as next-themes: 2 `__name(` calls with the default
setting, 0 with `keep_names = false`.
- Deployed on a production Cloudflare web deployment: the served HTML's
next-themes inline script (`localStorage.getItem(...)`) now contains no
`__name(` call, on `/`, `/sessions` and `/access-denied`.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Resolved a browser error affecting the theme-switching script in the
production web app.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Ojas Mor <ojas.m233@gmail.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…leMurray#2236)

Supersedes ColeMurray#2224 (by @rhlsthrm). This version is rebased onto current
`main` and includes one small follow-up from review.

## Changes from ColeMurray#2224

- **Merge conflict resolved.** Only
`hono-route-catalog-conformance.test.ts.snap` conflicted, because new
routes on `main` shifted the fixture indices. I kept `main`'s snapshot
and reapplied the single `POST /automations` line change.
- **Docs.** `administration/workspace-access.mdx` now says that creating
an automation also requires permission to create sessions, matching the
existing note that session creation requires repository/environment use.

## Review notes

- `requireAll(...)` keeps the old route's audit setting (`auditAllowed:
true`) and service policy (actor only, with no actorless grants). Only
the `allOf` list changes.
- `POST /automations` is the only path that inserts automations
(`AutomationStore`), so the route check covers creation completely.
- Every web create entry point (list, team tab, `/automations/new`,
templates) goes through `useCanCreateAutomation`.

## Verification (after rebase)

- `automation-executor-permissions` + `hono-route-catalog-conformance`
integration tests: 24 passed
- Web automations page/component tests: 180 passed
- `typecheck` (control-plane, web): passed
- `prettier --check` on touched files: clean

---

## Original description

## Problem

Found in review. `POST /automations` only requires `automations.create`,
but the creator becomes the automation's executor, and every run is
authorized against the executor by `isAutomationExecutionAuthorized`,
which requires `sessions.create`. A user whose custom role grants
`automations.create` without `sessions.create` gets a `201` for an
enabled automation, workspace- or team-owned, that can never run:

- the first scheduled firing is recorded as a skipped invocation with
`execution_authorization_denied` and the automation is paused;
- event firings are skipped;
- the creator's own **Trigger Now** is refused.

The other executor writes already refuse this state. Executor
reassignment (`PATCH /automations/:id`) rejects a candidate without
`sessions.create`, and target edits refuse to leave the automation
unrunnable by its executor. Create already checks the target-use half of
the rule (`repositories.use` / `environments.use` through
`authorizeSessionTarget`), so `sessions.create` is the only execution
permission it skips.

## Cause

- `packages/control-plane/src/routes/automation-crud.ts`: the create
route authorizes `requirePermission("automations.create")` only.
- `packages/control-plane/src/automation/authorization-guard.ts`:
execution requires the executor to hold `sessions.create`.

## Fix

Require `sessions.create` alongside `automations.create` in the create
route's declarative authorization, composed with `requireAll(...)` as
`POST /sessions/:id/children` does. A denial returns the standard
route-level `permission_required` response for `sessions.create`.

The web create gate (`useCanCreateAutomation`) now requires
`sessions.create` too, so a user without it no longer sees **Create
Automation**, **Browse templates**, or the create form only to get a
`403` on save. The team Automations tab uses the same gate.

Built-in roles are unaffected: every built-in role with
`automations.create` also has `sessions.create`. The route catalog
snapshot changes for this one route.

## Verified (original PR, pre-rebase)

- New integration test in `automation-executor-permissions.test.ts`,
`rejects {team,workspace} creation by an executor without
sessions.create`: fails on `main` (`expected 201 to be 403`) and passes
with the fix.
- The list-page test `hides create and template entry points without
sessions.create` fails against the old client gate and passes with the
fix. The other automation page tests now grant both permissions.
- On `main`, a throwaway integration test confirmed the failure mode for
both ownerships. The created automation was enabled, the first tick
returned `{ processed: 0, skipped: 1, failed: 0 }`, the automation was
paused with a skipped `execution_authorization_denied` invocation and no
session, and `trigger()` by the creator threw
`AutomationExecutionUnauthorizedError`.
- `npm run typecheck`: passed.
- `npm test -w @open-inspect/control-plane`: 6,176 passed.
- `npm run test:integration -w @open-inspect/control-plane`: 1,885
passed, 1 skipped. Only the `POST /automations` snapshot line changed.
- Web tests for the automations list, new, and templates pages and
`automation-collection`: 36 passed.
- `prettier` and `eslint` on the touched files: clean.


---
*Created with
[Open-Inspect](https://open-inspect-prod.vercel.app/session/92af5b49885b98f65256f86a6a14707e)*

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Access Changes**
* Creating an automation now requires permission to create both
automations and sessions. Users without session-creation permission
receive an access-denied response, and no automation is created.
* Automation creation and template links are hidden when either required
permission is missing.

* **Documentation**
* Clarified that automation runs use the creator’s authority, so
creating an automation requires session-creation permission.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Rahul Sethuram <rahul.eth@icloud.com>
Co-authored-by: Cole Murray <2492022+ColeMurray@users.noreply.github.com>
…eMurray#2239)

## Problem

Claude harness sessions run with two competing memory systems:

1. Open-Inspect's memory tools (`mcp__oi__memory_write` /
`memory_search` / `memory_read`), which store memories server-side with
personal, repository, and environment scopes and an approval flow.
2. Claude Code's built-in **auto memory**. It adds a detailed "Memory"
section to the system prompt telling the agent to write markdown files
to `$CLAUDE_CONFIG_DIR/projects/<cwd>/memory/` and index them in
`MEMORY.md`.

The harness never turns (2) off. Its system-prompt instructions are
detailed, while the OI memory tools are deferred, so the agent sees only
their names until it loads them. As a result, when a user asked the
agent to "add to our personal memory", it wrote a local file instead of
calling `mcp__oi__memory_write`. The file never reached Open-Inspect's
memory store.

## Fix

Set `CLAUDE_CODE_DISABLE_AUTO_MEMORY=1` in `harness_env`, next to the
existing `CLAUDE_CODE_DISABLE_*` policy variables. With that,
Open-Inspect's tools are the only memory system the agent is told about.

The variable is checked in the bundled CLI (`claude-agent-sdk==0.2.161`,
Claude Code 2.1.284). The auto-memory resolver returns `"off"` for a
truthy `CLAUDE_CODE_DISABLE_AUTO_MEMORY` before it reads the
`autoMemoryEnabled` setting. So a repository's `.claude/settings.json`,
which is loaded through `setting_sources=["user","project"]`, cannot
turn it back on.

`docs/CLAUDE_AGENT.md` now has a **Memory** entry in the operational
notes, alongside the sub-agent note.

## Verification

- New `test_harness_env_disables_file_based_auto_memory` in
`tests/test_claude_env.py`
- `pytest tests/test_claude_env.py tests/test_claude_harness.py`: 57
passed
- `ruff check` / `ruff format --check`: clean; `prettier --check
docs/CLAUDE_AGENT.md`: clean

Not verified end-to-end: no live Claude session was started with the new
env, because that needs model credentials. The behavior relies on the
CLI code path described above.

## Rollout

Sandboxes pick this up when the sandbox-runtime code they run includes
the change. Existing sandboxes keep auto memory on until they're
restarted on the new runtime.


---
*Created with
[Open-Inspect](https://open-inspect-prod.vercel.app/session/92af5b49885b98f65256f86a6a14707e)*

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Updates**
* Claude Agent runs with file-based automatic memory disabled in the
sandbox. Open-Inspect’s memory tools remain available as the memory
system.
* **Documentation**
* Updated operational notes to reflect Claude Agent’s memory
configuration.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Cole Murray <2492022+ColeMurray@users.noreply.github.com>
…ay#2237)

## Summary

If the page refreshed while you were typing a long prompt, you lost the
prompt. Drafts are now saved to `localStorage` as you type and restored
when the page loads. This works in both composers:

- **New-session composer** (`/`): uses the key
`open-inspect-prompt-draft:new-session`
- **Session composer** (`/session/[id]`): uses the key
`open-inspect-prompt-draft:<sessionId>`, so each session keeps its own
draft

### Behavior

- Each keystroke writes the draft to storage synchronously, so a refresh
right after typing doesn't lose anything.
- Setting the prompt to empty removes the stored key. A successful send
clears the prompt, so the key is removed then too, and storage doesn't
build up keys for sent prompts.
- If a send fails (rejected, timed out or disconnected), the draft stays
so you can retry after a reload.
- The draft is restored in an effect after hydration, so server and
client render the same markup. This is the same approach as the other
`localStorage` preferences in the web app.
- Restoring a draft on the home page does **not** start warming a
sandbox; warming still begins on the next keystroke. If you send before
then, submit creates the session as it does today.
- Storage errors (unavailable or quota exceeded) are caught, and the
composer falls back to in-memory state.
- A queued prompt restored into the composer (`restorePrompt`) is also
saved, because it goes through the same setter.

### Implementation

- New `usePromptDraft(draftId)` hook in
`packages/web/src/hooks/use-prompt-draft.ts`
- `usePromptInput` now gets its prompt state from
`usePromptDraft(sessionId)`, replacing its own `useState`/`promptRef`
pair
- The home page uses `usePromptDraft(NEW_SESSION_PROMPT_DRAFT_ID)` and
clears the draft after the first prompt is sent

## Testing

- New tests in `use-prompt-input.test.tsx`: the draft is restored after
a remount, drafts are kept separate per session, the draft is cleared
after a successful send, and it is kept after a failed send
- New tests in `page.test.tsx`: the draft is restored after a remount,
cleared once the session starts, and kept when the first prompt fails
- I checked that the new restore and keep-on-failure tests fail without
the source change
- `npm test -w @open-inspect/web`: 192 files, 2051 tests passed
- `tsc --noEmit -p packages/web`, ESLint and Prettier: clean

---
*Created with
[Open-Inspect](https://open-inspect-prod.vercel.app/session/74a5580e3fd4c378721b6c3fb94b4f6e)*

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Prompt drafts are saved automatically and restored when you return to
a composer, including after navigating away and back.
* Drafts are kept separate across users, sessions, and browser tabs, and
remain available when a prompt fails to send.
* Retrying a restored draft reuses its request identity until you edit
the draft.
* Drafts are cleared after a prompt is successfully sent or you sign out
successfully. If sign-out fails, your draft remains available.
  * Completing an earlier send won’t clear a newer draft.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Cole Murray <2492022+ColeMurray@users.noreply.github.com>
Co-authored-by: waclaude <colemurray.cs+ghwaclaude@gmail.com>
## Summary

- Support primary/source Linear team bindings in the existing
provider-keyed store and Channels tab, with provider-matching bot lookup
and audited management.
- Add the global-only Linear `unboundChannels` policy: `workspace`
preserves workspace-level launches; `reject` posts binding instructions
and creates no session.
- Create Linear sessions with the resolved `teamId` and signed
human/app-user actor. Surface membership refusals and name the
repository for `target_team_missing_grant` refusals without linking or
prompting a refused session.
- Scope catalog, settings, stop, and completion requests with the signed
external Linear team coordinate. Scoped catalogs re-read live
bindings/grants and bypass the bot's unscoped caches. Preflight reads
remain actorless so session creation retains first-time identity
linking.
- Persist the external team in callback contexts and issue-session
mappings; safely recover older completion contexts or skip reads when
the coordinate cannot be recovered.
- Preserve Slack discovery and channel safeguards. Add an
operator-facing changelog entry.

Closes
[COL-256](https://linear.app/colemurray/issue/COL-256/teams-pr-16b-control-plane-linear-bot-web-linear-team-bindings).

## Access And Schema

Based on `main` at `5abc1fb`. Uses existing D1 migration `0083` and
session DO schema version `56`; no migration, table, or column changes.

Binding management, binding lookup, and scoped catalog checks enforce
independently of `TEAMS_ENFORCEMENT`. Existing session-creation
membership/grant checks are unchanged. Existing session admission
remains responsible for completion reads: `off` retains legacy
non-private admission, `shadow` audits would-be non-private denials, and
`on` enforces resolver decisions. Private service reads remain refused
in every mode. The unset enforcement default remains `shadow`.

## Checkpoint Report

### 1. Commands And Results

Heavy checks ran sequentially with a single Vitest worker and 600000 ms
shell timeouts.

| Command | Final result |
| --- | --- |
| `npm run build -w @open-inspect/shared` | Passed |
| `npm run typecheck` | Passed across every TypeScript workspace |
| `npm run lint:fix` | Passed, including the commit hook |
| `npm run lint:sql-portability` | Passed; 24 existing baselined
occurrences |
| `npm test -w @open-inspect/shared -- --maxWorkers=1` | 66 files, 1150
tests passed |
| `npm test -w @open-inspect/control-plane -- --maxWorkers=1` | 365
files, 6261 tests passed |
| `npm run test:integration -w @open-inspect/control-plane --
--maxWorkers=1` | 148 files, 2023 passed, 1 skipped |
| `npm test -w @open-inspect/web -- --maxWorkers=1` | 274 files, 2839
tests passed |
| `npm test -w @open-inspect/linear-bot -- --maxWorkers=1` | 19 files,
319 tests passed |
| `npm test -w @open-inspect/slack-bot -- --maxWorkers=1` | 39 files,
621 tests passed |
| `npm test -w @open-inspect/github-bot -- --maxWorkers=1` | 8 files,
146 tests passed |
| `git ls-files --modified --others --exclude-standard -z \| xargs -0
npx prettier --write --ignore-unknown` | Passed |
| `git diff --check` and `git diff --check origin/main...HEAD` | Passed
|

The successful web/integration runs emitted existing navigation/timer,
forced-eviction, and D1 error-fixture diagnostics; these were not failed
tests.

Targeted regression runs and their initial failures are recorded below.
All corresponding tests passed in the final full suites.

<details>
<summary>Initial failing validation output</summary>

`npm test -w @open-inspect/linear-bot -- src/webhook-handler.test.ts
--maxWorkers=1`, before handler wiring:

```text
 ❯ src/webhook-handler.test.ts (46 tests | 8 failed) 128ms
     × transitions an existing installation and creates an environment session 33ms
     × creates a session in the resolved ownership scope null 3ms
     × creates a session in the resolved ownership scope team_internal 7ms
     × refuses a failed or invalid binding lookup (404) 4ms
     × refuses a failed or invalid binding lookup (503) 3ms
     × refuses a failed or invalid binding lookup (200) 2ms
     × posts a membership error without linking or prompting an app-user fallback session 2ms
     × stops an existing session when Linear sends a stop signal 2ms

 Test Files  1 failed (1)
      Tests  8 failed | 38 passed (46)
```

`npm test -w @open-inspect/web --
src/components/settings/integrations/linear-integration-settings.test.tsx
--maxWorkers=1`, before disabling the whole pending form:

```text
 ❯ src/components/settings/integrations/linear-integration-settings.test.tsx (10 tests | 1 failed) 1661ms
     × preserves dirty edits during revalidation and saves the policy in global defaults 162ms

Received element is not disabled:

 Test Files  1 failed (1)
      Tests  1 failed | 9 passed (10)
```

`npm test -w @open-inspect/linear-bot -- src/webhook-handler.test.ts
--maxWorkers=1`, before retaining actorless preflight reads and refusing
an unavailable bound environment mapping:

```text
 ❯ src/webhook-handler.test.ts (47 tests | 3 failed) 102ms
     × refuses an unavailable bound environment mapping instead of falling back to a repository 6ms
     × creates a session in the resolved ownership scope null 3ms
     × creates a session in the resolved ownership scope team_internal 5ms

AssertionError: expected { repoOwner: 'acme', …(5) } to be null
AssertionError: expected true to be false // Object.is equality

 Test Files  1 failed (1)
      Tests  3 failed | 44 passed (47)
```

`npm run test:integration -w @open-inspect/control-plane --
test/integration/environments-catalog.test.ts --maxWorkers=1`, before
actorless Linear catalog admission:

```text
 FAIL  test/integration/environments-catalog.test.ts > team-scoped environment catalog > scopes actorless Linear catalog reads to the live binding without enrolling a user
AssertionError: expected 403 to be 200 // Object.is equality

 Test Files  1 failed (1)
      Tests  1 failed | 8 passed (9)
```

`npm run test:integration -w @open-inspect/control-plane --
test/integration/environments-catalog.test.ts
test/integration/team-grants.test.ts
test/integration/team-channel-bindings.test.ts --maxWorkers=1`, before
separating the preserved Slack actor requirement from Linear's actorless
catalog contract:

```text
 FAIL  test/integration/team-grants.test.ts > team repository grants > refuses invalid, actorless, and mismatched linear channel claims before reading catalogs
AssertionError: expected 200 to be 403 // Object.is equality

 Test Files  1 failed | 2 passed (3)
      Tests  1 failed | 70 passed (71)
```

The initial formatting command without `--ignore-unknown` also failed on
Vitest's snapshot extension:

```text
[error] No parser could be inferred for file "/workspace/background-agents/packages/control-plane/test/integration/__snapshots__/hono-route-catalog-conformance.test.ts.snap".
```

Rerunning with `--ignore-unknown` passed; snapshot contents were
validated by the integration suite.

</details>

### 2. Verified Facts And Drift

- Webhook dispatch, project/team mapping precedence, app-user fallback,
and signed actor assertions matched the existing behavior. The
operator-managed `config:team-repos` mapping stays intact.
- The shared binding enum, store, SQL constraints, and signed
session-channel parser already supported Linear. No additional session
route-admission implementation was necessary; integration tests exercise
Linear completion-event scopes in all enforcement modes.
- Binding PUT and bot lookup were still Slack-only. Catalog scoping also
had a Slack-only gate in `routes/team-ownership.ts`, so Linear support
includes that existing read helper.
- Actor-bearing reads finalize identity before RBAC
(`routing/route-admission.ts`); this exposed the first-time-linking
hazard of asserting an actor on preflight catalogs. Linear preflight
reads therefore use the binding-derived service viewer, while creation
remains the canonical actor/profile-claims seam.
- Scoped environment lists already omit targets whose repositories lack
grants. A bound, explicitly mapped environment now refuses rather than
silently falling through to another target when it is unavailable in
that catalog.
- The existing integration test file is `team-channel-bindings.test.ts`.
The current control-plane catalog has 212 routes and 160 paths; neither
count changes. Only existing policy snapshot entries change.
- The strict callback schema now explicitly permits an optional external
`linearTeamId`, preserving persisted contexts while ensuring new
callbacks have a scoped read coordinate.

### 3. Deliberately Excluded

- GitHub routing, automation candidate selection, enforcement-default
changes, new migrations, and shared session-creation/token-mint changes
are outside this change.
- No Linear team discovery API was added. The Channels tab accepts a
Linear team ID manually and retains Slack's existing picker.
- No new Linear publication-purpose or Slack-style outbound-post policy
was introduced. Completion reads use existing service-viewer decisions.
- Real sign-in, production API persistence, and live Linear delivery
were not exercised locally. Browser verification used real components
and repository CSS with explicitly mocked auth and API fixtures.

## Visual Verification

Verified bind/unbind and policy save/reset at desktop 1440×1000 and
mobile 390×844, including disabled controls during pending saves and no
mobile horizontal overflow. The mobile reject label was shortened and
rechecked.

| Surface | Capture | Source | Uploaded artifact |
| --- | --- | --- | --- |
| Desktop Channels | Viewport, 1440×1000 |
`http://127.0.0.1:4173/channels` | `75358db59fcd5ba04167aca8e1859f2f` |
| Mobile Channels | Viewport, 390×844 | `http://127.0.0.1:4173/channels`
| `28f77063fa3caffa6204da2ca92eca7d` |
| Desktop Linear policy | Full-page, 1440×1000 viewport |
`http://127.0.0.1:4173/linear-settings` |
`3872fcfcd5df7d72cb4a7c38f4c84de3` |
| Mobile Linear policy | Full-page, 390×844 viewport |
`http://127.0.0.1:4173/linear-settings` |
`b440e7ac27923a8fb95b4a8cea6718c3` |

The local preview used mocked authentication, authorization, models,
fixtures, and API responses, and browser fallback fonts rather than the
complete Next.js app shell.

---
*Created with
[Open-Inspect](https://open-inspect-prod.vercel.app/session/657787201d55309489d5251a9a87b083)*

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Team leads and workspace administrators can bind or unbind Linear
teams in team Channels settings.
* Workspace administrators can choose whether requests from unbound
Linear teams create workspace-level sessions or are rejected.
* Requests from bound teams use team-scoped repository, environment, and
session access, with membership and repository-grant checks.
* **Bug Fixes**
* Requests stop when a team binding or required access cannot be
verified.
* Completion content is withheld if the issue’s team changes or scoped
session data cannot be read.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Cole Murray <2492022+ColeMurray@users.noreply.github.com>
Co-authored-by: waclaude <colemurray.cs+ghwaclaude@gmail.com>
…#2240)

## Summary

The new-session composer's team context (and audience) picker in
`SessionAccessSelector` only lived in React state, so it reset to the
sidebar team defaults on every reload or navigation back to the home
page. Users had to reselect their team each time.

This persists the composer access draft (`contextKey`, `teamId`,
`visibility`) to localStorage under `open-inspect-last-session-access`:

- Saved only on explicit user changes (team or audience), not on
automatic reconciliation.
- Restored on mount and validated with zod
(`parseStoredComposerAccess`); malformed values are ignored.
- Still keyed by the sidebar `contextKey`, so a stored choice only
applies while the sidebar team context (already persisted via
`open-inspect-active-team`) matches. Switching the sidebar team keeps
the existing "use team defaults" behavior.
- Stale team IDs fall through the existing `resolveComposerAccess`
validation against current memberships.
- Storage access is wrapped in try/catch, matching `use-active-team`.

## Testing

- New tests in `page-team-context.test.tsx`: restores team + audience
after remount (verified failing without the fix), ignores a selection
stored under a different sidebar context, and ignores malformed storage.
- `npm test -w @open-inspect/web`: 192 files, 2049 tests passing
- `tsc --noEmit` and eslint are clean

---
*Created with
[Open-Inspect](https://open-inspect-prod.vercel.app/session/2b167816c4d25a733bd423bf07329672)*

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Team and visibility selections in the composer are saved and restored
when you return, unless you’ve already made a new selection.
* If browser storage is unavailable, your current selection continues to
work for the session.
* **Bug Fixes**
* Invalid, inaccessible, or context-mismatched saved selections are
ignored, preventing them from overriding the current sidebar context.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Cole Murray <2492022+ColeMurray@users.noreply.github.com>
Co-authored-by: waclaude <colemurray.cs+ghwaclaude@gmail.com>
…rray#2211)

## Summary

- correlate sandbox event receipt, completed dispatch, and failed
processing with sandbox/message/tool/task/step/operation/ACK metadata
- record critical-event ACK outcomes after successful dispatch,
distinguishing local send success, unavailable socket, failed send, and
legacy missing ACK IDs
- retain DEBUG-only token/heartbeat logging; allowlist and bound
metadata without logging content, arguments, output, error text, titles,
or attachments
- preserve dispatch exceptions, event persistence/broadcast behavior,
and critical-event acknowledgement ordering
- log receipt before attribution lookup and capture safe failures even
when the persisted processing-message lookup fails; missing-ID critical
ACK outcomes remain visible at INFO

`processed` means the family handler's dispatch finished. It does not
claim completion of background callbacks, client delivery, or remote ACK
receipt. `sent` means the local WebSocket send succeeded.

## Validation

- Node 24.19.0; shared package build passed
- focused processor/runtime handler tests: 64 passed (`--maxWorkers=1`)
- after review fixes: processor suite 59 passed, including lookup
failure with and without an explicit message ID
- control-plane package typecheck passed (Worker, Node, tests,
integration config)
- ESLint on changed files passed; Prettier applied; `git diff --check`
passed
- tests cover payload exclusion, bounded metadata, explicit/fallback
message attribution, failure preservation/no ACK, and ACK outcomes/order

## Scope

Independent of the Python logging PRs. No schema changes or deployment
performed. Local tests do not establish production log ingestion; after
deployment, confirm the same message/call/ACK IDs across Modal and
control-plane logs.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Improvements**
* Event-processing diagnostics now include timing, status, and
attribution details, with long metadata shortened. Heartbeat and token
details are logged at debug level.
* Processing failures record the error type and duration before the
original error is rethrown; failed events are not acknowledged.
* Acknowledgment logs distinguish successful and failed sends,
unavailable connections, and missing event IDs, and reflect that
acknowledgments follow event processing.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Cole Murray <2492022+ColeMurray@users.noreply.github.com>
…eMurray#2243)

## Summary

This supersedes ColeMurray#2194 (by @iamladi). It's rebased onto `main` with one
review fix added. The original commit is kept with its authorship.

The Slack and Linear classifiers send no `reasoning_effort`, so an
OpenAI classification model always runs at its default effort. On some
reasoning models that default is `medium`, which costs latency and
reasoning tokens for a routing decision. This PR lets an operator choose
the effort.

- **New variable `classification_reasoning_effort`** (CI: the
`CLASSIFICATION_REASONING_EFFORT` Actions variable). When it is set,
both classifier Workers get a `CLASSIFICATION_REASONING_EFFORT` binding,
and `callOpenAIStructured` sends it as `reasoning_effort`.
- **Blank is the default and changes nothing.** No binding is created
and no field is sent.
- **OpenAI only.** A validation rule rejects the variable at plan time
when `classification_model` is an Anthropic id. Without it, the setting
would be silently ignored.

## Changes from ColeMurray#2194

- **Rebased onto `main`** and resolved the `CHANGELOG.md` conflict. The
entry sits under the existing `### Added` section, next to the Linear
team bindings entry.
- **Format check on the value.** The effort is still not limited to a
fixed list, since supported values differ by OpenAI model. But it must
now be blank or a lowercase word (`^[a-z]+$`). Before, a value like
`"low "` or `"Low"` passed `terraform plan`, was bound as-is, and made
OpenAI return HTTP 400 on every classification. Every Slack/Linear
request then quietly fell back to the repo picker or a clarifying
question. Added a `rejects_padded_reasoning_effort` tftest.

## Testing

- `npm test` for shared, slack-bot, and linear-bot
- `npm run typecheck`
- Prettier check on the changed files
- `terraform fmt -check -recursive`
- Full `terraform test` suite (66 passed)

Not covered: no run against the live OpenAI API.

---
*Created with
[Open-Inspect](https://open-inspect-prod.vercel.app/session/74d38ef76a4ce8e99cb46e12163a80c0)*

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Added an optional reasoning-effort setting for Slack and Linear
classification with OpenAI models. When unset, the model’s default is
used.
* Added validation to reject this setting for Anthropic models and
invalid values.
* **Documentation**
* Updated setup guides and configuration examples with details on the
new setting.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Ladislav Martincik <ladislav.martincik@gmail.com>
Co-authored-by: Cole Murray <2492022+ColeMurray@users.noreply.github.com>
## Summary
- Split the serial coverage workflow into six control-plane Vitest
shards plus parallel web, small TypeScript, and Python jobs.
- Preserve the existing `Coverage` check as the final gate: require
every upstream job to pass, merge all control-plane blob reports, and
enforce the unchanged full-suite coverage floor on the merged result.
- Keep the combined `production-coverage` artifact and document the new
layout. Ignore local Vitest shard reports.

## Validation
- Built `@open-inspect/shared`, typechecked
`@open-inspect/control-plane`, ran coverage gate tests, and checked
formatting.
- Smoke-tested two control-plane shards containing unit and Workers
integration tests; merging their blobs produced a combined report. The
merge correctly failed the full-suite threshold when deliberately run
with only those two tests.

CI on this PR will establish the actual wall time and whether the
six-shard layout meets the 3–4 minute target.

---
*Created with
[Open-Inspect](https://open-inspect-prod.vercel.app/session/f7f5be2008fc39113067520fa149b402)*

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Chores**
* Coverage checks now run in parallel for control-plane, web, other
TypeScript packages, and Python. Each job uploads its results, which are
collected into a combined coverage artifact.
* The overall coverage check reports unsuccessful jobs and fails if any
individual coverage check fails.
* **Documentation**
* Updated coverage guidance to describe the parallel jobs and combined
artifact. Removed outdated instructions to limit TypeScript coverage
runs to a single worker.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Cole Murray <2492022+ColeMurray@users.noreply.github.com>
Co-authored-by: waclaude <colemurray.cs+ghwaclaude@gmail.com>
…y#2210)

## Summary

Make Claude Agent SDK activity visible in sandbox/Modal logs without
changing permissions, authentication, tool execution, persistence, or
emitted session events. Claude stdout remains SDK-owned structured
input; OpenCode process forwarding is unchanged.

## Implementation

- Add structured INFO entries for tool starts/results, completed
assistant updates, task lifecycle metadata, compaction/provider
diagnostics, and completed/failed/cancelled turn outcomes with duration,
usage, and available cost.
- Generate wire events and trajectory records in one typed
`ClaudeTranslator`. Render records before event delivery, with
per-record failure isolation.
- Keep prompt correlation and result state invocation-local. SDK stderr
stays distinctly session-scoped because its connection-lived callback
provides no reliable turn provenance.
- Keep raw text/argument/output previews bounded to 2,048 UTF-8 bytes
with explicit truncation. Multiline and non-ASCII content remains
readable through the existing structured JSON formatter.
- Use canonical `StructuredLogger` exception metadata and tracebacks
rather than a custom sanitized exception path.
- Preserve task-parent mappings across turns, clean up terminal/reset
mappings, and bound orphan tracking.
- Keep harness, trajectory, logger, and translator tests in focused
modules with reusable SDK fakes.
- Do not collect thinking blocks, streaming deltas, subagent text, task
summaries, raw SDK messages, or automatically dump
configuration/environment state.

### Logging Policy

Per maintainer request, the extra credential sanitization and provenance
layer has been removed for parity with the existing OpenCode setup.
There is no new secret inventory, credential scanning,
sensitive-key/header/CLI masking, or content-gating dependency. The
control-plane and Modal environment assembly files match `main` again.

**Content produced by the agent is logged as-is within preview limits
and can contain credentials if a tool or assistant emits them.** Preview
truncation is not credential redaction. Existing unrelated Git/boot
redaction remains unchanged.

## Validation

Run sequentially against the frozen dependencies and pinned
`claude-agent-sdk==0.2.161`:

- Focused Claude harness, trajectory, logger, and translator tests:
**114 passed**.
- Full sandbox-runtime Python suite: **1,476 passed, 3 skipped**.
- Control-plane environment/provider tests with `--maxWorkers=1`: **340
passed**.
- Modal environment/launch tests: **109 passed**, using
`PYTHONPATH=../sandbox-runtime/src:../sandbox-images/src` to test the
checkout rather than the image-installed runtime.
- Python Ruff lint/format and affected runtime/Modal mypy: passed.
- Full control-plane typecheck and affected ESLint/Prettier: passed.
- `git diff --check`: passed.

Tests cover unchanged content and wire events, UTF-8 preview bounds,
normal exception tracebacks, logging/serialization failure isolation,
interleaved turns, persistent SDK stderr readers, and task cleanup.

**These are local checks, not live Modal proof.** No production
deployment, image rollout, or public-to-production sync was performed;
fresh CI results have not been awaited.

## Authorized Canary

Only after merge and a separately authorized runtime rollout:

- [ ] Start a **fresh Claude sandbox** and verify it contains the
updated runtime commit.
- [ ] Exercise shell execution, file reading/editing, a foreground
subagent, and a harmless tool error.
- [ ] Confirm Modal has correlated tool starts/results, completed
assistant updates, task metadata, and turn outcomes with available
duration/usage/cost.
- [ ] Confirm follow-up prompts retain correct turn attribution and SDK
stderr remains distinctly session-scoped.
- [ ] Confirm the session UI receives its normal trajectory and terminal
outcome.
- [ ] Exercise large/multiline/non-ASCII output and verify preview
limits and truncation indicators. Do not intentionally print real
credentials or dump the environment/configuration.
- [ ] Smoke-check OpenCode for unchanged process logging and UI
behavior, with no duplicate Claude-style entries.
- [ ] Capture live evidence that an operator can follow Claude activity
and outcomes directly in Modal logs without opening the native
transcript.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Improvements**
* Claude interactions now provide more complete activity records,
including tool use, task progress, usage, costs, and turn outcomes.
* Interruption, connection, and provider issues are reported more
clearly, while logging failures are prevented from disrupting
interactions.
* Activity records include bounded previews and relevant session
context, helping make diagnostics more useful without exposing
excessively long content.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Cole Murray <2492022+ColeMurray@users.noreply.github.com>
Co-authored-by: waclaude <colemurray.cs+ghwaclaude@gmail.com>
…urray#2245)

## Summary

On the team **Channels** page, the **Provider** and **Binding kind**
fields were plain native `<select>` elements. They didn't match the
styled dropdown next to them (the Slack channel picker) or the rest of
the team pages. `team-repositories.tsx`, for example, already uses the
shared Radix `Select`.

This switches both fields to `@/components/ui/select` (`Select` /
`SelectTrigger` / `SelectContent` / `SelectItem`). Behavior is the same:

- Changing the provider still resets that provider's editor draft and
clears the error banner.
- The binding kind is still disabled when the provider is locked, for
example when Slack discovery is denied.
- The `<label htmlFor>` still points at the trigger, so both fields keep
their accessible names ("Provider", "Binding kind").

## Tests

- `team-channels.test.tsx` now picks options through the Radix trigger
and listbox using the same `chooseOption` helper and pointer-capture
stubs as `team-repositories.test.tsx`. The assertions are unchanged.
- `vitest run src/components/teams/team-channels.test.tsx`: 24 passed
- `tsc --noEmit`, `eslint`, and `prettier --check` pass on the changed
files

---
*Created with
[Open-Inspect](https://open-inspect-prod.vercel.app/session/683d563a1a258c45660b77febf26eecb)*

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Improvements**
* Updated provider and binding-kind menus to use the app’s shared
selection controls for a more consistent interface.
* The provider menu now reflects the form’s disabled state, preventing
selection changes while the form is disabled.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Cole Murray <2492022+ColeMurray@users.noreply.github.com>
## Summary

Control-plane coverage is still the critical path for the `Coverage`
check: it takes 8–13 minutes (483s and 781s on recent runs) against a
15-minute job timeout. ColeMurray#2238's description mentions six control-plane
shards, but its final commit reverted to a single uncapped job, so
`main` never got sharding.

Vitest's timing breakdown shows the problem is throughput, not any
single slow test:

- Duration: 446–692s. Cumulative worker time: setup 770–1250s, tests
200–260s, import 98–155s.
- The slowest file takes 22s, so there's nothing to target individually.
- Most of the setup cost is the Workers pool starting up for each
integration file. Locally, stubbing out the D1 migrations only reduced
setup from ~4.6s to ~4.2s per file, so squashing migrations wouldn't
help much.

That makes this work a good fit for spreading across runners.

## Changes

- **Shard control-plane coverage 8 ways** (`Coverage (control-plane
i/8)`). Each shard writes a Vitest blob report. Unlike the earlier
attempt in ColeMurray#2238, workers aren't capped with `--maxWorkers=2`, so each
shard uses the whole 4-vCPU runner.
- **Merge in a dedicated `Coverage (control-plane)` job** that waits
only for the shards. It runs `vitest run --merge-reports` (which
re-applies the Vitest thresholds) and then `check-coverage.mjs`, and
uploads the same `coverage-data-control-plane` artifact as before. The
merge no longer waits for web, and the final `Coverage` gate is still a
lightweight aggregator.
- `COVERAGE_SHARD=true` turns off the full-suite floor for individual
shards, since a partial run can't meet it. The floor is unchanged and is
enforced on the merged result.
- The final `Coverage` gate also checks the shard matrix result, so a
failed shard is reported directly instead of showing up as a skipped
merge job.
- Ignore `.vitest-reports/` and update `docs/TEST_REDUCTION.md`.

## Expected impact

From ColeMurray#2238's earlier sharded runs: 6 shards capped at 2 workers took
≤235s per shard, and 10 shards took ≤185s. With uncapped workers and the
merge off the gate's critical path, control-plane coverage should come
in around 3–3.5 minutes, down from 8–13. Web coverage (3–4.7 minutes)
becomes the next bottleneck. It can be sharded the same way in a
follow-up if needed.

## Validation

- Ran two local shards over a mixed unit and integration subset with
`COVERAGE_SHARD=true`. Both passed and wrote blob reports without
tripping the floor.
- `vitest run --merge-reports` combined both shards (4 files, 168 tests)
and failed the floor as expected for a partial run. `check-coverage.mjs`
reported FAIL on the merged summary.
- The merge also worked with `packages/shared/dist` removed, which
confirms the merge job doesn't need the shared build.
- Workflow and coverage-gate contract tests pass; the control-plane test
tsconfig typechecks; Prettier is clean.
- This PR's CI run will show the actual wall time.

---
*Created with
[Open-Inspect](https://open-inspect-prod.vercel.app/session/aa446e92f50d8e4f38def70ff69f7ce9)*

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* Control-plane coverage checks now run in parallel shards, with results
combined before the full-suite coverage threshold is checked.
* The overall coverage check verifies that both the shard runs and
report merge succeed.
* Updated coverage workflow documentation and excluded generated test
reports from version control.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Cole Murray <2492022+ColeMurray@users.noreply.github.com>
## Stack / review scope

Depends on ColeMurray#2212 (safe agent logging foundation). Targeting `main` so
the repository's main-only PR CI runs on this exact head. Until the
parent is merged, the overall diff includes its changes; review this
PR's additional commit or the [incremental
diff](ColeMurray/background-agents@sandbox-agent-trajectory-logging...sandbox-transport-diagnostics).
Merge ColeMurray#2212 first.

## Summary

- report buffer evictions with event/message/ACK identities, critical
status, cumulative counts, and rate-limited noncritical warnings;
critical evictions are always reported
- expose compact read-only buffer/pending/in-flight ACK/loss counters
and enrich existing send/recovery failures
- distinguish heartbeat scheduling delay from send duration, warn on
abnormal delays, and emit approximately one aggregate health entry per
minute
- retain prompt failure category, exception type, source outcome, phase,
redacted/bounded error detail, available cost, and
emitted-event/tool-event counts in the turn summary
- preserve upstream oversized-response failure handling and identify its
`text_undelivered` category even when the underlying harness reports
success
- use monotonic turn duration and advance runtime/rebuild generation to
75 without tightening compatibility/preservation/harness floors

Intentional unbuffered stale boot reports stay DEBUG. `evicted_events`
means buffer eviction, not proof of permanent loss (an in-flight send
may still complete). Event counters count emission attempts/lifecycle
updates, not persisted or uniquely executed tools. No retention, ACK,
replay, scheduling cadence, deadline, or execution semantics changed. No
resource-sampling dependency added.

## Validation

- Python 3.12 with frozen dependencies
- 148 focused
transport/forwarder/retirement/reconnect/cost/stop/message-tracking
tests passed after stacking the foundation
- real production formatter tests prove known credentials are redacted
from failure summaries, oversized details are bounded, and terminal
event error text remains unchanged
- Ruff lint/format passed, targeted mypy passed for both source modules,
diff check passed
- combined runtime-stack verification is recorded in the snapshot
follow-up
- final combined stack after upstream rebase and logging review fixes:
1,486 runtime tests passed, 3 skipped; 551 Modal tests and 23 Node tests
passed
- oversized-response regression preserves failure delivery while
recording source success and `text_undelivered`

## Rollout verification (not performed)

In a fresh deployed sandbox, observe normal low-volume health summaries
and correlated prompt outcomes. Use a staging transport interruption to
verify warning counters and recovery identities; distinguish buffered
events from delivered/ACKed events. Do not deliberately interrupt
production sessions. No production sync/deployment performed.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Improvements**
* Added periodic connection and event-delivery health reporting,
including during reconnect attempts.
  * Heartbeat warnings now identify scheduling delays and slow sends.
* Prompt summaries now report outcomes, execution details, and event and
tool-call counts.
* Event-delivery diagnostics now include buffer and acknowledgement
status, with rate-limited warnings for noncritical evictions and
warnings for critical evictions.

* **Tests**
* Expanded coverage for heartbeat, reconnect, prompt outcome, and
event-delivery diagnostics.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Cole Murray <2492022+ColeMurray@users.noreply.github.com>
## Summary
Fixes COL-260: Terraform plan output could become executable
`github-script` source, and a failing plan could be masked by `tee`.

- Capture plan stdout/stderr only in a file, disable the Terraform
output wrapper, and use explicit Bash `pipefail` so Terraform failures
survive the logging pipeline.
- Suspend runner workflow-command processing while logging untrusted
plan text, restoring it on exit even when the output lacks a trailing
newline.
- Generate comments with a small checked-in Node CLI that strips ANSI
escapes, HTML-escapes plan text inside `<pre>`, and truncates the
escaped text without splitting UTF-8 characters or HTML entities.
- Transfer only the prepared comment as a short-lived artifact. A
separate commenting job performs no checkout or execution of PR code and
has only `pull-requests: write`; planning, validation, and apply retain
read-only GitHub permissions.
- Keep the final failed-plan gate unconditional with respect to
reporting failures and pass validation outcomes through environment
variables rather than interpolating outputs into JavaScript source.
- Add malicious-text and failure-path regression coverage and trigger it
for Terraform-workflow-only changes.

## Validation
- `npm run test:terraform-workflow-contract`: 13 tests passed, covering
hostile backticks/interpolation, quotes, shell-looking text,
expression-looking strings, runner commands, ANSI escapes, HTML tags,
oversized/multibyte output, missing final newlines, actual workflow
capture/preparation/posting code, and Terraform exit codes 0, 1, and 42.
- `npm run test:node-version-workflow-contract`: 1 test passed.
- Targeted ESLint and Prettier checks passed.
- `actionlint` passed for both modified workflows.
- `git diff --check` passed.

Live Terraform planning against production state and the GitHub
artifact/comment exchange were not run locally.

## Scope
The separate production-secret and state-access exposure tracked by
COL-259 is not resolved by this change. This PR removes write-token
exposure from planning/validation and fixes the plan-output injection
and failure-masking paths.

---
*Created with
[Open-Inspect](https://open-inspect-prod.vercel.app/session/ba765df4fa4c3ad2ae65a91da468243b)*

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Pull requests now receive Terraform validation results and, when
available, a plan summary as comments.
* Comments show whether planning succeeded or failed, and include plan
details in an expandable section.
* Validation and secret-availability status are also reported in pull
request comments.
* **Chores**
  * Changes to the Terraform workflow now trigger CI checks.
* Terraform plan output in comments is sanitized and may be shortened
when it exceeds the display limit.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Cole Murray <2492022+ColeMurray@users.noreply.github.com>
Co-authored-by: waclaude <colemurray.cs+ghwaclaude@gmail.com>
…urray#2248)

Follow-up to ColeMurray#2220
(ColeMurray#2220). ColeMurray#2220 comes
from a fork, so this branch stacks on its commit (`c209ff5`). **Review
only the commits after `c209ff5`.** Merge after ColeMurray#2220, or instead of it.

## Problem

ColeMurray#2220 blocks an automatic target whenever its catalog has *any* error.
The app-wide SWR fetcher already separates errors: it throws
`SwrFetchError(status)`, and `use-automations.ts` already follows the
rule *"only transient failures (network, 5xx) keep the last loaded
data"*. `revalidateOnFocus` is on, so a brief failure is common.
Reproduced with tests on ColeMurray#2220's code:

- **A temporary error drops the auto target and retires the warm
sandbox.** One 503 or network error during a focus revalidation sets
`sessionTarget` to null. The warm request becomes null and
`useWarmDraftSession` retires the pre-warmed sandbox. Before ColeMurray#2220, auto
targets were unaffected.
- **Workspace auto repos are blocked on any 5xx.** In workspace mode the
repos catalog keeps cached data on error, and the new gate now blocks it
anyway. The branch list clears too.
- **Two places handle stale data, inconsistently.** Repos were emptied
on any error in team mode only, environments never were, and the launch
gate added a third rule on top.
- **A held auto target shows as "Select repo".** While a failed catalog
holds the auto target, the picker label fell back to "Select repo"
instead of showing the held target the way explicit selections are
shown.
- The same-context comparison (`teamId` plus default environment) was
written out twice.

## Fix

- `lib/swr-fetch-error.ts` decides when cached data is still usable.
`isRetryableFetchError` keeps it only for failures without an HTTP
response (network, client-side validation) and for HTTP 408, 429 and
5xx. Every other status, including any not listed, makes it unusable.
`usableFetchData(data, error)` applies that rule. `use-automations` uses
it in place of its own 401/403/404 list.
- `useRepos` and `useEnvironments` apply the rule themselves, so every
consumer gets empty catalogs after a non-retryable failure and keeps
cached rows after a retryable one. The picker no longer knows about
fetch errors: its separate catalog-error launch check and the team-only
rule for repos are both gone. `targetIsAvailable` against the hook
output covers both cases.
- The same-context check is now one `inSelectionContext` value, used by
the launch gate. The "a failed catalog neither confirms nor replaces
this context's target" hold from ColeMurray#2220 still applies, now as
`catalogErrorHoldsTarget`. The selection effect and `pickerTarget` both
use it, so the picker keeps showing a held auto target, the same way
explicit ones are shown.

Behavior change to note: an **explicit** target with cached catalog data
now also stays launchable through transient errors. Before, any error
blocked it. This matches the automations rule and avoids the same
warm-sandbox churn. Explicit targets are still not invalidated on any
catalog error.

## Not changed

The review also said the hold stops a fallback to a healthy catalog's
stored target in the same context. That reproduces only when
localStorage holds a different target than the current auto target. In a
single tab, localStorage always holds the current auto target, so this
needs another tab writing to it. Holding the target until its catalog
recovers is ColeMurray#2220's stated intent, so this is left as is.

## Verified

- New tests, each failing on ColeMurray#2220 and passing here:
- an auto environment target stays launchable through `Error("Failed to
fetch")` and `SwrFetchError(503)`
- an auto repository stays launchable through `SwrFetchError(500)`, in
both workspace and team mode
  - an explicit target stays launchable through `SwrFetchError(503)`
- an auto environment held after a 403 is not launchable and the picker
still shows it
- `swr-fetch-error.test.ts` checks each status code directly.
`use-repos` and `use-environments` tests check that 400/403/404/422 give
empty lists and that 500/503 and network errors keep cached rows; they
fail against the previous hooks.
- Picker tests now mock what the hooks really return after a denial:
`SwrFetchError(403)` with empty catalogs. ColeMurray#2220's auto-environment test
now also checks the held picker display.
- `npm test -w @open-inspect/web`: 194 files / 2120 tests pass. `npm run
typecheck` exits 0. ESLint and Prettier are clean.

---
*Created with
[Open-Inspect](https://open-inspect-prod.vercel.app/session/fc780c804544d079c0a58c7f92151f07)*

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **Bug Fixes**
- Automation data remains visible during temporary fetch errors and is
hidden after access-denied or not-found errors.
- Repository and environment choices remain available during temporary
catalog failures when cached data is usable. Access-denied and other
non-retryable errors no longer expose stale catalog data.
- When a catalog request fails, the session target picker preserves an
existing selection in the same team and environment context, but blocks
launching if that target is unavailable. Selections from a different
context continue to follow the new context’s catalogs.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Rahul Sethuram <rahul.eth@icloud.com>
Co-authored-by: Cole Murray <2492022+ColeMurray@users.noreply.github.com>
Co-authored-by: waclaude <colemurray.cs+ghwaclaude@gmail.com>
…oleMurray#2244)

Builds on ColeMurray#2241 (its commit is included unchanged) and fixes the issues
found in review. Merging this supersedes ColeMurray#2241.

ColeMurray#2241 makes a `ready` sandbox whose bridge dropped wait for the
heartbeat alarm instead of being replaced. But nothing guaranteed that
alarm would fire soon, and the same gap remained for other live
statuses.

## Changes

- **Arm the heartbeat deadline while waiting.** A new `await_reconnect`
spawn action makes the manager schedule an alarm at the heartbeat
staleness deadline: `heartbeatStaleAt(last_heartbeat)`, or immediately
if the heartbeat is already stale. Previously the only alarm might be an
`inactivity_warning` extension 5 minutes out, so a pending prompt could
hang that long. Before ColeMurray#2241 it would have spawned after 60s. The
scheduler keeps the earliest deadline, so this never delays an earlier
alarm.
- **One reconnect rule for every launched, live status.** The separate
`hasConnected` checks for `spawning`/`connecting` and `ready` are
replaced by one check that runs before the per-status branches. It also
covers `snapshotting`, which still fell through to the cooldown check
and spawned. While a checkpoint is in flight, `startupDecision()`
already holds spawns, so this only matters in edge states, but the
shared check covers it at no cost. `pending` is excluded because nothing
has launched yet.
- **Restore client state on the wait.** Callers broadcast
`sandbox_spawning` / `sandbox_warming` before deciding. That makes the
UI show "spawning" and clears sandbox access state. The wait now
re-broadcasts the persisted status, plus `sandbox_access_changed` for
`ready`.
- **Remove `SpawnConfig.readyWaitMs`.** `ready` is only set by
`markSandboxReady`, which needs an authorized runtime event over an
attached socket, and socket accept writes `last_heartbeat` first (pinned
by the `connection-authenticator` attach test). So the age-based `ready`
branch was unreachable. A `ready` row that never connected is now
governed by the 30s spawn cooldown, the same as any other unconnected
generation.
- `heartbeatStaleAt` is shared with `alarm-policy` so both use the same
staleness deadline.

## Tests

`manager-reconnect.test.ts` now covers:
- no replacement for connected `spawning` / `connecting` / `ready` /
`snapshotting` sources, with recent and stale heartbeats
- the exact alarm deadline armed on wait (recent and already-stale
heartbeat)
- the status and access re-broadcast
- end-to-end: an `inactivity_warning` alarm armed 5 minutes out, then a
prompt arms the earlier heartbeat deadline, which retires the source,
and the next prompt restores it
- cooldown-only handling of a `ready` source that never connected

The fake `status` parameter is gone. The stopped/stale/failed restore
cases are kept: they check that the reconnect check runs after restore
for dead statuses.

Against ColeMurray#2241's code, 10 of the 21 cases fail. With this change all
pass.

## Validation

- `npm test -w @open-inspect/control-plane`: 4263 passed
- Sandbox-related integration suites (`prompt-enqueue`,
`sandbox-early-connect`, `sandbox-events`, `sandbox-shutdown`,
`sandbox-state-retention`, `sandbox-vm-reconciliation`,
`session-lifecycle-alarm-recovery`, `websocket-sandbox`): 118 passed.
The full integration run exceeded my 10-minute command limit, so CI
covers the rest.
- control-plane `typecheck`, ESLint and Prettier: clean

---
*Created with
[Open-Inspect](https://open-inspect-prod.vercel.app/session/d378941876d00fede711bc46f29fbc84)*

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Previously connected sandboxes retain their existing status while
awaiting a WebSocket reconnection, rather than being replaced based on
boot status or age.
* Reconnected ready sandboxes continue to report their status to
clients, and heartbeat deadlines are scheduled to retire stale
connections.
* Sandboxes that never connected can still be replaced after the spawn
cooldown.
* Spawn and warm-up announcements are sent only when a launch proceeds,
avoiding misleading notices while a sandbox is queued or reconnecting.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: XuJian <265865031+xujiantop-crypto@users.noreply.github.com>
Co-authored-by: Cole Murray <2492022+ColeMurray@users.noreply.github.com>
Co-authored-by: waclaude <colemurray.cs+ghwaclaude@gmail.com>
ColeMurray and others added 22 commits October 4, 2026 00:21
Adds scheduled Dependabot **version updates**, scoped to the ecosystems
where an automated bump can be validated by CI before merge. Replaces
ColeMurray#1897 (thanks @rhlsthrm for the original proposal — this keeps its
grouping approach and narrows the scope).

Security updates are already enabled in repository settings and are
unaffected; they continue to cover every ecosystem, including the ones
excluded here.

## Schedule

Roughly every two weeks: `cron` on the 1st and 15th at 09:00 UTC.
Dependabot has no biweekly interval and cron can't express "every other
week", so this is the closest equivalent.

All entries use a 7-day `cooldown`, so a release must be at least a week
old before it's proposed. This limits exposure to compromised releases
that are typically pulled within days.

## Scope

| Ecosystem | Directories | Grouping |
|---|---|---|
| npm | `/` (root lockfile spans all workspaces) | minor + patch
grouped; majors individual |
| github-actions | `/` | all grouped |
| uv | `modal-infra`, `e2b-infra`, `daytona-infra`, `sandbox-images` |
minor + patch grouped; majors individual |

## Intentionally excluded

- **`packages/sandbox-runtime` and
`packages/sandbox-images/locks/python-tools` (uv)**: their `uv.lock`
feeds the hash-checked exports `locks/runtime.txt` /
`locks/python-tools.txt`. Dependabot only edits `uv.lock`, so `cli.py
lock --check` fails until someone regenerates the export by hand (see
ColeMurray#2231). `python-tools/pyproject.toml` is also generated from
`toolchain.json`, so Dependabot shouldn't edit it at all.
- **`packages/sandbox-images/locks/{tools,plugins}` (npm)**: pinned
through `toolchain.json`.
- **Terraform**: the plan job needs production secrets that Dependabot
PRs can't read, so plan is skipped, and merges to `main` auto-apply.
Provider bumps should go through a regular branch where the plan runs.
- **Docker / docker-compose**: only a handful of base images, and the
useful bumps are majors that need manual review (e.g. `node:24` →
non-LTS, `litestream` 0.3 → 0.5 config change).

## Verification

- `check-jsonschema --builtin-schema vendor.dependabot
.github/dependabot.yml` passes. Confirmed the schema rejects an invalid
`interval` and unknown `cooldown` keys, so `cron` and `cooldown` are
actually validated.
- `prettier --check` passes.

---
*Created with
[Open-Inspect](https://open-inspect-prod.vercel.app/session/c4ba5bd73ecf4f284f1445eed3cbdcfa)*

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Chores**
* Scheduled update checks are configured for npm, GitHub Actions, and uv
on the 1st and 15th of each month.
* npm and uv minor and patch updates are grouped, with up to five open
update pull requests. GitHub Actions updates are grouped without a
specified limit.
* A seven-day cooldown applies between updates. Checks are configured
for npm at the repository root and uv in the infrastructure and sandbox
image packages.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Cole Murray <2492022+ColeMurray@users.noreply.github.com>
Co-authored-by: waclaude <colemurray.cs+ghwaclaude@gmail.com>
## Problem

`coverage.yml` had no path filters, so every push and PR to `main` ran
all 12 coverage jobs (8 control-plane shards, the merge, web,
shared/bots, Python), including docs-only changes.

## Change

This adds change detection inside the workflow, following the pattern
`compose-smoke.yml` already uses. A trigger-level `paths:` filter would
leave the aggregate `Coverage` check stuck on "Expected" when it is
required for merge, so the workflow stays unfiltered.

- **New `changes` job:** diffs the PR (merge base) or push range and
emits one output per suite: `control-plane`, `web`, `other-ts`,
`python`. If the comparison can't be made (e.g. a force push), every
suite runs.
- **What each suite watches:**
  - its own package(s)
- the coverage gate: the workflow itself, `.nvmrc`,
`scripts/check-coverage.mjs`, `scripts/coverage-policy.ts` and
`scripts/coverage-baseline.json`
- for TypeScript suites, `packages/shared` and the root `package.json`
and lockfile
- files outside the package that its tests actually read or import, e.g.
`vercel-infra`, `sandbox-images`, D1 migrations and
`workers-control-plane.tf` for control-plane; three control-plane
session files for web; `docs/AVAILABLE_MODELS.md` and
`choosing-a-model.mdx` for shared
  - `packages/**/*.md` READMEs are ignored.
- **Each suite job** is gated on its output. The control-plane merge job
is skipped automatically when its shards are skipped.
- **Aggregate `Coverage` job:** accepts `skipped` only when that suite's
output is `false`. If `changes` fails, the check fails. It downloads
only the artifacts of suites that ran, and skips the final upload when
no suite ran.

## Verification

- `prettier --check` passes, and `node --test
scripts/node-version-workflow-contract.test.mjs
scripts/terraform-workflow-contract.test.mjs` passes (4/4).
- I dry-ran the detection step against the last 12 `main` commits:

| Commit type | Before | Now |
|---|---|---|
| Docs-only (`80fd4cc`, `818a259`, `be36560`) | all jobs | none |
| Web-only (`3abc4be`, `4d98ad1`, `d53df53`) | all jobs | web only |
| Control-plane-only (`9bc6a4e`, `d605e35`) | all jobs | control-plane
only |
| Cross-cutting (`a05d417`) | all jobs | all suites |

- An unresolvable diff range runs every suite.

Because this PR changes `coverage.yml`, every suite should run on it.

## Trade-off

The lists of files each suite reads from other packages are maintained
by hand, like the filters in `ci.yml` and `ci-python.yml`. If a test
starts reading a new file elsewhere in the repo, add it to that suite's
list. A comment in the workflow says so.

---
*Created with
[Open-Inspect](https://open-inspect-prod.vercel.app/session/7be0cf65aea1877955532f02fca58ce9)*

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* Coverage checks now run only for suites affected by changes, while
unavailable change comparisons still trigger checks.
* The combined coverage report accounts for skipped suites and is
uploaded when at least one suite runs.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Cole Murray <2492022+ColeMurray@users.noreply.github.com>
…leMurray#2282)

## Summary

Rebuilds the idea behind ColeMurray#619 (per-comment model overrides for the
GitHub bot) on the current codebase. It follows the Slack `!model` /
`!reasoning` flags instead of adding a second directive grammar.

```text
@my-app[bot] !model openai/gpt-5.6-sol !reasoning high investigate the flaky test
```

- **One grammar for both bots.** `parseInlinePromptFlags` moves from
`slack-bot` into a new `@open-inspect/shared/inline-prompt-flags`
module. Slack and GitHub now parse the same syntax: flags must lead the
request, each accepts a space or a colon before its value, and a
duplicate or empty flag is an error. Slack keeps its own turn-plan
resolution in `slack-bot/src/inline-flags.ts`.
- **GitHub comment handling.** `handleIssueComment` and
`handleReviewComment` parse flags from the comment after stripping the
bot mention. The flags are removed from the prompt, and `startSession`
resolves the session's model from the configured defaults plus the
flags.
- Each GitHub comment starts a new session, so the flags become that
session's model settings.
- A model flag must be a known model that is enabled under Settings ›
Models. A model flag without `!reasoning` keeps the configured effort if
the new model supports it; otherwise the session uses the model's
default.
- A reasoning-only flag is checked against the configured model and does
not fetch the enabled-models list.
  - Auto-reviews and review requests are unchanged.
- **Errors are posted on the PR.** For an invalid flag, or when the
enabled-models list can't be loaded, the bot posts a PR comment and
skips session creation. This works like Slack's in-thread error message
and the bot's existing refusal comments. User-supplied values are shown
in code spans, so they can't inject markdown or `@mentions`. Both new
skip reasons are checkpointed in the dispatch dedupe, so a redelivery
doesn't post the comment twice.
- **Control plane.** `GET /model-preferences` now grants actorless reads
to `github-bot`, as it already does for `slack-bot`. GitHub senders may
not have workspace accounts, so the bot reads the list without an actor.
- **Logging.** `session.created` now logs `model`, `reasoning_effort`,
and `inline_model_override`.
- **Docs.** Updated `docs/integrations/GITHUB.md`, the public GitHub
integration page, and the model-defaults table.

### Differences from ColeMurray#619

- **Flags instead of free-floating `model:` / `reasoning:` directives.**
ColeMurray#619 matched directives anywhere in the comment and silently dropped
invalid values. Here flags must lead the request, so prose like "the
model: field" is never captured, and invalid flags get an explicit
reply.
- **No `allowInlineDirectiveOverride` toggle.** Slack has none. Only
enabled models can be chosen, and only users who pass the existing
trigger-user and write-permission gates can trigger the bot.
- **No model aliases.** Neither bot supports `opus`-style aliases today.
Bare ids such as `claude-sonnet-4-6` already normalize.
- **No new settings UI or schema.** The default model and reasoning
settings, plus per-repository overrides, already exist in the GitHub
integration settings.

## Testing

- `npx vitest run` in `packages/github-bot`: 302 passed. New tests:
  - `test/model-selection.test.ts`
- inline-flag cases in `test/handlers.test.ts`, covering both comment
handlers
- a dedupe-checkpoint test in `test/webhook.test.ts`, mutation-checked:
it fails when the skip reason is removed from the checkpoint list
- `npx vitest run` in `packages/slack-bot`: 553 passed.
- Shared tests `src/inline-prompt-flags.test.ts` and
`src/module-boundaries.test.ts`: passed.
- Control plane:
  - unit test `src/router.policy.test.ts`: passed
- integration tests `service-auth`, `model-preferences`,
`hono-route-catalog-conformance`, and `route-admission-matrix`: 75
passed
- `npm test -w @open-inspect/docs`: passed.
- `npm run typecheck` for shared, github-bot, slack-bot, and
control-plane: clean.

Supersedes ColeMurray#619.

---
*Created with
[Open-Inspect](https://open-inspect-prod.vercel.app/session/b6e32d1cc1b67cec7b9245d445dc7d70)*

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* GitHub pull request comments and inline review comments can now begin
with `!model` and `!reasoning` to override the defaults for that
session. Flags support colon or space separators and must appear
together at the start of the request.
* Invalid or unsupported flags receive an explanatory comment, and no
session is started. Automatic reviews and review requests continue to
use configured settings.
* **Documentation**
* Updated the GitHub integration and model-selection guides with flag
syntax, validation behavior, and override scope.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Cole Murray <2492022+ColeMurray@users.noreply.github.com>
…#2283)

## Summary

Adds an October 4, 2026 `CHANGELOG.md` entry for the GitHub `!model` /
`!reasoning` mention flags added in ColeMurray#2282. The entry says to upgrade the
GitHub bot and control plane together, because the bot needs the new
control-plane permission to read the enabled-models list. It links to
the new section in `docs/integrations/GITHUB.md`.

---
*Created with
[Open-Inspect](https://open-inspect-prod.vercel.app/session/b6e32d1cc1b67cec7b9245d445dc7d70)*

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Documentation**
* Added changelog notes on selecting session models and reasoning effort
in GitHub, with controls matching Slack.
* Noted that the GitHub bot and control plane need to be upgraded
together.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Cole Murray <2492022+ColeMurray@users.noreply.github.com>
…oleMurray#2280)

Bumps [mypy](https://github.com/python/mypy) from 1.19.1 to 2.3.1.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/python/mypy/blob/master/CHANGELOG.md">mypy's
changelog</a>.</em></p>
<blockquote>
<h3>Mypy 2.3.1</h3>
<ul>
<li>Fix mypyc crash on double yielding Iterators (Daniël van Noord, PR
<a
href="https://redirect.github.com/python/mypy/pull/21826">21826</a>)</li>
<li>Fix mypyc <code>default_factory</code> for inherited dataclass
(Daniël van Noord, PR <a
href="https://redirect.github.com/python/mypy/pull/21785">21785</a>)</li>
<li>Clear mypyc coroutine env on coroutine completion (Piotr Sawicki, PR
<a
href="https://redirect.github.com/python/mypy/pull/21734">21734</a>)</li>
<li>Fix crash when unpacking return value from overload (Shantanu, PR <a
href="https://redirect.github.com/python/mypy/pull/21830">21830</a>)</li>
</ul>
<h3>Acknowledgements</h3>
<p>Thanks to all mypy contributors who contributed to this release:</p>
<ul>
<li>Agriya Khetarpal</li>
<li>Ethan Sarp</li>
<li>Ivan Levkivskyi</li>
<li>Jingchen Ye</li>
<li>Jukka Lehtosalo</li>
<li>Piotr Sawicki</li>
<li>Shantanu</li>
<li>Tom Bannink</li>
<li>Viktor Szépe</li>
<li>ygale</li>
</ul>
<p>I'd also like to thank my employer, Dropbox, for supporting mypy
development.</p>
<h2>Mypy 2.2</h2>
<p>We've just uploaded mypy 2.2.0 to the Python Package Index (<a
href="https://pypi.org/project/mypy/">PyPI</a>).
Mypy is a static type checker for Python. This release includes new
features, performance
improvements and bug fixes. You can install it as follows:</p>
<pre><code>python3 -m pip install -U mypy
</code></pre>
<p>You can read the full documentation for this release on <a
href="http://mypy.readthedocs.io">Read the Docs</a>.</p>
<h3>Support for Closed TypedDicts (PEP 728)</h3>
<p>Mypy now supports closed TypedDicts as specified in PEP 728. A closed
TypedDict cannot have extra
keys beyond those explicitly defined. This allows the type checker to
determine that certain
operations are safe when they otherwise wouldn't be due to the potential
presence of unknown keys.</p>
<p>You can use the <code>closed</code> keyword argument with
<code>TypedDict</code>:</p>
<pre lang="python"><code>HasName = TypedDict(&quot;HasName&quot;,
{&quot;name&quot;: str})
HasOnlyName = TypedDict(&quot;HasOnlyName&quot;, {&quot;name&quot;:
str}, closed=True)
Movie = TypedDict(&quot;Movie&quot;, {&quot;name&quot;: str,
&quot;year&quot;: int})
<p>movie: Movie = {&quot;name&quot;: &quot;Nimona&quot;,
&quot;year&quot;: 2023}
has_name: HasName = movie  # OK: HasName is open (default)
has_only_name: HasOnlyName = movie # Error: HasOnlyName is closed and
Movie has extra &quot;year&quot; key
&lt;/tr&gt;&lt;/table&gt;
</code></pre></p>
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/python/mypy/commit/d642c4478e9e3acbe9233edbe17ffc569a1a778c"><code>d642c44</code></a>
Bump version to 2.3.1</li>
<li><a
href="https://github.com/python/mypy/commit/a39242983d3c2cb85886a1eb6d5869180672784c"><code>a392429</code></a>
[mypyc] Fix crash on double yielding Iterators (<a
href="https://redirect.github.com/python/mypy/issues/21826">#21826</a>)</li>
<li><a
href="https://github.com/python/mypy/commit/4843e7773e7dc8fe3f1fd1319277d6d11cd6cdb3"><code>4843e77</code></a>
[mypyc] Fix <code>default_factory</code> for inherited dataclass (<a
href="https://redirect.github.com/python/mypy/issues/21785">#21785</a>)</li>
<li><a
href="https://github.com/python/mypy/commit/14f5df93ed8d1be4f4cc9c447eb2e6e619362e05"><code>14f5df9</code></a>
[mypyc] Clear coroutine env on coroutine completion (<a
href="https://redirect.github.com/python/mypy/issues/21734">#21734</a>)</li>
<li><a
href="https://github.com/python/mypy/commit/6dfa06dda6e34912279e498d35a43ba6dc30bfee"><code>6dfa06d</code></a>
Fix crash when unpacking return value from overload (<a
href="https://redirect.github.com/python/mypy/issues/21830">#21830</a>)</li>
<li><a
href="https://github.com/python/mypy/commit/a3857467da126d28b55724e8bb682019df9a503e"><code>a385746</code></a>
Bump version to 2.3.1+dev</li>
<li><a
href="https://github.com/python/mypy/commit/8aabf8435357eaffceca7237f371e293b8168e54"><code>8aabf84</code></a>
Drop +dev from version</li>
<li><a
href="https://github.com/python/mypy/commit/4d8ad2ab5e86c99581b73775f2c00b9b8265b589"><code>4d8ad2a</code></a>
Update changelog for 2.3 release (<a
href="https://redirect.github.com/python/mypy/issues/21728">#21728</a>)</li>
<li><a
href="https://github.com/python/mypy/commit/2c2154672040c52e481f423854d104e6cf172585"><code>2c21546</code></a>
[mypyc] Update documentation of race conditions under free threading (<a
href="https://redirect.github.com/python/mypy/issues/21726">#21726</a>)</li>
<li><a
href="https://github.com/python/mypy/commit/a9f62a3cf98a58a7a2607b7c81695802b39f5edc"><code>a9f62a3</code></a>
[mypyc] Make attribute access memory safe on free-threaded builds (<a
href="https://redirect.github.com/python/mypy/issues/21705">#21705</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/python/mypy/compare/v1.19.1...v2.3.1">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=mypy&package-manager=uv&previous-version=1.19.1&new-version=2.3.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
)

Bumps [lint-staged](https://github.com/lint-staged/lint-staged) from
16.4.0 to 17.6.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/lint-staged/lint-staged/releases">lint-staged's
releases</a>.</em></p>
<blockquote>
<h2>v17.6.0</h2>
<h3>Minor Changes</h3>
<ul>
<li>
<p><a
href="https://redirect.github.com/lint-staged/lint-staged/pull/1850">#1850</a>
<a
href="https://github.com/lint-staged/lint-staged/commit/938d3f43d07cbd74f08052dfb8a7380ce8868180"><code>938d3f4</code></a>
- Task functions like <code>{ title, task }</code> can now use a logger
function <code>log()</code> to emit output while the task runs. By
default, the output will only be visible if the task fails, unless the
<code>--verbose</code> option was used. Additionally, when the task
rejects, the error will be shown in the output.</p>
<pre lang="js"><code>import { defineConfig } from 'lint-staged/config'
<p>export default defineConfig({
'*': {
title: 'Fail if PDF files are committed',
task: async (filepaths, { log }) =&gt; {
const pdfFiles = filepaths.filter((f) =&gt;
f.toLowerCase().endsWith('.pdf'))
if (pdfFiles.length &gt; 0) {
log('PDF files should not be committed: %s', pdfFiles)
throw new Error('Failed')
}
},
},
})
</code></pre></p>
</li>
<li>
<p><a
href="https://redirect.github.com/lint-staged/lint-staged/pull/1854">#1854</a>
<a
href="https://github.com/lint-staged/lint-staged/commit/30562bcbc5267bdb733c257c79c0a65c34465ba3"><code>30562bc</code></a>
- <em>lint-staged</em> now stages changes to <strong>all tracked files
modified by tasks</strong>, including files that weren’t originally
staged or didn’t match the configured globs. This can happen when your
task has side-effects, or it's a function that ignores the staged files
like <code>() =&gt; &quot;prettier --write .&quot;</code>.</p>
<p>If you have unstaged changes in a file and the task also edits that
file, your unstaged changes will be staged too. Use
<code>--hide-unstaged</code> to hide your changes while tasks run.</p>
</li>
</ul>
<h3>Patch Changes</h3>
<ul>
<li>
<p><a
href="https://redirect.github.com/lint-staged/lint-staged/pull/1860">#1860</a>
<a
href="https://github.com/lint-staged/lint-staged/commit/4296532155fb893ab8f754a47f3518f691fd4d98"><code>4296532</code></a>
- The assignment of staged files to <em>lint-staged</em> configuration
files (when using multiple, for example in a monorepo) has been
rewritten to be more efficient. As a reminder, each staged file is
assigned to exactly one configuration (the closest one), even if that
config doesn't match the file in its globs.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/lint-staged/lint-staged/pull/1861">#1861</a>
<a
href="https://github.com/lint-staged/lint-staged/commit/c45f28af47a540730de2bf22fddedeb8fac5952a"><code>c45f28a</code></a>
- Fix running parallel tasks for a single glob, when tasks are created
by a function. Nesting one level of arrays inside an array of tasks will
result in the inner tasks running in parallel. This behavior should now
be consistent when creating tasks using functions. In the following
example <code>eslint</code> and <code>prettier</code> will run in
parallel (for all files, when any JS files are staged):</p>
<pre lang="js"><code>import { defineConfig } from 'lint-staged/config'
<p>export default defineConfig({
'*.js': () =&gt; [['eslint --max-warnings=0 .', 'prettier
--list-different .']],
})
</code></pre></p>
</li>
<li>
<p><a
href="https://redirect.github.com/lint-staged/lint-staged/pull/1859">#1859</a>
<a
href="https://github.com/lint-staged/lint-staged/commit/f0ea69dc67399e504a08db67594f697d4c24df6d"><code>f0ea69d</code></a>
- Various performance improvements from skipping redundant internal Git
calls.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/lint-staged/lint-staged/pull/1856">#1856</a>
<a
href="https://github.com/lint-staged/lint-staged/commit/69d7d17ca6d3b10f2ececf8b2756c1927a627821"><code>69d7d17</code></a>
- Partially staged changes are hidden in a uniquely-named patch file to
avoid multiple invocations of <em>lint-staged</em> overwriting it. This
makes it safer to run <em>lint-staged</em> in multiple worktrees at the
same time.</p>
</li>
</ul>
<h2>v17.5.1</h2>
<h3>Patch Changes</h3>
<ul>
<li>
<p><a
href="https://redirect.github.com/lint-staged/lint-staged/pull/1852">#1852</a>
<a
href="https://github.com/lint-staged/lint-staged/commit/bfcca94e61aef7078a7a0ec8165c0cc2c9baca99"><code>bfcca94</code></a>
- Fix TypeScript issue <code>TS1254</code> from
<code>defineConfig()</code> by changing the signature from
<code>const</code> to a <code>function</code>:</p>
<blockquote>
<p>A 'const' initializer in an ambient context must be a string or
numeric literal or literal enum reference.</p>
</blockquote>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/lint-staged/lint-staged/blob/main/CHANGELOG.md">lint-staged's
changelog</a>.</em></p>
<blockquote>
<h2>17.6.0</h2>
<h3>Minor Changes</h3>
<ul>
<li>
<p><a
href="https://redirect.github.com/lint-staged/lint-staged/pull/1850">#1850</a>
<a
href="https://github.com/lint-staged/lint-staged/commit/938d3f43d07cbd74f08052dfb8a7380ce8868180"><code>938d3f4</code></a>
- Task functions like <code>{ title, task }</code> can now use a logger
function <code>log()</code> to emit output while the task runs. By
default, the output will only be visible if the task fails, unless the
<code>--verbose</code> option was used. Additionally, when the task
rejects, the error will be shown in the output.</p>
<pre lang="js"><code>import { defineConfig } from 'lint-staged/config'
<p>export default defineConfig({
'*': {
title: 'Fail if PDF files are committed',
task: async (filepaths, { log }) =&gt; {
const pdfFiles = filepaths.filter((f) =&gt;
f.toLowerCase().endsWith('.pdf'))
if (pdfFiles.length &gt; 0) {
log('PDF files should not be committed: %s', pdfFiles)
throw new Error('Failed')
}
},
},
})
</code></pre></p>
</li>
<li>
<p><a
href="https://redirect.github.com/lint-staged/lint-staged/pull/1854">#1854</a>
<a
href="https://github.com/lint-staged/lint-staged/commit/30562bcbc5267bdb733c257c79c0a65c34465ba3"><code>30562bc</code></a>
- <em>lint-staged</em> now stages changes to <strong>all tracked files
modified by tasks</strong>, including files that weren’t originally
staged or didn’t match the configured globs. This can happen when your
task has side-effects, or it's a function that ignores the staged files
like <code>() =&gt; &quot;prettier --write .&quot;</code>.</p>
<p>If you have unstaged changes in a file and the task also edits that
file, your unstaged changes will be staged too. Use
<code>--hide-unstaged</code> to hide your changes while tasks run.</p>
</li>
</ul>
<h3>Patch Changes</h3>
<ul>
<li>
<p><a
href="https://redirect.github.com/lint-staged/lint-staged/pull/1860">#1860</a>
<a
href="https://github.com/lint-staged/lint-staged/commit/4296532155fb893ab8f754a47f3518f691fd4d98"><code>4296532</code></a>
- The assignment of staged files to <em>lint-staged</em> configuration
files (when using multiple, for example in a monorepo) has been
rewritten to be more efficient. As a reminder, each staged file is
assigned to exactly one configuration (the closest one), even if that
config doesn't match the file in its globs.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/lint-staged/lint-staged/pull/1861">#1861</a>
<a
href="https://github.com/lint-staged/lint-staged/commit/c45f28af47a540730de2bf22fddedeb8fac5952a"><code>c45f28a</code></a>
- Fix running parallel tasks for a single glob, when tasks are created
by a function. Nesting one level of arrays inside an array of tasks will
result in the inner tasks running in parallel. This behavior should now
be consistent when creating tasks using functions. In the following
example <code>eslint</code> and <code>prettier</code> will run in
parallel (for all files, when any JS files are staged):</p>
<pre lang="js"><code>import { defineConfig } from 'lint-staged/config'
<p>export default defineConfig({
'*.js': () =&gt; [['eslint --max-warnings=0 .', 'prettier
--list-different .']],
})
</code></pre></p>
</li>
<li>
<p><a
href="https://redirect.github.com/lint-staged/lint-staged/pull/1859">#1859</a>
<a
href="https://github.com/lint-staged/lint-staged/commit/f0ea69dc67399e504a08db67594f697d4c24df6d"><code>f0ea69d</code></a>
- Various performance improvements from skipping redundant internal Git
calls.</p>
</li>
<li>
<p><a
href="https://redirect.github.com/lint-staged/lint-staged/pull/1856">#1856</a>
<a
href="https://github.com/lint-staged/lint-staged/commit/69d7d17ca6d3b10f2ececf8b2756c1927a627821"><code>69d7d17</code></a>
- Partially staged changes are hidden in a uniquely-named patch file to
avoid multiple invocations of <em>lint-staged</em> overwriting it. This
makes it safer to run <em>lint-staged</em> in multiple worktrees at the
same time.</p>
</li>
</ul>
<h2>17.5.1</h2>
<h3>Patch Changes</h3>
<ul>
<li><a
href="https://redirect.github.com/lint-staged/lint-staged/pull/1852">#1852</a>
<a
href="https://github.com/lint-staged/lint-staged/commit/bfcca94e61aef7078a7a0ec8165c0cc2c9baca99"><code>bfcca94</code></a>
- Fix TypeScript issue <code>TS1254</code> from
<code>defineConfig()</code> by changing the signature from
<code>const</code> to a <code>function</code>:</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/lint-staged/lint-staged/commit/48f9f4ea4b88eb605de3546e4599083de7a394b2"><code>48f9f4e</code></a>
Merge pull request <a
href="https://redirect.github.com/lint-staged/lint-staged/issues/1857">#1857</a>
from lint-staged/changeset-release/main</li>
<li><a
href="https://github.com/lint-staged/lint-staged/commit/16b2e213efeec330f7e1576a8d35776822bf698a"><code>16b2e21</code></a>
chore(changeset): release</li>
<li><a
href="https://github.com/lint-staged/lint-staged/commit/195f15677da877431b63dfd001e1ed9369bb1479"><code>195f156</code></a>
docs: improve changeset</li>
<li><a
href="https://github.com/lint-staged/lint-staged/commit/0ba6261cabfdade60e487385ebec4fc2b4b44309"><code>0ba6261</code></a>
fix: create hidden directory only when required</li>
<li><a
href="https://github.com/lint-staged/lint-staged/commit/66ac2de6f71d19256cc5d11026d37e653af11549"><code>66ac2de</code></a>
docs: fixes to changesets</li>
<li><a
href="https://github.com/lint-staged/lint-staged/commit/80af8d7f8246c4246cdf8b53229bd1bf7763f959"><code>80af8d7</code></a>
Merge pull request <a
href="https://redirect.github.com/lint-staged/lint-staged/issues/1863">#1863</a>
from lint-staged/fix-issues</li>
<li><a
href="https://github.com/lint-staged/lint-staged/commit/e4334881d49d94669bc2b2fb5a73705d822c69bb"><code>e433488</code></a>
fix: handle task editing a symlinked file to a regular file, and
--fail-on-ch...</li>
<li><a
href="https://github.com/lint-staged/lint-staged/commit/e5019b32138e301c777c683f95e4a1e17362845f"><code>e5019b3</code></a>
fix: handle trailing newlines when detecting changed files</li>
<li><a
href="https://github.com/lint-staged/lint-staged/commit/74efec85fa276618837d3c4602062ef30d16abf1"><code>74efec8</code></a>
ci: run Cygwin and MSYS2 tests on Node.js 26</li>
<li><a
href="https://github.com/lint-staged/lint-staged/commit/655b7dcd9f7eb57a6f574f03be371190afeb9f5c"><code>655b7dc</code></a>
fix: use TypeScript types instead of JSDoc</li>
<li>Additional commits viewable in <a
href="https://github.com/lint-staged/lint-staged/compare/v16.4.0...v17.6.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=lint-staged&package-manager=npm_and_yarn&previous-version=16.4.0&new-version=17.6.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…oleMurray#2275)

Bumps
[@testing-library/jest-dom](https://github.com/testing-library/jest-dom)
from 6.9.1 to 7.0.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/testing-library/jest-dom/releases">@​testing-library/jest-dom's
releases</a>.</em></p>
<blockquote>
<h2>v7.0.1</h2>
<h2><a
href="https://github.com/testing-library/jest-dom/compare/v7.0.0...v7.0.1">7.0.1</a>
(2026-08-09)</h2>
<h3>Bug Fixes</h3>
<ul>
<li>declare vitest as an optional peer dependency (<a
href="https://redirect.github.com/testing-library/jest-dom/issues/733">#733</a>)
(<a
href="https://github.com/testing-library/jest-dom/commit/3782c78b3dc9824675afe0cb8f1722f8c96f494d">3782c78</a>)</li>
</ul>
<h2>v7.0.0</h2>
<h1><a
href="https://github.com/testing-library/jest-dom/compare/v6.10.0...v7.0.0">7.0.0</a>
(2026-07-20)</h1>
<h3>Features</h3>
<ul>
<li>add toContainAnyBy* and toContainOneBy* query matchers (<a
href="https://github.com/testing-library/jest-dom/commit/1e39089d850408a583c83495d00d8aa27078933f">1e39089</a>)</li>
</ul>
<h3>BREAKING CHANGES</h3>
<ul>
<li><code>@​testing-library/dom</code> is now a required peer
dependency. The minimum supported
Node.js version is now 22.</li>
</ul>
<p>Repaired release for <a
href="https://redirect.github.com/testing-library/jest-dom/pull/731">testing-library/jest-dom#731</a></p>
<h2>v6.10.0</h2>
<h1><a
href="https://github.com/testing-library/jest-dom/compare/v6.9.1...v6.10.0">6.10.0</a>
(2026-07-20)</h1>
<h3>Features</h3>
<ul>
<li>add toContainAnyBy* and toContainOneBy* query matchers (<a
href="https://redirect.github.com/testing-library/jest-dom/issues/731">#731</a>)
(<a
href="https://github.com/testing-library/jest-dom/commit/cae44df901cf8e92e3febc0af6fa667b10be6d6a">cae44df</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/testing-library/jest-dom/commit/3782c78b3dc9824675afe0cb8f1722f8c96f494d"><code>3782c78</code></a>
fix: declare vitest as an optional peer dependency (<a
href="https://redirect.github.com/testing-library/jest-dom/issues/733">#733</a>)</li>
<li><a
href="https://github.com/testing-library/jest-dom/commit/1e39089d850408a583c83495d00d8aa27078933f"><code>1e39089</code></a>
feat: add toContainAnyBy* and toContainOneBy* query matchers</li>
<li><a
href="https://github.com/testing-library/jest-dom/commit/cae44df901cf8e92e3febc0af6fa667b10be6d6a"><code>cae44df</code></a>
feat: add toContainAnyBy* and toContainOneBy* query matchers (<a
href="https://redirect.github.com/testing-library/jest-dom/issues/731">#731</a>)</li>
<li><a
href="https://github.com/testing-library/jest-dom/commit/55c07ce5f1c489b5b9dc31a770a84d83a1178072"><code>55c07ce</code></a>
ci: switch release to npm trusted publishing (<a
href="https://redirect.github.com/testing-library/jest-dom/issues/726">#726</a>)</li>
<li><a
href="https://github.com/testing-library/jest-dom/commit/213256fa8e0aff45e47920a0bc564f708d1f67de"><code>213256f</code></a>
docs: move toHaveSelection from the deprecated section (<a
href="https://redirect.github.com/testing-library/jest-dom/issues/717">#717</a>)</li>
<li>See full diff in <a
href="https://github.com/testing-library/jest-dom/compare/v6.9.1...v7.0.1">compare
view</a></li>
</ul>
</details>
<details>
<summary>Maintainer changes</summary>
<p>This version was pushed to npm by <a
href="https://www.npmjs.com/~GitHub%20Actions">GitHub Actions</a>, a new
releaser for <code>@​testing-library/jest-dom</code> since your current
version.</p>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@testing-library/jest-dom&package-manager=npm_and_yarn&previous-version=6.9.1&new-version=7.0.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…ColeMurray#2272)

Bumps the actions group with 7 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [actions/checkout](https://github.com/actions/checkout) | `6` | `7` |
| [actions/setup-python](https://github.com/actions/setup-python) | `6`
| `7` |
| [actions/setup-node](https://github.com/actions/setup-node) | `6` |
`7` |
| [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) | `6` |
`7` |
| [actions/upload-artifact](https://github.com/actions/upload-artifact)
| `4` | `7` |
|
[actions/download-artifact](https://github.com/actions/download-artifact)
| `4` | `8` |
| [actions/github-script](https://github.com/actions/github-script) |
`8` | `9` |


Updates `actions/checkout` from 6 to 7
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/releases">actions/checkout's
releases</a>.</em></p>
<blockquote>
<h2>v7.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>block checking out fork pr for pull_request_target and workflow_run
by <a href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2454">actions/checkout#2454</a></li>
<li>Bump actions/publish-immutable-action from 0.0.3 to 0.0.4 in the
minor-actions-dependencies group across 1 directory by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2458">actions/checkout#2458</a></li>
<li>Bump flatted from 3.3.1 to 3.4.2 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2460">actions/checkout#2460</a></li>
<li>Bump js-yaml from 4.1.0 to 4.2.0 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2461">actions/checkout#2461</a></li>
<li>Bump <code>@​actions/core</code> and
<code>@​actions/tool-cache</code> and Remove uuid by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2459">actions/checkout#2459</a></li>
<li>upgrade module to esm and update dependencies by <a
href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2463">actions/checkout#2463</a></li>
<li>Bump the minor-npm-dependencies group across 1 directory with 3
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2462">actions/checkout#2462</a></li>
<li>getting ready for checkout v7 release by <a
href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2464">actions/checkout#2464</a></li>
<li>update error wording by <a
href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2467">actions/checkout#2467</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/2454">actions/checkout#2454</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v6.0.3...v7.0.0">https://github.com/actions/checkout/compare/v6.0.3...v7.0.0</a></p>
<h2>v6.1.0</h2>
<h2>What's Changed</h2>
<ul>
<li><strong>[BREAKING]</strong> backport
<code>allow-unsafe-pr-checkout</code> to v6 by <a
href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2500">actions/checkout#2500</a></li>
<li>backport fixes to releases-v6 by <a
href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2527">actions/checkout#2527</a></li>
</ul>
<p><a
href="https://github.blog/changelog/2026-06-18-safer-pull_request_target-defaults-for-github-actions-checkout/">https://github.blog/changelog/2026-06-18-safer-pull_request_target-defaults-for-github-actions-checkout/</a>
for more details about this breaking change</p>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v6.0.3...v6.1.0">https://github.com/actions/checkout/compare/v6.0.3...v6.1.0</a></p>
<h2>v6.0.3</h2>
<h2>What's Changed</h2>
<ul>
<li>Update changelog by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2357">actions/checkout#2357</a></li>
<li>fix: expand merge commit SHA regex and add SHA-256 test cases by <a
href="https://github.com/yaananth"><code>@​yaananth</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2414">actions/checkout#2414</a></li>
<li>Fix checkout init for SHA-256 repositories by <a
href="https://github.com/yaananth"><code>@​yaananth</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2439">actions/checkout#2439</a></li>
<li>Update changelog for v6.0.3 by <a
href="https://github.com/yaananth"><code>@​yaananth</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2446">actions/checkout#2446</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/yaananth"><code>@​yaananth</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/2414">actions/checkout#2414</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v6...v6.0.3">https://github.com/actions/checkout/compare/v6...v6.0.3</a></p>
<h2>v6.0.2</h2>
<h2>What's Changed</h2>
<ul>
<li>Add orchestration_id to git user-agent when ACTIONS_ORCHESTRATION_ID
is set by <a
href="https://github.com/TingluoHuang"><code>@​TingluoHuang</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2355">actions/checkout#2355</a></li>
<li>Fix tag handling: preserve annotations and explicit fetch-tags by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2356">actions/checkout#2356</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v6.0.1...v6.0.2">https://github.com/actions/checkout/compare/v6.0.1...v6.0.2</a></p>
<h2>v6.0.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Update all references from v5 and v4 to v6 by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2314">actions/checkout#2314</a></li>
<li>Add worktree support for persist-credentials includeIf by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2327">actions/checkout#2327</a></li>
<li>Clarify v6 README by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2328">actions/checkout#2328</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/blob/main/CHANGELOG.md">actions/checkout's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<h2>v7.0.1</h2>
<ul>
<li>Skip running unsafe pr check if input is default by <a
href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2518">actions/checkout#2518</a></li>
<li>Trim only ascii whitespace for branch by <a
href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2521">actions/checkout#2521</a></li>
<li>Escape values passed to --unset by <a
href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2530">actions/checkout#2530</a></li>
<li>Various dependency updates</li>
</ul>
<h2>v7.0.0</h2>
<ul>
<li>Block checking out fork PR for pull_request_target and workflow_run
by <a href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2454">actions/checkout#2454</a></li>
<li>Various dependency updates</li>
</ul>
<h2>v6.0.3</h2>
<ul>
<li>Fix checkout init for SHA-256 repositories by <a
href="https://github.com/yaananth"><code>@​yaananth</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2439">actions/checkout#2439</a></li>
<li>fix: expand merge commit SHA regex and add SHA-256 test cases by <a
href="https://github.com/yaananth"><code>@​yaananth</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2414">actions/checkout#2414</a></li>
</ul>
<h2>v6.0.2</h2>
<ul>
<li>Fix tag handling: preserve annotations and explicit fetch-tags by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2356">actions/checkout#2356</a></li>
</ul>
<h2>v6.0.1</h2>
<ul>
<li>Add worktree support for persist-credentials includeIf by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2327">actions/checkout#2327</a></li>
</ul>
<h2>v6.0.0</h2>
<ul>
<li>Persist creds to a separate file by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2286">actions/checkout#2286</a></li>
<li>Update README to include Node.js 24 support details and requirements
by <a href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2248">actions/checkout#2248</a></li>
</ul>
<h2>v5.0.1</h2>
<ul>
<li>Port v6 cleanup to v5 by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2301">actions/checkout#2301</a></li>
</ul>
<h2>v5.0.0</h2>
<ul>
<li>Update actions checkout to use node 24 by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2226">actions/checkout#2226</a></li>
</ul>
<h2>v4.3.1</h2>
<ul>
<li>Port v6 cleanup to v4 by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2305">actions/checkout#2305</a></li>
</ul>
<h2>v4.3.0</h2>
<ul>
<li>docs: update README.md by <a
href="https://github.com/motss"><code>@​motss</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1971">actions/checkout#1971</a></li>
<li>Add internal repos for checking out multiple repositories by <a
href="https://github.com/mouismail"><code>@​mouismail</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1977">actions/checkout#1977</a></li>
<li>Documentation update - add recommended permissions to Readme by <a
href="https://github.com/benwells"><code>@​benwells</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2043">actions/checkout#2043</a></li>
<li>Adjust positioning of user email note and permissions heading by <a
href="https://github.com/joshmgross"><code>@​joshmgross</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2044">actions/checkout#2044</a></li>
<li>Update README.md by <a
href="https://github.com/nebuk89"><code>@​nebuk89</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2194">actions/checkout#2194</a></li>
<li>Update CODEOWNERS for actions by <a
href="https://github.com/TingluoHuang"><code>@​TingluoHuang</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2224">actions/checkout#2224</a></li>
<li>Update package dependencies by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2236">actions/checkout#2236</a></li>
</ul>
<h2>v4.2.2</h2>
<ul>
<li><code>url-helper.ts</code> now leverages well-known environment
variables by <a href="https://github.com/jww3"><code>@​jww3</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/1941">actions/checkout#1941</a></li>
<li>Expand unit test coverage for <code>isGhes</code> by <a
href="https://github.com/jww3"><code>@​jww3</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1946">actions/checkout#1946</a></li>
</ul>
<h2>v4.2.1</h2>
<ul>
<li>Check out other refs/* by commit if provided, fall back to ref by <a
href="https://github.com/orhantoy"><code>@​orhantoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1924">actions/checkout#1924</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/checkout/commit/3d3c42e5aac5ba805825da76410c181273ba90b1"><code>3d3c42e</code></a>
prep v7.0.1 release (<a
href="https://redirect.github.com/actions/checkout/issues/2531">#2531</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/28802689a136bfcdb721715abd713740beecbe07"><code>2880268</code></a>
escape values passed to --unset (<a
href="https://redirect.github.com/actions/checkout/issues/2530">#2530</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/12cd2235efa0937479335606d7c3ac9f6c0973b1"><code>12cd223</code></a>
trim only ascii whitespace for branch (<a
href="https://redirect.github.com/actions/checkout/issues/2521">#2521</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/62661c4e71a304b2823ed026347b8d34c3eac541"><code>62661c4</code></a>
skip running unsafe pr check if input is default (<a
href="https://redirect.github.com/actions/checkout/issues/2518">#2518</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/e8d4307400f9427dba7cb98e488d6ab85f1cec5f"><code>e8d4307</code></a>
Bump the minor-actions-dependencies group with 2 updates (<a
href="https://redirect.github.com/actions/checkout/issues/2499">#2499</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/631c942040754b6e095e929c1677c07e10ed4f87"><code>631c942</code></a>
eslint 9 (<a
href="https://redirect.github.com/actions/checkout/issues/2474">#2474</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/4f1f4aec02e41874fa0262ea8ff5172d7978ad1e"><code>4f1f4ae</code></a>
Bump actions/upload-artifact from 4 to 7 (<a
href="https://redirect.github.com/actions/checkout/issues/2476">#2476</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/ba097532fb203f7e88c9c3c0b899b49469908a92"><code>ba09753</code></a>
Bump actions/checkout from 6 to 7 (<a
href="https://redirect.github.com/actions/checkout/issues/2488">#2488</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/b9e0990d219a03df7633c93f6f005a8fecbcab22"><code>b9e0990</code></a>
Bump docker/login-action from 3.3.0 to 4.2.0 (<a
href="https://redirect.github.com/actions/checkout/issues/2479">#2479</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/e8cb398be4a550817e382abf69e4c12c76fce1f2"><code>e8cb398</code></a>
Bump docker/build-push-action from 6.5.0 to 7.2.0 (<a
href="https://redirect.github.com/actions/checkout/issues/2478">#2478</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/checkout/compare/v6...v7">compare
view</a></li>
</ul>
</details>
<br />

Updates `actions/setup-python` from 6 to 7
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/setup-python/releases">actions/setup-python's
releases</a>.</em></p>
<blockquote>
<h2>v7.0.0</h2>
<h2>What's Changed</h2>
<h3>Enhancements</h3>
<ul>
<li>Migrate to ESM and upgrade dependencies by <a
href="https://github.com/priyagupta108"><code>@​priyagupta108</code></a>
in <a
href="https://redirect.github.com/actions/setup-python/pull/1330">actions/setup-python#1330</a></li>
<li>Pin SHA commits and update docs with latest versions by <a
href="https://github.com/HarithaVattikuti"><code>@​HarithaVattikuti</code></a>
in <a
href="https://redirect.github.com/actions/setup-python/pull/1338">actions/setup-python#1338</a></li>
<li>Remove the pip-install input by <a
href="https://github.com/gowridurgad"><code>@​gowridurgad</code></a> in
<a
href="https://redirect.github.com/actions/setup-python/pull/1336">actions/setup-python#1336</a></li>
</ul>
<h3>Bug Fix</h3>
<ul>
<li>Fix to Classify stderr warning messages as warnings instead of
errors in annotations by <a
href="https://github.com/lmvysakh"><code>@​lmvysakh</code></a> in <a
href="https://redirect.github.com/actions/setup-python/pull/1335">actions/setup-python#1335</a></li>
<li>Validate and retry manifest fetch to prevent silent failures by <a
href="https://github.com/priyagupta108"><code>@​priyagupta108</code></a>
in <a
href="https://redirect.github.com/actions/setup-python/pull/1332">actions/setup-python#1332</a></li>
</ul>
<h3>Dependency Upgrade</h3>
<ul>
<li>Bump certifi from 2020.6.20 to 2024.7.4 in
/<strong>tests</strong>/data by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/setup-python/pull/1328">actions/setup-python#1328</a></li>
<li>Remove EOL Python versions and Bumps numpy text fixture by <a
href="https://github.com/priya-kinthali"><code>@​priya-kinthali</code></a>
in <a
href="https://redirect.github.com/actions/setup-python/pull/1333">actions/setup-python#1333</a></li>
<li>Upgrade <code>@​actions/cache</code> to 6.2.0 by <a
href="https://github.com/philip-gai"><code>@​philip-gai</code></a> in <a
href="https://redirect.github.com/actions/setup-python/pull/1337">actions/setup-python#1337</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/lmvysakh"><code>@​lmvysakh</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/setup-python/pull/1335">actions/setup-python#1335</a></li>
<li><a
href="https://github.com/philip-gai"><code>@​philip-gai</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/setup-python/pull/1337">actions/setup-python#1337</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/setup-python/compare/v6...v7.0.0">https://github.com/actions/setup-python/compare/v6...v7.0.0</a></p>
<h2>v6.3.0</h2>
<h2>What's Changed</h2>
<h3>Enhancement</h3>
<ul>
<li>Add RHEL support and include Linux distro in cache keys by <a
href="https://github.com/priyagupta108"><code>@​priyagupta108</code></a>
in <a
href="https://redirect.github.com/actions/setup-python/pull/1323">actions/setup-python#1323</a></li>
<li>Fix pip cache error handling on Windows by <a
href="https://github.com/priyagupta108"><code>@​priyagupta108</code></a>
in <a
href="https://redirect.github.com/actions/setup-python/pull/1040">actions/setup-python#1040</a></li>
</ul>
<h3>Dependency update</h3>
<ul>
<li>Upgrade minimatch from 3.1.2 to 3.1.5 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/setup-python/pull/1281">actions/setup-python#1281</a></li>
<li>Upgrade actions dependencies by <a
href="https://github.com/gowridurgad"><code>@​gowridurgad</code></a>
with <a href="https://github.com/Copilot"><code>@​Copilot</code></a> in
<a
href="https://redirect.github.com/actions/setup-python/pull/1303">actions/setup-python#1303</a></li>
<li>Upgrade <code>@​actions/cache</code> to 5.1.0, log cache write
denied by <a
href="https://github.com/jasongin"><code>@​jasongin</code></a> in <a
href="https://redirect.github.com/actions/setup-python/pull/1324">actions/setup-python#1324</a></li>
<li>Upgrade dependency versions and test workflow configuration by <a
href="https://github.com/HarithaVattikuti"><code>@​HarithaVattikuti</code></a>
in <a
href="https://redirect.github.com/actions/setup-python/pull/1322">actions/setup-python#1322</a></li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Update advanced-usage.md by <a
href="https://github.com/Dunky-Z"><code>@​Dunky-Z</code></a> in <a
href="https://redirect.github.com/actions/setup-python/pull/811">actions/setup-python#811</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/gowridurgad"><code>@​gowridurgad</code></a>
with <a href="https://github.com/Copilot"><code>@​Copilot</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/setup-python/pull/1303">actions/setup-python#1303</a></li>
<li><a href="https://github.com/jasongin"><code>@​jasongin</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/setup-python/pull/1324">actions/setup-python#1324</a></li>
<li><a href="https://github.com/Dunky-Z"><code>@​Dunky-Z</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/setup-python/pull/811">actions/setup-python#811</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/setup-python/compare/v6.2.0...v6.3.0">https://github.com/actions/setup-python/compare/v6.2.0...v6.3.0</a></p>
<h2>v6.2.0</h2>
<h2>What's Changed</h2>
<h3>Dependency Upgrades</h3>
<ul>
<li>Upgrade dependencies to Node 24 compatible versions by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/setup-python/pull/1259">actions/setup-python#1259</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/setup-python/commit/5fda3b95a4ea91299a34e894583c3862153e4b97"><code>5fda3b9</code></a>
Pin SHA commits and update docs with latest versions (<a
href="https://redirect.github.com/actions/setup-python/issues/1338">#1338</a>)</li>
<li><a
href="https://github.com/actions/setup-python/commit/4ab7e95f05e168b4356aebde89dd84f59c283d8e"><code>4ab7e95</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/setup-python/issues/1337">#1337</a>
from actions/philip-gai/bump-actions-cache-6-2-0</li>
<li><a
href="https://github.com/actions/setup-python/commit/0f3a009f475dbea83c0371cd85d099690fee8c5c"><code>0f3a009</code></a>
Remove the pip-install input (<a
href="https://redirect.github.com/actions/setup-python/issues/1336">#1336</a>)</li>
<li><a
href="https://github.com/actions/setup-python/commit/f8cf4291c8b8e273ddd26e569454615c7315d932"><code>f8cf429</code></a>
Migrate to ESM and upgrade dependencies (<a
href="https://redirect.github.com/actions/setup-python/issues/1330">#1330</a>)</li>
<li><a
href="https://github.com/actions/setup-python/commit/54baeea5b34417d10a7479663a23cca53ea209b5"><code>54baeea</code></a>
Validate and retry manifest fetch to prevent silent failures (<a
href="https://redirect.github.com/actions/setup-python/issues/1332">#1332</a>)</li>
<li><a
href="https://github.com/actions/setup-python/commit/c7092773a316760f4ecfe498e4af668a4dafeac5"><code>c709277</code></a>
Annotation code fix (<a
href="https://redirect.github.com/actions/setup-python/issues/1335">#1335</a>)</li>
<li><a
href="https://github.com/actions/setup-python/commit/6849080452e69b330395e8a6d23cf90f56d76a1a"><code>6849080</code></a>
remove EOL Python versions and Bumps numpy text fixture (<a
href="https://redirect.github.com/actions/setup-python/issues/1333">#1333</a>)</li>
<li><a
href="https://github.com/actions/setup-python/commit/0903b469fbf4441aadfe4f4b249dc5b1fba3a73e"><code>0903b46</code></a>
Bump certifi from 2020.6.20 to 2024.7.4 in /<strong>tests</strong>/data
(<a
href="https://redirect.github.com/actions/setup-python/issues/1328">#1328</a>)</li>
<li>See full diff in <a
href="https://github.com/actions/setup-python/compare/v6...v7">compare
view</a></li>
</ul>
</details>
<br />

Updates `actions/setup-node` from 6 to 7
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/setup-node/releases">actions/setup-node's
releases</a>.</em></p>
<blockquote>
<h2>v7.0.0</h2>
<h2>What's Changed</h2>
<h3>Enhancements:</h3>
<ul>
<li>Add cache-primary-key and cache-matched-key as outputs by <a
href="https://github.com/gowridurgad"><code>@​gowridurgad</code></a> in
<a
href="https://redirect.github.com/actions/setup-node/pull/1577">actions/setup-node#1577</a></li>
<li>Migrate to ESM and upgrade dependencies by <a
href="https://github.com/gowridurgad"><code>@​gowridurgad</code></a> in
<a
href="https://redirect.github.com/actions/setup-node/pull/1574">actions/setup-node#1574</a></li>
</ul>
<h3>Bug fixes:</h3>
<ul>
<li>Remove dummy NODE_AUTH_TOKEN export by <a
href="https://github.com/gowridurgad"><code>@​gowridurgad</code></a> in
<a
href="https://redirect.github.com/actions/setup-node/pull/1558">actions/setup-node#1558</a></li>
<li>Only use <code>mirrorToken</code> in <code>getManifest</code> if
it's provided by <a
href="https://github.com/deiga"><code>@​deiga</code></a> in <a
href="https://redirect.github.com/actions/setup-node/pull/1548">actions/setup-node#1548</a></li>
</ul>
<h3>Documentation updates:</h3>
<ul>
<li>Add documentation for publishing to npm with Trusted Publisher
(OIDC) by <a
href="https://github.com/chiranjib-swain"><code>@​chiranjib-swain</code></a>
in <a
href="https://redirect.github.com/actions/setup-node/pull/1536">actions/setup-node#1536</a></li>
<li>docs: Update restore-only cache documentation by <a
href="https://github.com/priya-kinthali"><code>@​priya-kinthali</code></a>
in <a
href="https://redirect.github.com/actions/setup-node/pull/1550">actions/setup-node#1550</a></li>
<li>docs: Update caching recommendations to mitigate cache poisoning
risks by <a
href="https://github.com/chiranjib-swain"><code>@​chiranjib-swain</code></a>
in <a
href="https://redirect.github.com/actions/setup-node/pull/1567">actions/setup-node#1567</a></li>
</ul>
<h3>Dependency update:</h3>
<ul>
<li>Upgrade <code>@​actions/cache</code> to 5.1.0, log cache write
denied by <a
href="https://github.com/jasongin"><code>@​jasongin</code></a> in <a
href="https://redirect.github.com/actions/setup-node/pull/1569">actions/setup-node#1569</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/chiranjib-swain"><code>@​chiranjib-swain</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/setup-node/pull/1536">actions/setup-node#1536</a></li>
<li><a href="https://github.com/deiga"><code>@​deiga</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/setup-node/pull/1548">actions/setup-node#1548</a></li>
<li><a href="https://github.com/jasongin"><code>@​jasongin</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/setup-node/pull/1569">actions/setup-node#1569</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/setup-node/compare/v6...v7.0.0">https://github.com/actions/setup-node/compare/v6...v7.0.0</a></p>
<h2>v6.5.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Update <code>@​actions/cache</code> to 5.1.0 and add security
overrides for undici and fast-xml-parser by <a
href="https://github.com/HarithaVattikuti"><code>@​HarithaVattikuti</code></a>
in <a
href="https://redirect.github.com/actions/setup-node/pull/1579">actions/setup-node#1579</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/setup-node/compare/v6.4.0...v6.5.0">https://github.com/actions/setup-node/compare/v6.4.0...v6.5.0</a></p>
<h2>v6.4.0</h2>
<h2>What's Changed</h2>
<h3>Dependency updates:</h3>
<ul>
<li>Upgrade <a
href="https://github.com/actions"><code>@​actions</code></a>
dependencies by <a
href="https://github.com/Copilot"><code>@​Copilot</code></a> in <a
href="https://redirect.github.com/actions/setup-node/pull/1525">actions/setup-node#1525</a></li>
<li>Update Node.js versions in versions.yml and bump package to v6.4.0
by <a
href="https://github.com/priya-kinthali"><code>@​priya-kinthali</code></a>
in <a
href="https://redirect.github.com/actions/setup-node/pull/1533">actions/setup-node#1533</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/Copilot"><code>@​Copilot</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/setup-node/pull/1525">actions/setup-node#1525</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/setup-node/compare/v6...v6.4.0">https://github.com/actions/setup-node/compare/v6...v6.4.0</a></p>
<h2>v6.3.0</h2>
<h2>What's Changed</h2>
<h3>Enhancements:</h3>
<ul>
<li>Support parsing <code>devEngines</code> field by <a
href="https://github.com/susnux"><code>@​susnux</code></a> in <a
href="https://redirect.github.com/actions/setup-node/pull/1283">actions/setup-node#1283</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/setup-node/commit/820762786026740c76f36085b0efc47a31fe5020"><code>8207627</code></a>
Migrate to ESM and upgrade dependencies (<a
href="https://redirect.github.com/actions/setup-node/issues/1574">#1574</a>)</li>
<li><a
href="https://github.com/actions/setup-node/commit/04be95cf3511ea51ebf9f224ddfb99cc7ab87cd4"><code>04be95c</code></a>
Add cache-primary-key and cache-matched-key as outputs (<a
href="https://redirect.github.com/actions/setup-node/issues/1577">#1577</a>)</li>
<li><a
href="https://github.com/actions/setup-node/commit/7c2c68d20d402ed6a201ada70a81341941093140"><code>7c2c68d</code></a>
docs: Update caching recommendations to mitigate cache poisoning risks
(<a
href="https://redirect.github.com/actions/setup-node/issues/1567">#1567</a>)</li>
<li><a
href="https://github.com/actions/setup-node/commit/6a61c0375d66246de94630495909f12cf8dac84d"><code>6a61c03</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/setup-node/issues/1569">#1569</a>
from jasongin/update-actions-cache-5.1.0</li>
<li><a
href="https://github.com/actions/setup-node/commit/30eb73b41ded577900c1ebf968ef95cdf8f7434f"><code>30eb73b</code></a>
Resolve high-severity audit issues</li>
<li><a
href="https://github.com/actions/setup-node/commit/4e1a87a501d0302f99e30e2748568adcb388d09f"><code>4e1a87a</code></a>
Update dist</li>
<li><a
href="https://github.com/actions/setup-node/commit/360237f0c01778d0c17291f75c56d6feae4f7574"><code>360237f</code></a>
Strict equality</li>
<li><a
href="https://github.com/actions/setup-node/commit/4f8aac5beb2f0854bc79651567a18c67eb0b9de3"><code>4f8aac5</code></a>
Bump <code>@​actions/cache</code> to 5.1.0, log cache write denied</li>
<li><a
href="https://github.com/actions/setup-node/commit/f4a67bbeca970f103397d3d2b9462cf787cd2980"><code>f4a67bb</code></a>
Only use <code>mirrorToken</code> in <code>getManifest</code> if it's
provided (<a
href="https://redirect.github.com/actions/setup-node/issues/1548">#1548</a>)</li>
<li><a
href="https://github.com/actions/setup-node/commit/0355742c943ddb13ca8a6b700f824231caa91e75"><code>0355742</code></a>
Remove dummy NODE_AUTH_TOKEN export (<a
href="https://redirect.github.com/actions/setup-node/issues/1558">#1558</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/setup-node/compare/v6...v7">compare
view</a></li>
</ul>
</details>
<br />

Updates `astral-sh/setup-uv` from 6 to 7
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/setup-uv/releases">astral-sh/setup-uv's
releases</a>.</em></p>
<blockquote>
<h2>v7.0.0 🌈 node24 and a lot of bugfixes</h2>
<h2>Changes</h2>
<p>This release comes with a load of bug fixes and a speed up. Because
of switching from node20 to node24 it is also a breaking change. If you
are running on GitHub hosted runners this will just work, if you are
using self-hosted runners make sure, that your runners are up to date.
If you followed the normal installation instructions your self-hosted
runner will keep itself updated.</p>
<p>This release also removes the deprecated input
<code>server-url</code> which was used to download uv releases from a
different server.
The <a
href="https://github.com/astral-sh/setup-uv?tab=readme-ov-file#manifest-file">manifest-file</a>
input supersedes that functionality by adding a flexible way to define
available versions and where they should be downloaded from.</p>
<h3>Fixes</h3>
<ul>
<li>The action now respects when the environment variable
<code>UV_CACHE_DIR</code> is already set and does not overwrite it. It
now also finds <a
href="https://docs.astral.sh/uv/reference/settings/#cache-dir">cache-dir</a>
settings in config files if you set them.</li>
<li>Some users encountered problems that <a
href="https://github.com/astral-sh/setup-uv?tab=readme-ov-file#disable-cache-pruning">cache
pruning</a> took forever because they had some <code>uv</code> processes
running in the background. Starting with uv version <code>0.8.24</code>
this action uses <code>uv cache prune --ci --force</code> to ignore the
running processes</li>
<li>If you just want to install uv but not have it available in path,
this action now respects <code>UV_NO_MODIFY_PATH</code></li>
<li>Some other actions also set the env var <code>UV_CACHE_DIR</code>.
This action can now deal with that but as this could lead to unwanted
behavior in some edgecases a warning is now displayed.</li>
</ul>
<h3>Improvements</h3>
<p>If you are using minimum version specifiers for the version of uv to
install for example</p>
<pre lang="toml"><code>[tool.uv]
required-version = &quot;&gt;=0.8.17&quot;
</code></pre>
<p>This action now detects that and directly uses the latest version.
Previously it would download all available releases from the uv repo
to determine the highest matching candidate for the version specifier,
which took much more time.</p>
<p>If you are using other specifiers like <code>0.8.x</code> this action
still needs to download all available releases because the specifier
defines an upper bound (not 0.9.0 or later) and &quot;latest&quot; would
possibly not satisfy that.</p>
<h2>🚨 Breaking changes</h2>
<ul>
<li>Use node24 instead of node20 <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/608">#608</a>)</li>
<li>Remove deprecated input server-url <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/607">#607</a>)</li>
</ul>
<h2>🐛 Bug fixes</h2>
<ul>
<li>Respect UV_CACHE_DIR and cache-dir <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/612">#612</a>)</li>
<li>Use --force when pruning cache <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/611">#611</a>)</li>
<li>Respect UV_NO_MODIFY_PATH <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/603">#603</a>)</li>
<li>Warn when <code>UV_CACHE_DIR</code> has changed <a
href="https://github.com/jamesbraza"><code>@​jamesbraza</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/601">#601</a>)</li>
</ul>
<h2>🚀 Enhancements</h2>
<ul>
<li>Shortcut to latest version for minimum version specifier <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/598">#598</a>)</li>
</ul>
<h2>🧰 Maintenance</h2>
<ul>
<li>Bump dependencies <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/613">#613</a>)</li>
<li>Fix test-uv-no-modify-path <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/604">#604</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/37802adc94f370d6bfd71619e3f0bf239e1f3b78"><code>37802ad</code></a>
Fetch uv from Astral's mirror by default (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/809">#809</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/9f00d186ce05fb186322da2c89bac726cc9005f5"><code>9f00d18</code></a>
chore(deps): bump zizmorcore/zizmor-action from 0.5.0 to 0.5.2 (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/808">#808</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/fd8f376b22c1219b8021404baf54539061a0339a"><code>fd8f376</code></a>
Switch to ESM for source and test, use CommonJS for dist (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/806">#806</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/f9070de1eac8816a02afc90f4a12cc6fe70d141c"><code>f9070de</code></a>
Bump deps (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/805">#805</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/cadb67bdc9933e2f8795f82ab47acc5f41ed4d31"><code>cadb67b</code></a>
chore: update known checksums for 0.10.10 (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/804">#804</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/e06108dd0aef18192324c70427afc47652e63a82"><code>e06108d</code></a>
Use astral-sh/versions as primary version provider (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/802">#802</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/0f6ec07aafe46cff7a322c837e5ba37d95c82b00"><code>0f6ec07</code></a>
docs: replace copilot instructions with AGENTS.md (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/794">#794</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/821e5c98158b218f7c8e97d0ea3862c6d6425e8b"><code>821e5c9</code></a>
docs: add cross-client dependabot rollup skill (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/793">#793</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/6ee6290f1cbc4156c0bdd66691b2c144ef8df19a"><code>6ee6290</code></a>
chore(deps): bump versions (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/792">#792</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/9f332a133a60f39d23361d5262fa95793aa02590"><code>9f332a1</code></a>
Add riscv64 architecture support to platform detection (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/791">#791</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/setup-uv/compare/v6...v7">compare
view</a></li>
</ul>
</details>
<br />

Updates `actions/upload-artifact` from 4 to 7
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/upload-artifact/releases">actions/upload-artifact's
releases</a>.</em></p>
<blockquote>
<h2>v7.0.0</h2>
<h2>v7 What's new</h2>
<h3>Direct Uploads</h3>
<p>Adds support for uploading single files directly (unzipped). Callers
can set the new <code>archive</code> parameter to <code>false</code> to
skip zipping the file during upload. Right now, we only support single
files. The action will fail if the glob passed resolves to multiple
files. The <code>name</code> parameter is also ignored with this
setting. Instead, the name of the artifact will be the name of the
uploaded file.</p>
<h3>ESM</h3>
<p>To support new versions of the <code>@actions/*</code> packages,
we've upgraded the package to ESM.</p>
<h2>What's Changed</h2>
<ul>
<li>Add proxy integration test by <a
href="https://github.com/Link"><code>@​Link</code></a>- in <a
href="https://redirect.github.com/actions/upload-artifact/pull/754">actions/upload-artifact#754</a></li>
<li>Upgrade the module to ESM and bump dependencies by <a
href="https://github.com/danwkennedy"><code>@​danwkennedy</code></a> in
<a
href="https://redirect.github.com/actions/upload-artifact/pull/762">actions/upload-artifact#762</a></li>
<li>Support direct file uploads by <a
href="https://github.com/danwkennedy"><code>@​danwkennedy</code></a> in
<a
href="https://redirect.github.com/actions/upload-artifact/pull/764">actions/upload-artifact#764</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/Link"><code>@​Link</code></a>- made
their first contribution in <a
href="https://redirect.github.com/actions/upload-artifact/pull/754">actions/upload-artifact#754</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/upload-artifact/compare/v6...v7.0.0">https://github.com/actions/upload-artifact/compare/v6...v7.0.0</a></p>
<h2>v6.0.0</h2>
<h2>v6 - What's new</h2>
<blockquote>
<p>[!IMPORTANT]
actions/upload-artifact@v6 now runs on Node.js 24 (<code>runs.using:
node24</code>) and requires a minimum Actions Runner version of 2.327.1.
If you are using self-hosted runners, ensure they are updated before
upgrading.</p>
</blockquote>
<h3>Node.js 24</h3>
<p>This release updates the runtime to Node.js 24. v5 had preliminary
support for Node.js 24, however this action was by default still running
on Node.js 20. Now this action by default will run on Node.js 24.</p>
<h2>What's Changed</h2>
<ul>
<li>Upload Artifact Node 24 support by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/upload-artifact/pull/719">actions/upload-artifact#719</a></li>
<li>fix: update <code>@​actions/artifact</code> for Node.js 24 punycode
deprecation by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/upload-artifact/pull/744">actions/upload-artifact#744</a></li>
<li>prepare release v6.0.0 for Node.js 24 support by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/upload-artifact/pull/745">actions/upload-artifact#745</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/upload-artifact/compare/v5.0.0...v6.0.0">https://github.com/actions/upload-artifact/compare/v5.0.0...v6.0.0</a></p>
<h2>v5.0.0</h2>
<h2>What's Changed</h2>
<p><strong>BREAKING CHANGE:</strong> this update supports Node
<code>v24.x</code>. This is not a breaking change per-se but we're
treating it as such.</p>
<ul>
<li>Update README.md by <a
href="https://github.com/GhadimiR"><code>@​GhadimiR</code></a> in <a
href="https://redirect.github.com/actions/upload-artifact/pull/681">actions/upload-artifact#681</a></li>
<li>Update README.md by <a
href="https://github.com/nebuk89"><code>@​nebuk89</code></a> in <a
href="https://redirect.github.com/actions/upload-artifact/pull/712">actions/upload-artifact#712</a></li>
<li>Readme: spell out the first use of GHES by <a
href="https://github.com/danwkennedy"><code>@​danwkennedy</code></a> in
<a
href="https://redirect.github.com/actions/upload-artifact/pull/727">actions/upload-artifact#727</a></li>
<li>Update GHES guidance to include reference to Node 20 version by <a
href="https://github.com/patrikpolyak"><code>@​patrikpolyak</code></a>
in <a
href="https://redirect.github.com/actions/upload-artifact/pull/725">actions/upload-artifact#725</a></li>
<li>Bump <code>@actions/artifact</code> to <code>v4.0.0</code></li>
<li>Prepare <code>v5.0.0</code> by <a
href="https://github.com/danwkennedy"><code>@​danwkennedy</code></a> in
<a
href="https://redirect.github.com/actions/upload-artifact/pull/734">actions/upload-artifact#734</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/upload-artifact/commit/043fb46d1a93c77aae656e7c1c64a875d1fc6a0a"><code>043fb46</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/upload-artifact/issues/797">#797</a>
from actions/yacaovsnc/update-dependency</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/634250c1388765ea7ed0f053e636f1f399000b94"><code>634250c</code></a>
Include changes in typespec/ts-http-runtime 0.3.5</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/e454baaac2be505c9450e11b8f3215c6fc023ce8"><code>e454baa</code></a>
Readme: bump all the example versions to v7 (<a
href="https://redirect.github.com/actions/upload-artifact/issues/796">#796</a>)</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/74fad66b98a6d799dc004d3353ccd0e6f6b2530e"><code>74fad66</code></a>
Update the readme with direct upload details (<a
href="https://redirect.github.com/actions/upload-artifact/issues/795">#795</a>)</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/bbbca2ddaa5d8feaa63e36b76fdaad77386f024f"><code>bbbca2d</code></a>
Support direct file uploads (<a
href="https://redirect.github.com/actions/upload-artifact/issues/764">#764</a>)</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/589182c5a4cec8920b8c1bce3e2fab1c97a02296"><code>589182c</code></a>
Upgrade the module to ESM and bump dependencies (<a
href="https://redirect.github.com/actions/upload-artifact/issues/762">#762</a>)</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/47309c993abb98030a35d55ef7ff34b7fa1074b5"><code>47309c9</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/upload-artifact/issues/754">#754</a>
from actions/Link-/add-proxy-integration-tests</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/02a8460834e70dab0ce194c64360c59dc1475ef0"><code>02a8460</code></a>
Add proxy integration test</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/b7c566a772e6b6bfb58ed0dc250532a479d7789f"><code>b7c566a</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/upload-artifact/issues/745">#745</a>
from actions/upload-artifact-v6-release</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/e516bc8500aaf3d07d591fcd4ae6ab5f9c391d5b"><code>e516bc8</code></a>
docs: correct description of Node.js 24 support in README</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/upload-artifact/compare/v4...v7">compare
view</a></li>
</ul>
</details>
<br />

Updates `actions/download-artifact` from 4 to 8
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/download-artifact/releases">actions/download-artifact's
releases</a>.</em></p>
<blockquote>
<h2>v8.0.0</h2>
<h2>v8 - What's new</h2>
<blockquote>
<p>[!IMPORTANT]
actions/download-artifact@v8 has been migrated to an ESM module. This
should be transparent to the caller but forks might need to make
significant changes.</p>
</blockquote>
<blockquote>
<p>[!IMPORTANT]
Hash mismatches will now error by default. Users can override this
behavior with a setting change (see below).</p>
</blockquote>
<h3>Direct downloads</h3>
<p>To support direct uploads in <code>actions/upload-artifact</code>,
the action will no longer attempt to unzip all downloaded files.
Instead, the action checks the <code>Content-Type</code> header ahead of
unzipping and skips non-zipped files. Callers wishing to download a
zipped file as-is can also set the new <code>skip-decompress</code>
parameter to <code>true</code>.</p>
<h3>Enforced checks (breaking)</h3>
<p>A previous release introduced digest checks on the download. If a
download hash didn't match the expected hash from the server, the action
would log a warning. Callers can now configure the behavior on mismatch
with the <code>digest-mismatch</code> parameter. To be secure by
default, we are now defaulting the behavior to <code>error</code> which
will fail the workflow run.</p>
<h3>ESM</h3>
<p>To support new versions of the @actions/* packages, we've upgraded
the package to ESM.</p>
<h2>What's Changed</h2>
<ul>
<li>Don't attempt to un-zip non-zipped downloads by <a
href="https://github.com/danwkennedy"><code>@​danwkennedy</code></a> in
<a
href="https://redirect.github.com/actions/download-artifact/pull/460">actions/download-artifact#460</a></li>
<li>Add a setting to specify what to do on hash mismatch and default it
to <code>error</code> by <a
href="https://github.com/danwkennedy"><code>@​danwkennedy</code></a> in
<a
href="https://redirect.github.com/actions/download-artifact/pull/461">actions/download-artifact#461</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/download-artifact/compare/v7...v8.0.0">https://github.com/actions/download-artifact/compare/v7...v8.0.0</a></p>
<h2>v7.0.0</h2>
<h2>v7 - What's new</h2>
<blockquote>
<p>[!IMPORTANT]
actions/download-artifact@v7 now runs on Node.js 24 (<code>runs.using:
node24</code>) and requires a minimum Actions Runner version of 2.327.1.
If you are using self-hosted runners, ensure they are updated before
upgrading.</p>
</blockquote>
<h3>Node.js 24</h3>
<p>This release updates the runtime to Node.js 24. v6 had preliminary
support for Node 24, however this action was by default still running on
Node.js 20. Now this action by default will run on Node.js 24.</p>
<h2>What's Changed</h2>
<ul>
<li>Update GHES guidance to include reference to Node 20 version by <a
href="https://github.com/patrikpolyak"><code>@​patrikpolyak</code></a>
in <a
href="https://redirect.github.com/actions/download-artifact/pull/440">actions/download-artifact#440</a></li>
<li>Download Artifact Node24 support by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/download-artifact/pull/415">actions/download-artifact#415</a></li>
<li>fix: update <code>@​actions/artifact</code> to fix Node.js 24
punycode deprecation by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/download-artifact/pull/451">actions/download-artifact#451</a></li>
<li>prepare release v7.0.0 for Node.js 24 support by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/download-artifact/pull/452">actions/download-artifact#452</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/patrikpolyak"><code>@​patrikpolyak</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/download-artifact/pull/440">actions/download-artifact#440</a></li>
<li><a href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/download-artifact/pull/415">actions/download-artifact#415</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/download-artifact/compare/v6.0.0...v7.0.0">https://github.com/actions/download-artifact/compare/v6.0.0...v7.0.0</a></p>
<h2>v6.0.0</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/download-artifact/commit/3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c"><code>3e5f45b</code></a>
Add regression tests for CJK characters (<a
href="https://redirect.github.com/actions/download-artifact/issues/471">#471</a>)</li>
<li><a
href="https://github.com/actions/download-artifact/commit/e6d03f67377d4412c7aa56a8e2e4988e6ec479dd"><code>e6d03f6</code></a>
Add a regression test for artifact name + content-type mismatches (<a
href="https://redirect.github.com/actions/download-artifact/issues/472">#472</a>)</li>
<li><a
href="https://github.com/actions/download-artifact/commit/70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3"><code>70fc10c</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/download-artifact/issues/461">#461</a>
from actions/danwkennedy/digest-mismatch-behavior</li>
<li><a
href="https://github.com/actions/download-artifact/commit/f258da9a506b755b84a09a531814700b86ccfc62"><code>f258da9</code></a>
Add change docs</li>
<li><a
href="https://github.com/actions/download-artifact/commit/ccc058e5fbb0bb2352213eaec3491e117cbc4a5c"><code>ccc058e</code></a>
Fix linting issues</li>
<li><a
href="https://github.com/actions/download-artifact/commit/bd7976ba57ecea96e6f3df575eb922d11a12a9fd"><code>bd7976b</code></a>
Add a setting to specify what to do on hash mismatch and default it to
<code>error</code></li>
<li><a
href="https://github.com/actions/download-artifact/commit/ac21fcf45e0aaee541c0f7030558bdad38d77d6c"><code>ac21fcf</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/download-artifact/issues/460">#460</a>
from actions/danwkennedy/download-no-unzip</li>
<li><a
href="https://github.com/actions/download-artifact/commit/15999bff51058bc7c19b50ebbba518eaef7c26c0"><code>15999bf</code></a>
Add note about package bumps</li>
<li><a
href="https://github.com/actions/download-artifact/commit/974686ed5098c7f9c9289ec946b9058e496a2561"><code>974686e</code></a>
Bump the version to <code>v8</code> and add release notes</li>
<li><a
href="https://github.com/actions/download-artifact/commit/fbe48b1d2756394be4cd4358ed3bc1343b330e75"><code>fbe48b1</code></a>
Update test names to make it clearer what they do</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/download-artifact/compare/v4...v8">compare
view</a></li>
</ul>
</details>
<br />

Updates `actions/github-script` from 8 to 9
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/github-script/releases">actions/github-script's
releases</a>.</em></p>
<blockquote>
<h2>v9.0.0</h2>
<p><strong>New features:</strong></p>
<ul>
<li><strong><code>getOctokit</code> factory function</strong> —
Available directly in the script context. Create additional
authenticated Octokit clients with different tokens for multi-token
workflows, GitHub App tokens, and cross-org access. See <a
href="https://github.com/actions/github-script#creating-additional-clients-with-getoctokit">Creating
additional clients with <code>getOctokit</code></a> for details and
examples.</li>
<li><strong>Orchestration ID in user-agent</strong> — The
<code>ACTIONS_ORCHESTRATION_ID</code> environment variable is
automatically appended to the user-agent string for request
tracing.</li>
</ul>
<p><strong>Breaking changes:</strong></p>
<ul>
<li><strong><code>require('@actions/github')</code> no longer works in
scripts.</strong> The upgrade to <code>@actions/github</code> v9
(ESM-only) means <code>require('@actions/github')</code> will fail at
runtime. If you previously used patterns like <code>const { getOctokit }
= require('@actions/github')</code> to create secondary clients, use the
new injected <code>getOctokit</code> function instead — it's available
directly in the script context with no imports needed.</li>
<li><code>getOctokit</code> is now an injected function parameter.
Scripts that declare <code>const getOctokit = ...</code> or <code>let
getOctokit = ...</code> will get a <code>SyntaxError</code> because
JavaScript does not allow <code>const</code>/<code>let</code>
redeclaration of function parameters. Use the injected
<code>getOctokit</code> directly, or use <code>var getOctokit =
...</code> if you need to redeclare it.</li>
<li>If your script accesses other <code>@actions/github</code> internals
beyond the standard <code>github</code>/<code>octokit</code> client, you
may need to update those references for v9 compatibility.</li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>Add ACTIONS_ORCHESTRATION_ID to user-agent string by <a
href="https://github.com/Copilot"><code>@​Copilot</code></a> in <a
href="https://redirect.github.com/actions/github-script/pull/695">actions/github-script#695</a></li>
<li>ci: use deployment: false for integration test environments by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/github-script/pull/712">actions/github-script#712</a></li>
<li>feat!: add getOctokit to script context, upgrade
<code>@​actions/github</code> v9, <code>@​octokit/core</code> v7, and
related packages by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/github-script/pull/700">actions/github-script#700</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/Copilot"><code>@​Copilot</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/github-script/pull/695">actions/github-script#695</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/github-script/compare/v8.0.0...v9.0.0">https://github.com/actions/github-script/compare/v8.0.0...v9.0.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/github-script/commit/3a2844b7e9c422d3c10d287c895573f7108da1b3"><code>3a2844b</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/github-script/issues/700">#700</a>
from actions/salmanmkc/expose-getoctokit + prepare re...</li>
<li><a
href="https://github.com/actions/github-script/commit/ca10bbdd1a7739de09e99a200c7a59f5d73a4079"><code>ca10bbd</code></a>
fix: use <code>@​octokit/core/</code>types import for v7
compatibility</li>
<li><a
href="https://github.com/actions/github-script/commit/86e48e20ac85c970ed1f96e718fd068173948b7b"><code>86e48e2</code></a>
merge: incorporate main branch changes</li>
<li><a
href="https://github.com/actions/github-script/commit/c1084728b5b935ec4ddc1e4cee877b01797b3ff9"><code>c108472</code></a>
chore: rebuild dist for v9 upgrade and getOctokit factory</li>
<li><a
href="https://github.com/actions/github-script/commit/afff112e4f8b57c718168af75b89ce00bc8d091d"><code>afff112</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/github-script/issues/712">#712</a>
from actions/salmanmkc/deployment-false + fix user-ag...</li>
<li><a
href="https://github.com/actions/github-script/commit/ff8117e5b78c415f814f39ad6998f424fee7b817"><code>ff8117e</code></a>
ci: fix user-agent test to handle orchestration ID</li>
<li><a
href="https://github.com/actions/github-script/commit/81c6b7876079abe10ff715951c9fc7b3e1ab389d"><code>81c6b78</code></a>
ci: use deployment: false to suppress deployment noise from integration
tests</li>
<li><a
href="https://github.com/actions/github-script/commit/3953caf8858d318f37b6cc53a9f5708859b5a7b7"><code>3953caf</code></a>
docs: update README examples from <a
href="https://github.com/v8"><code>@​v8</code></a> to <a
href="https://github.com/v9"><code>@​v9</code></a>, add getOctokit docs
and v9 brea...</li>
<li><a
href="https://github.com/actions/github-script/commit/c17d55b90dcdb3d554d0027a6c180a7adc2daf78"><code>c17d55b</code></a>
ci: add getOctokit integration test job</li>
<li><a
href="https://github.com/actions/github-script/commit/a047196d9a02fe92098771cafbb98c2f1814e408"><code>a047196</code></a>
test: add getOctokit integration tests via callAsyncFunction</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/github-script/compare/v8...v9">compare
view</a></li>
</ul>
</details>
<br />

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…oleMurray#2281)

Closes ColeMurray#2034.

> **Note:** This is an alternative implementation to ColeMurray#2208 for the same
issue. It was designed independently from `main` and the issue text.

## Summary

Operators can now choose **OpenCode** or **Claude Agent** for
Linear-triggered sessions, as a global default and per repository
override. When nothing is configured, sessions still run on OpenCode
with the same behavior as before. Because the harness is fixed at
create, follow-ups on an existing issue session are unchanged.

## Design

**A configured harness is a preference, and the resolved model decides
the final harness.** A new shared helper,
`resolveHarnessForModel(configured, model)` in `shared/harnesses.ts`,
returns the configured harness when it can run the model. Otherwise it
returns the built-in harness (OpenCode), which runs every model. The
Linear bot keeps its model resolution as it was (label → user preference
→ repo/global config → `DEFAULT_MODEL`), then picks the harness from the
result. A future GitHub or Slack harness setting can reuse the same
helper.

- **Schema:** `linearBotSettingsSchema` gets `harness:
harnessIdSchema.optional()`, so it is available at both the global and
repo level.
- **Save validation:** the store's model/effort check is renamed
`validateAgentSelection`. It now also calls `checkHarnessCompatibility`
when a harness and a model are saved at the same level, which matches
how automations validate on save. Any integration that later adds a
`harness` field gets this check automatically.
- **Resolved endpoint:** `GET /integration-settings/linear/resolved/...`
returns a concrete `harness` (via `getValidHarnessOrDefault`). The bot's
schema treats a missing value as OpenCode, so an older control plane
during a deploy doesn't break config reads.
- **Bot:** `resolveSessionAgentSettings` (renamed from
`resolveSessionModelSettings`) returns `{ harness, model,
reasoningEffort }`. `createSession` always sends `harness`.
- **Web settings:**
- The global form and each repo row get a harness picker
(`HarnessSelect`, a reusable component); repo rows can also pick
"Inherit (X)".
- Model pickers only list models the effective harness can run
(`filterModelOptionsForHarness`). Switching to a harness that can't run
the current model clears the model and effort.
  - Saves stay sparse: the default harness and "inherit" are omitted.
- Repo rows warn when the effective harness and effective model clash
across levels (for example, a global `openai/gpt-5.4` with a repo
override of Claude Agent). Save-time validation can't catch that case,
and those sessions run on OpenCode.
- **Provider auth:** Linear sessions are unattended. On Claude Agent
they follow the **Automated authentication** policy and may use the
default Claude account. The UI copy and the docs say this.

## Open questions

- **Claude Agent selected but the resolved model isn't Anthropic: fall
back or fail?** It falls back to OpenCode. Labels, user preferences and
the env default are resolved at runtime by people other than the
operator, so a hard failure would turn `model:gpt-*` into a dead end.
The rule is deterministic, tested for each model source, and named in
the Linear activity. The web composer already adjusts the model to fit
the harness rather than failing. Operators who want strict Claude Agent
can set an Anthropic default model and turn off label and
user-preference overrides; the docs explain this.
- **Per-issue `harness:*` label or per-user override?** No,
operator-level only for now. The harness decides which credential pays:
with Claude Agent, unattended sessions can draw on a connected
subscription. Automations treat that as an operator decision too, and
Linear labels are editable by anyone in the workspace.
- **Should "Creating coding session…" mention the harness?** Yes.
Because of the fallback, the harness isn't always obvious.

## Visible change: Linear activity wording

Linear activities now name the agent, **including for default (OpenCode)
sessions**:

- `Creating coding session on <target> (agent: OpenCode, model: …)...`
- `Working on \`<target>\` with **<model>** (OpenCode).`

The `agent_session.session_created` log now includes
`configured_harness` and `harness`.

## Docs

- `docs/CLAUDE_AGENT.md`: replaced "Bots and integrations create
OpenCode sessions" and added a "Linear sessions" section.
- `docs/integrations/LINEAR.md` and
`packages/docs/.../integrations/linear.mdx`: the new setting, how the
harness is resolved, and troubleshooting.
- `agent-harnesses.mdx`, `choosing-a-model.mdx`,
`provider-accounts.mdx`: removed statements that Linear always runs on
OpenCode.

## Tests, lint, typecheck

Only the tests covering the changed files were run:

| Command | Result |
| --- | --- |
| `npm run build -w @open-inspect/shared` | ✅ |
| shared `vitest run src/harnesses.test.ts src/module-boundaries.test.ts
src/public-api.test.ts` | ✅ 30 passed |
| control-plane `vitest run --config vitest.integration.config.ts
test/integration/linear-integration-settings.test.ts
test/integration/integration-settings.test.ts` | ✅ 67 passed |
| control-plane `vitest run src/db/integration-settings.test.ts` | ✅ 134
passed |
| linear-bot `vitest run` on `webhook-handler.harness.test.ts` (new),
`__tests__/pure-functions.test.ts`, `utils/integration-config.test.ts`,
`webhook-handler.test.ts` | ✅ all passed |
| web `vitest run
src/components/settings/integrations/linear-integration-settings.test.tsx`
| ✅ 15 passed |
| `npm test -w @open-inspect/docs` | ✅ 44 passed |
| `npm run typecheck` for shared, control-plane, linear-bot, web | ✅
clean |
| `npm run lint` for shared, control-plane, linear-bot, web | ✅ clean |
| `npm run lint:complexity` | ✅ no hotspots in touched files |

## Trade-offs

- If Claude Agent is selected, the model is left on "Use system
default", and `DEFAULT_MODEL` isn't Anthropic, sessions run on OpenCode.
The form can't warn about this because the web app doesn't know the
bot's env default. The UI help text, the Linear activity and the docs
explain it.
- Repos whose prebuilt images predate the Claude harness's minimum image
generation will miss the prebuilt image on their first Claude Agent
sessions. This is expected.

---
*Created with
[Open-Inspect](https://open-inspect-prod.vercel.app/session/aad95f46ac3dbe5bffb0bd6a4f54bf6b)*

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Choose an agent harness for Linear sessions, with repository-level
overrides that can inherit global settings.
* Linear sessions use the selected harness when it supports the resolved
model; otherwise, they use OpenCode. OpenCode remains the default.
  * Session activity now shows which harness is being used.
* **Improvements**
* Settings filter model choices based on the selected harness and flag
incompatible defaults that will fall back to OpenCode.
* Documentation clarifies how harness selection, authentication, and
changes to existing versus new sessions work.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Cole Murray <2492022+ColeMurray@users.noreply.github.com>
Co-authored-by: waclaude <colemurray.cs+ghwaclaude@gmail.com>
)

## Summary

Takes over ColeMurray#2155 by @ffesseler, which now conflicts with `main`. The
goal is unchanged. External callers such as CLIs, CI jobs, and tools
like Herdr can submit work through an inbound webhook, but they get
nothing back to correlate with it. Checking whether it finished
currently requires a signed-in web session. This PR returns an
invocation ID from the webhook and adds a status endpoint that accepts
the same webhook key.

It also addresses the review on ColeMurray#2155
(ColeMurray#2155 (review)).

## What changes

**API**
- `POST /webhooks/automation/:id` now also returns `invocationId`. It is
`null` only when nothing was recorded: conditions did not match, the
automation is paused, or execution was denied before admission.
- New endpoint `GET /webhooks/automation/:id/invocations/:invocationId`,
authenticated with the webhook key. It returns `{ invocationId, status,
runs: [{ id, status, sessionId }] }` and nothing else: no session
content, payload, or other history. It returns 404 for other
automations' invocations and for firings the webhook didn't cause
(manual or scheduled).
- Response types `WebhookTriggerResponse` and
`WebhookInvocationStatusResponse` live in `@open-inspect/shared`.

**Idempotent retries keep their ID (fixes a gap in ColeMurray#2155)**
- A retry with the same `idempotencyKey` now returns the **original**
invocation ID. In ColeMurray#2155 it returned `null` if the first firing had
finished. If the first firing was still running, it recorded a new
*skipped* invocation and returned that ID, so a polling client concluded
its task had been dropped.
- `startInvocation` now looks up the invocation that owns the event's
`trigger_key` before the overlap check, and does the same after an
insert collision. This applies to every event source, so a redelivered
GitHub, Sentry, or Slack event while its run is still active now
resolves to the original firing. Previously it recorded a spurious
"concurrent run active" skip, and for Slack posted an "already active"
notice. Skipped invocations still never hold a `trigger_key`, so a skip
doesn't take the dedup slot of a firing that never ran.

**Structure**
- `SchedulerEventResult.invocationIds: string[]` is filled for every
source with no source-specific checks. ColeMurray#2155 added `webhookInvocationId`
and `event.source === "webhook"` checks to the shared event loop. The
webhook handler now returns `invocationIds[0] ?? null`, since a webhook
event targets exactly one automation.
- `StartInvocationResult` and the new `firingInvocationId()` helper
moved to `scheduler/invocation-outcome.ts`, so GitHub admission can use
them without a runtime import cycle. `scheduler.ts` re-exports the
types.
- New canonical `AutomationStore.getInvocation(automationId,
invocationId)` reuses the `listInvocations` mappers and reads the
invocation and its runs in one `db.batch`, so the status and runs always
come from the same snapshot. `listInvocations` and `getInvocation` share
the select SQL. The webhook handler narrows the result to the public
status shape.
- `authenticateWebhook` returns `{ ok: true; automation } | { ok: false;
response }` instead of `Response | AutomationStore`.

## Testing
- Unit (control-plane): scheduler, GitHub admission, webhooks, route
policy, and automation routes. 480 tests pass.
- Integration (control-plane): scheduler events (webhook, Sentry, Slack,
Slack team steering), GitHub routing, team grants, service auth, Slack
and GitHub-PR webhooks, inbound webhooks, invocation store, route
catalog conformance, and the admission matrix. 200 tests pass.
- New coverage: a same-key retry returns the original ID, both after the
original completed and while it is still running; an overlap skip
returns its own ID; a filtered body returns `invocationId: null`; the
status endpoint's auth/404 matrix, its manual-invocation exclusion, and
its minimal fields; and `getInvocation` equals the listing entry for
each history shape.
- `typecheck` (all control-plane configs), ESLint, Prettier,
`lint:sql-portability`, and the docs package tests all pass.
- About 47 existing `toEqual({ triggered, skipped, steered })`
assertions now include an exact `invocationIds` value (`[]` or one
`expect.any(String)` per recorded invocation).

## Docs
- `packages/docs/.../inbound-webhooks.mdx`: adds `invocationId` to the
responses section, a new "Checking status" section, and a note on
idempotent retries.
- `docs/AUTOMATIONS.md` and the control-plane README.

Supersedes ColeMurray#2155.

Co-authored-by: Florian Fesseler <florian@mozza.io>

---
*Created with
[Open-Inspect](https://open-inspect-prod.vercel.app/session/2eed8e3e5f06ed75a5ccb0ac6255ecfe)*

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Webhook trigger responses now include an invocation ID when a firing
is recorded. Repeated requests with the same idempotency key return the
original ID, including while the firing is in progress.
* Added an API-key-authenticated endpoint to check an invocation’s
status and its runs’ statuses and session IDs. It does not expose
session content.
* **Documentation**
* Updated webhook guides with response details, retry behavior, and
instructions for checking invocation status.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Cole Murray <2492022+ColeMurray@users.noreply.github.com>
Co-authored-by: Florian Fesseler <florian@mozza.io>
Co-authored-by: waclaude <colemurray.cs+ghwaclaude@gmail.com>
This is an automated nightly unsafe-cast remediation sweep. It replaces
qualifying unsafe TypeScript assertions with parse-don't-assert
validation at boundary/persistence seams, following the TypeScript
Coding Standards for unsafe casts and the Zod boundary-validation
pattern established in PR ColeMurray#807.

| Finding | Risk | Cast removed | Fix |
| --- | --- | --- | --- |
| `packages/control-plane/src/node/job-store.ts:278` | Medium | SQLite
aggregate row cast `as { run_at: number \| null }` used for job
scheduling | Added Zod parsing via `parseNullableRunAtRow`, including
the valid `null` aggregate case |
| `packages/control-plane/src/node/job-store.ts:305` | Medium | SQLite
recovery row casts `as Array<{ id: string }>` used to recover leased
jobs | Added Zod parsing via `parseJobIdRows` before returning recovered
ids |
| `packages/control-plane/src/node/job-store.ts:308` | Medium | SQLite
status-count row cast `as Array<{ status: string; count: number }>` used
for queue health state | Added Zod parsing via `parseStatusCountRows`
before computing stats |
| `packages/control-plane/src/media.ts:220` | Low | Parsed multipart
dimensions object cast `as { width?: unknown; height?: unknown }` |
Removed assertion and read properties only through `in`-guarded access
after the existing JSON/object checks |

Verification:

| Command | Result |
| --- | --- |
| `npm run format -- --write
packages/control-plane/src/node/job-store.ts
packages/control-plane/src/node/job-store.test.ts
packages/control-plane/src/media.ts` | Passed |
| `npm test -w @open-inspect/control-plane -- src/node/job-store.test.ts
src/media.test.ts` | Passed, 2 files / 63 tests |
| `npm run build -w @open-inspect/shared` | Passed |
| `npm run build -w @open-inspect/control-plane` | Passed |
| `npm test -w @open-inspect/control-plane` | Passed, 329 files / 5300
tests |
| `npm run typecheck` | Passed |
| `npm run lint` | Passed |
| `npm run format` | Passed |

No new dependencies were added.

---
*Created with
[Open-Inspect](https://open-inspect-prod.vercel.app/session/7af4401825306a304add9ced4aed4937)*

---------

Co-authored-by: waclaude <colemurray.cs+ghwaclaude@gmail.com>
Co-authored-by: Cole Murray <2492022+ColeMurray@users.noreply.github.com>
…rray#2287)

## Summary

Adds four changelog entries for features merged recently that were
missing from `CHANGELOG.md`. Each entry is dated by its merge date in US
Pacific time, which is the convention the existing entries follow.

| Entry | Date | PRs |
| --- | --- | --- |
| Persistent memory | October 3 | ColeMurray#2214, ColeMurray#2261 |
| Analytics redesign | October 2 | ColeMurray#2233, ColeMurray#2218 |
| Saved prompt drafts | October 2 | ColeMurray#2237 |
| Session page redesign | October 1 | ColeMurray#2168, ColeMurray#2169 (Sep 30), ColeMurray#2199 (Oct
1) |

The session redesign entry is dated October 1, when ColeMurray#2199 completed the
tab layout. The artifact arrow-key navigation from ColeMurray#2234 is left out to
keep the entry short.

## Verification

- `npx prettier --check CHANGELOG.md` passes.

---
*Created with
[Open-Inspect](https://open-inspect-prod.vercel.app/session/2b8fc4c8c153f4e0cd78f4a52a5317ee)*

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added persistent memory for personal facts in a private session; other
agent memory writes require approval.
* Redesigned analytics with Usage, Cost, Pull requests, and People tabs,
selections preserved in the URL, and a Session origins breakdown.
* Added prompt drafts that persist across reloads, with separate drafts
for each session and the new-session composer.
* Redesigned the session page with Info, Changes, Tasks, and Tools tabs.
Captured media appears under Info’s Artifacts, and changed files open
beside the sidebar.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Cole Murray <2492022+ColeMurray@users.noreply.github.com>
Co-authored-by: waclaude <colemurray.cs+ghwaclaude@gmail.com>
…2268)

Takes over ColeMurray#2021 from @rhlsthrm, rebuilt on current `main` with the fix
that came out of review there. The original author is credited as
co-author.

## Problem

`SandboxShutdownBanner` showed a recovery failure message after the
shutdown phase it described had already been replaced. `recoveryError`
was cleared only when a new recovery request started. The page doesn't
key the banner, so the message stayed through phase changes. For
example, after a `failed`-phase retry timed out, a later `unknown` or
`restoring` → `failed` update still showed "Recovery was not
confirmed…".

## Fix

The rule is that recovery state belongs to one phase. Instead of
enforcing that with a phase-tagged error, a reset effect, and an
in-flight generation counter (the ColeMurray#2021 approach), the stateful body is
now a `ShutdownPhaseBanner` keyed by `shutdown.phase`. A new phase
mounts a fresh instance, which covers every case:

- **No stale frame:** the new phase commits with empty state in the same
render.
- **No resurfacing:** a phase that comes back also gets a fresh
instance.
- **In-flight results:** a request that settles after the phase changed
updates the unmounted instance, which has no effect.

**Behavior change:** if the phase changes while a request is pending,
the buttons for the new phase start enabled. They no longer show the old
phase's "Retrying save…". A second click is still refused by
`recoverShutdown`'s own in-flight guard ("A recovery request is awaiting
confirmation").

## Tests

- Keeps the four tests from ColeMurray#2021, including the `useLayoutEffect`
commit probe that checks the stale message is never committed next to
the newer phase.
- Adds "ignores a result that settles after the phase left and returned"
(failed → restoring → failed with a request pending). This is the case
the ColeMurray#2021 suite didn't cover.
- Asserts the pending indicator resets on a phase change.

Verification:
- `npx vitest run src/components/sandbox-shutdown-banner.test.tsx`
(packages/web): 28 passed. Against `main`'s component, all 5 new tests
fail.
- `npm run typecheck -w @open-inspect/web`: passes.

Supersedes ColeMurray#2021.

---
*Created with
[Open-Inspect](https://open-inspect-prod.vercel.app/session/20c0e8e42bc2814f18744d5bf873e4bf)*

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Recovery messages now clear when the shutdown phase changes,
preventing stale or delayed results from appearing in the wrong phase.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Cole Murray <2492022+ColeMurray@users.noreply.github.com>
Co-authored-by: Rahul Sethuram <rahul.eth@icloud.com>
## Summary

Apply only the Fumadocs portion of
ColeMurray#2285 as a
standalone change against main:

- Upgrade `fumadocs-core` and `fumadocs-ui` from `16.15.6` to
`16.15.14`, and `fumadocs-mdx` from `15.4.0` to `15.4.5`.
- Keep one hoisted `fumadocs-core@16.15.14` shared by the docs loader,
MDX, and UI.
- Update only required Fumadocs transitives (`cn`, Fumadocs Tailwind,
and the Yuku analyzer packages). Install MDX's required `zod@4.6.5`
beneath MDX, preserving the existing root Zod version for other
workspaces.

No Better Auth changes, other grouped dependency updates, casts,
source/schema changes, or unrelated formatting. PR ColeMurray#2285 was not
modified or pushed.

## Root Cause

PR ColeMurray#2285 retains root `node_modules/fumadocs-core@16.15.6` while
installing `16.15.14` under `packages/docs/node_modules`. Its hoisted
MDX declarations resolve the old core, while
`packages/docs/src/lib/source.ts` resolves the new core. The required
`LoaderOutput.getPageByUrl()` added in core 16.15.9 makes those loader
types structurally incompatible. Source inference consequently widens to
`PageData`, losing access to MDX fields such as `body`, `toc`, and
`getText`, and schema fields such as `lastReviewed`.

The public schema is already correctly supplied in `source.ts`; aligning
the dependency graph fixes inference rather than masking it with casts.

## Verification

All validation ran sequentially in the isolated sandbox:

- `npm ci --ignore-scripts --no-audit --no-fund` succeeds with the final
lockfile.
- `npm ls fumadocs-core fumadocs-mdx fumadocs-ui --workspace
@open-inspect/docs` shows MDX and UI deduped to core `16.15.14`.
- Module-resolution assertions confirm the docs loader, MDX, and UI
resolve the identical core source entry.
- `npm run typecheck -w @open-inspect/docs` passes.
- `npm test -w @open-inspect/docs -- src/lib/content-inventory.test.ts
src/lib/content-policy.test.ts --maxWorkers=1` passes: 23 tests across 2
files, including compilation of the MDX corpus.
- `NODE_ENV=production npm run build -w @open-inspect/docs` passes,
generating all 185 static pages.
- Prettier checks for both changed JSON files and `git diff --check`
pass. Lockfile-entry comparison confirms all changes are confined to
Fumadocs and required transitives.

The initial build without an explicit `NODE_ENV` failed during
prerendering with the sandbox's nonstandard environment value. Rerunning
with `NODE_ENV=production` succeeds; no application changes were needed.

---
*Created with
[Open-Inspect](https://open-inspect-prod.vercel.app/session/ff735b38dd74a103ddd8f948de214180)*

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* Updated the documentation site’s supporting packages to newer
versions.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Cole Murray <2492022+ColeMurray@users.noreply.github.com>
## Summary
- Isolate the Prettier portion of
ColeMurray#2285 into a
standalone PR against main.
- Upgrade only the root Prettier range from `^3.4.2` to `^3.9.9` and the
locked version from `3.8.4` to `3.9.9`.
- Apply configured Prettier 3.9.9 formatting to the same 72 existing
files flagged by the grouped dependency update: 71 TypeScript/TSX source
and test files plus one Markdown document containing TypeScript.
- Leave Better Auth, Fumadocs, all other dependencies, formatter
configuration, and the original PR untouched. No application behavior
changes.

## Root Cause
The grouped update changes the installed formatter version. Existing
formatting produced under Prettier 3.8.4 differs from 3.9.9 output,
notably for TypeScript unions, typed arrow callbacks, and mapped types.
The cited Lint & Format job fails at `npm run format:check`, reporting
72 files:

https://github.com/ColeMurray/background-agents/actions/runs/37238749141/job/111542997788

Verified PR head `3e2f1e0`, its base `b5bb5df`, and current main
`31f2afa` before branching. Current main still locks 3.8.4. Installing
only 3.9.9 on current main reproduced the 72-file failure; this PR
contains the formatter upgrade and its required output, not the grouped
dependency graph.

## Verification
Checks ran sequentially with a 2 GiB Node heap cap and explicit time
limits.
- `npm ci --ignore-scripts --no-audit --no-fund`: passed using the
narrowly updated lockfile.
- `npm run format:check`: passed on a clean export of the committed
repository, using the installed locked formatter.
- `npm run format:check -- '!.opencode/tool/_memory-contract.js'`:
passed in the working sandbox. The exclusion is solely for a
sandbox-generated, Git-excluded tool file absent from a clean checkout;
no repository ignore rules or generated tool files were changed.
- `npm run lint`: passed for the full repository.
- `git diff --check`: passed.
- Programmatically confirmed all 72 reformatted files exactly equal
configured Prettier 3.9.9 output applied to their original contents, and
all 71 TypeScript/TSX ASTs are unchanged.
- Deep-compared manifest and lockfile JSON: only the root Prettier range
and the `node_modules/prettier` entry changed; the latter matches PR
ColeMurray#2285 metadata exactly. No unrelated lockfile churn.
- Commit hooks passed ESLint and Prettier.

No behavioral test suite was run because the source changes are
formatter-only and syntax trees are unchanged.

---
*Created with
[Open-Inspect](https://open-inspect-prod.vercel.app/session/ac1bc1bbb1f6db4abea4f0b8ccb63761)*

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
  * Updated the code formatter version.
* Applied formatting-only changes throughout the project. No
functionality or behavior changed.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Cole Murray <2492022+ColeMurray@users.noreply.github.com>
…leMurray#2284)

## Summary

Fixes ColeMurray#1363. When a sandbox misses the 4-minute connect watchdog, the
session gets stuck. The sandbox is failed and fenced, but the prompt it
was booting for stays `pending` and nothing re-drives it. Recovery waits
for "your next message", and a bot-triggered session (e.g. a github-bot
review) never sends one. The prompt never runs and nothing is reported
back to the PR.

This is the part of ColeMurray#1600 (thanks @atirna) that is still open on `main`.
The rest of ColeMurray#1600 has already landed separately:

- connecting timeouts count toward the breaker (ColeMurray#1906)
- the breaker resets on prompt dispatch (ColeMurray#1906)
- Modal stop-by-id via `api_stop_sandbox` (ColeMurray#2146 and the lifecycle
refactor)

## Change

`failConnectTimeout` now tells the alarm handler what to do with the
queue, based on what happened to the generation:

| Generation after the timeout | Result | Queue |
| --- | --- | --- |
| Fenced and stopped, breaker still closed | `sandbox_terminated` |
Re-driven onto a replacement right away, the same path the heartbeat
watchdog already uses |
| Fenced and stopped, breaker now open | `{ kind:
"connect_retries_exhausted", reason }` | The boot prompt fails with
`reason`, like `boot_budget_exceeded`. Bots get a final failure instead
of silence. |
| Held retained boot | `sandbox_failed` (unchanged) | Shutdown owns
recovery |
| Provider cannot stop (late bridge may self-heal) | `sandbox_failed`
(unchanged) | Waits, as before |
| Replaced by another launch during the stop | `sandbox_failed` | The
replacement owns the queue |

The existing breaker (3 failures in 5 minutes, measured from attempt
start) limits how many times the re-drive repeats. The breaker is
checked right after this failure is recorded, before the stop await.

Other changes:

- `alarm/handler.ts` fails the boot prompt for any object result, not
just `boot_budget_exceeded`.
- `SandboxAlarmResult` now documents what each variant means for the
queue.
- `toCircuitBreakerState` replaces three copies of the row→state mapping
in `manager.ts`.
- The user-facing error for the re-drive case changes from "It will be
retried on your next message." to "Queued prompts will be retried on a
fresh sandbox."

## Not covered

If the watchdog fires while `createSandbox()` is still in flight, the
re-drive's `spawnSandbox` is skipped (a spawn is already running). The
late provider result is then destroyed as `startup_superseded` without
pumping the queue. This was already the case before this PR, and it
needs a provider call that takes longer than 4 minutes.

## Tests

- Unit (`alarm-connecting-watchdog-effects.test.ts`): a stoppable
timeout returns `sandbox_terminated`. The timeout that opens the breaker
returns `connect_retries_exhausted` and still fences and stops. A held
retained boot is left alone and returns `sandbox_failed`. Existing
expectations updated for the new result and message.
- Integration (`session-lifecycle-alarm-recovery.test.ts`, workerd +
D1), both failing on `main`:
- a pending github-sourced prompt behind a timed-out sandbox gets a
replacement spawn and stays `pending`
- with the breaker one failure short, the timeout fails that prompt with
the "after repeated attempts" reason
- the park helper now also keeps the warm spawn's `sandbox_preservation`
generation in sync with the rewritten row. Otherwise admission reads it
as a held foreign source, which never happens for a real boot.
- `control-plane` unit: `src/sandbox` + `src/session`, 77 files / 1703
tests pass.
- `control-plane` integration: `session-lifecycle-alarm-recovery`,
`sandbox-shutdown`, `websocket-sandbox`, 49 tests pass.
- `tsc --noEmit`, eslint, and prettier are clean.

---
*Created with
[Open-Inspect](https://open-inspect-prod.vercel.app/session/3c8c472777b15e6033a84357cd6aa188)*

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Pending prompts are retried on a replacement sandbox after a
connection timeout when the previous sandbox is confirmed stopped.
* Prompts now fail with a connection-timeout error when retries are
exhausted or the provider cannot confirm the sandbox has stopped.
* Queued work resumes after a sandbox launch completes, avoiding missed
processing when a timeout occurs during startup.
* **Documentation**
* Updated the debugging playbook to describe connection-timeout recovery
and failure conditions.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Cole Murray <2492022+ColeMurray@users.noreply.github.com>
Co-authored-by: waclaude <colemurray.cs+ghwaclaude@gmail.com>
# Conflicts:
#	.github/dependabot.yml
#	.github/workflows/terraform.yml
#	docs/SECRETS.md
#	docs/integrations/GITHUB.md
#	package-lock.json
#	package.json
#	packages/control-plane/package.json
#	packages/control-plane/src/db/automation-store.test.ts
#	packages/control-plane/src/router.policy.test.ts
#	packages/control-plane/src/routes/automation-crud.ts
#	packages/control-plane/src/routes/catalog.ts
#	packages/control-plane/src/routing/request-lifecycle.test.ts
#	packages/control-plane/src/routing/route-admission.ts
#	packages/control-plane/src/scheduler/scheduler.test.ts
#	packages/control-plane/src/session/callback-notification-service.test.ts
#	packages/control-plane/src/session/create-session-input.test.ts
#	packages/control-plane/src/session/initialize.test.ts
#	packages/control-plane/src/session/initialize.ts
#	packages/control-plane/test/integration/__snapshots__/hono-route-catalog-conformance.test.ts.snap
#	packages/control-plane/test/integration/__snapshots__/route-admission-matrix.test.ts.snap
#	packages/control-plane/test/integration/automation-invocations.test.ts
#	packages/control-plane/test/integration/automations-slack-route.test.ts
#	packages/control-plane/test/integration/cleanup.ts
#	packages/control-plane/test/integration/hono-route-catalog-conformance.test.ts
#	packages/control-plane/test/integration/scheduler.test.ts
#	packages/control-plane/test/integration/slack-channel-store.test.ts
#	packages/docs/package.json
#	packages/github-bot/src/github-auth.ts
#	packages/github-bot/src/handlers.ts
#	packages/github-bot/src/payload-schemas.ts
#	packages/github-bot/test/github-auth.test.ts
#	packages/github-bot/test/handlers.test.ts
#	packages/github-bot/test/payload-schemas.test.ts
#	packages/github-bot/test/webhook.test.ts
#	packages/modal-infra/uv.lock
#	packages/shared/package.json
#	packages/shared/src/types/audit-events.test.ts
#	packages/shared/src/types/automations.test.ts
#	packages/web/package.json
#	packages/web/src/components/automations/automation-form-policy.test.ts
#	packages/web/src/components/settings/integrations/github-global-settings-section.tsx
#	packages/web/src/components/settings/integrations/github-repo-overrides-section.tsx
#	packages/web/src/components/settings/settings-registry.test.ts
#	packages/web/src/hooks/use-automations.test.tsx
@coderabbitai

coderabbitai Bot commented Oct 5, 2026

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 1000 files, which is 700 over the limit of 300.

To get a review, reduce the PR to 300 files or fewer by splitting it into smaller PRs or changing its base branch.

Usage-priced reviews support at most 300 files.

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Team
  • Run ID: e6240447-e708-4bbe-ad6a-5917b4037f38
📥 Commits

Reviewing files that changed from the base of the PR and between a75897f and d061f40.

⛔ Files ignored due to path filters (5)
  • package-lock.json is excluded by !**/package-lock.json
  • packages/control-plane/test/integration/__snapshots__/hono-route-catalog-conformance.test.ts.snap is excluded by !**/*.snap
  • packages/control-plane/test/integration/__snapshots__/route-admission-matrix.test.ts.snap is excluded by !**/*.snap
  • packages/modal-infra/uv.lock is excluded by !**/*.lock
  • packages/sandbox-runtime/uv.lock is excluded by !**/*.lock
📒 Files selected for processing (1000)
  • .github/dependabot.yml
  • .github/workflows/ci-python.yml
  • .github/workflows/ci.yml
  • .github/workflows/coverage.yml
  • .github/workflows/terraform.yml
  • .gitignore
  • .prettierignore
  • CHANGELOG.md
  • CONTRIBUTING.md
  • README.md
  • docs/AUTH.md
  • docs/AUTOMATIONS.md
  • docs/CLAUDE_AGENT.md
  • docs/DEBUGGING_PLAYBOOK.md
  • docs/GETTING_STARTED.md
  • docs/HOW_IT_WORKS.md
  • docs/IMAGE_PREBUILD.md
  • docs/MEMORY.md
  • docs/MULTI_REPO_AUTOMATIONS.md
  • docs/SECRETS.md
  • docs/SETUP_GUIDE.md
  • docs/TEST_REDUCTION.md
  • docs/integrations/GITHUB.md
  • docs/integrations/LINEAR.md
  • docs/integrations/SLACK.md
  • docs/plans/managed-skills.md
  • eslint.config.js
  • knip.json
  • package.json
  • packages/control-plane/README.md
  • packages/control-plane/package.json
  • packages/control-plane/src/auth/model-provider-account-adapters.ts
  • packages/control-plane/src/auth/openai.ts
  • packages/control-plane/src/authorization/channel-scope.test.ts
  • packages/control-plane/src/authorization/channel-scope.ts
  • packages/control-plane/src/authorization/memory-access-factory.ts
  • packages/control-plane/src/authorization/memory-access.test.ts
  • packages/control-plane/src/authorization/memory-access.ts
  • packages/control-plane/src/authorization/owned-resource-admission.ts
  • packages/control-plane/src/authorization/request-audit.ts
  • packages/control-plane/src/authorization/session-admission.ts
  • packages/control-plane/src/authorization/session-shadow-audit.test.ts
  • packages/control-plane/src/authorization/session-shadow-audit.ts
  • packages/control-plane/src/authorization/session-socket-audit.test.ts
  • packages/control-plane/src/authorization/session-socket-audit.ts
  • packages/control-plane/src/authorization/slack-post-gate.test.ts
  • packages/control-plane/src/authorization/slack-post-gate.ts
  • packages/control-plane/src/autofix/handler.test.ts
  • packages/control-plane/src/autofix/service.test.ts
  • packages/control-plane/src/autofix/service.ts
  • packages/control-plane/src/automation/github-event-admission.test.ts
  • packages/control-plane/src/automation/github-event-admission.ts
  • packages/control-plane/src/automation/repository.test.ts
  • packages/control-plane/src/automation/session-target.test.ts
  • packages/control-plane/src/background-tasks.test-support.test.ts
  • packages/control-plane/src/cloudflare/background-tasks.test.ts
  • packages/control-plane/src/cloudflare/job-queue.test.ts
  • packages/control-plane/src/cloudflare/session-platform.test.ts
  • packages/control-plane/src/cloudflare/session-runtime-dispatch.test.ts
  • packages/control-plane/src/created-at-cursor.test.ts
  • packages/control-plane/src/created-at-cursor.ts
  • packages/control-plane/src/db/analytics-dashboard-store.test.ts
  • packages/control-plane/src/db/analytics-dashboard-store.ts
  • packages/control-plane/src/db/analytics-store.test.ts
  • packages/control-plane/src/db/analytics-store.ts
  • packages/control-plane/src/db/audit-event-cursor.ts
  • packages/control-plane/src/db/audit-event-store.test.ts
  • packages/control-plane/src/db/automation-model-provider-auth.test.ts
  • packages/control-plane/src/db/automation-status.test.ts
  • packages/control-plane/src/db/automation-store-invocations.test.ts
  • packages/control-plane/src/db/automation-store.test.ts
  • packages/control-plane/src/db/automation-store.ts
  • packages/control-plane/src/db/bulk-insert.test.ts
  • packages/control-plane/src/db/github-automation-store.ts
  • packages/control-plane/src/db/global-secrets.test.ts
  • packages/control-plane/src/db/image-build-finalization.test.ts
  • packages/control-plane/src/db/image-builds.test.ts
  • packages/control-plane/src/db/image-builds.ts
  • packages/control-plane/src/db/integration-settings.ts
  • packages/control-plane/src/db/json-columns.test.ts
  • packages/control-plane/src/db/lexical-fact-index.test.ts
  • packages/control-plane/src/db/lexical-fact-index.ts
  • packages/control-plane/src/db/like-pattern.test.ts
  • packages/control-plane/src/db/memory-preferences.ts
  • packages/control-plane/src/db/memory-queries.ts
  • packages/control-plane/src/db/memory-records.ts
  • packages/control-plane/src/db/model-preferences.test.ts
  • packages/control-plane/src/db/model-provider-account-atomic-writer.ts
  • packages/control-plane/src/db/model-provider-accounts.test.ts
  • packages/control-plane/src/db/pr-autofix-feedback-store.test.ts
  • packages/control-plane/src/db/provider-account-authorizations.ts
  • packages/control-plane/src/db/provider-account-credentials.test.ts
  • packages/control-plane/src/db/pull-request-analytics-store.test.ts
  • packages/control-plane/src/db/repo-secrets.test.ts
  • packages/control-plane/src/db/scm-settings.test.ts
  • packages/control-plane/src/db/session-collaborators.ts
  • packages/control-plane/src/db/session-export-cursor.ts
  • packages/control-plane/src/db/session-export-store.ts
  • packages/control-plane/src/db/session-inbox-cursor.test.ts
  • packages/control-plane/src/db/session-index.test.ts
  • packages/control-plane/src/db/session-index.ts
  • packages/control-plane/src/db/session-list-predicates.test.ts
  • packages/control-plane/src/db/session-memory-selections.ts
  • packages/control-plane/src/db/session-memory-write-guard.ts
  • packages/control-plane/src/db/session-run-store.test.ts
  • packages/control-plane/src/db/session-scope-store.ts
  • packages/control-plane/src/db/session-status-projection-store.test.ts
  • packages/control-plane/src/db/session-visibility.test.ts
  • packages/control-plane/src/db/slack-channel-store.ts
  • packages/control-plane/src/db/sql-cache-store.test.ts
  • packages/control-plane/src/db/sql-fragment.test.ts
  • packages/control-plane/src/db/sql-fragment.ts
  • packages/control-plane/src/db/team-channel-bindings.test.ts
  • packages/control-plane/src/db/team-channel-bindings.ts
  • packages/control-plane/src/db/teams.ts
  • packages/control-plane/src/db/user-merge.ts
  • packages/control-plane/src/http/bounded-body.test.ts
  • packages/control-plane/src/http/bounded-body.ts
  • packages/control-plane/src/http/request-context.ts
  • packages/control-plane/src/image-builds/daytona-adapter.test.ts
  • packages/control-plane/src/image-builds/finalization-consumer.test.ts
  • packages/control-plane/src/image-builds/finalizer.ts
  • packages/control-plane/src/image-builds/fingerprint.test.ts
  • packages/control-plane/src/image-builds/maintenance.test.ts
  • packages/control-plane/src/image-builds/planner.test.ts
  • packages/control-plane/src/image-builds/provenance.test.ts
  • packages/control-plane/src/image-builds/provider-policy.test.ts
  • packages/control-plane/src/image-builds/reaper.test.ts
  • packages/control-plane/src/image-builds/reaper.ts
  • packages/control-plane/src/image-builds/scheduler.test.ts
  • packages/control-plane/src/image-builds/scope.test.ts
  • packages/control-plane/src/image-builds/session-cleanup.test.ts
  • packages/control-plane/src/image-builds/types.ts
  • packages/control-plane/src/image-builds/workflow.test.ts
  • packages/control-plane/src/jobs.test.ts
  • packages/control-plane/src/media.ts
  • packages/control-plane/src/memory/dto.ts
  • packages/control-plane/src/memory/errors.ts
  • packages/control-plane/src/memory/fact-search.test.ts
  • packages/control-plane/src/memory/fact-search.ts
  • packages/control-plane/src/memory/lifecycle.ts
  • packages/control-plane/src/memory/partition.ts
  • packages/control-plane/src/memory/render.ts
  • packages/control-plane/src/memory/selection.test.ts
  • packages/control-plane/src/memory/selection.ts
  • packages/control-plane/src/memory/session-memory-selector-factory.ts
  • packages/control-plane/src/memory/session-memory-selector.test.ts
  • packages/control-plane/src/memory/session-memory-selector.ts
  • packages/control-plane/src/memory/session-memory-service.test.ts
  • packages/control-plane/src/memory/session-memory-service.ts
  • packages/control-plane/src/memory/session-rules.ts
  • packages/control-plane/src/memory/sources.ts
  • packages/control-plane/src/memory/types.ts
  • packages/control-plane/src/model-provider-accounts/account-lifecycle-policy.test.ts
  • packages/control-plane/src/model-provider-accounts/automation-provider-selection.test.ts
  • packages/control-plane/src/model-provider-accounts/selection-policy.test.ts
  • packages/control-plane/src/node/host-alarm-index.ts
  • packages/control-plane/src/node/job-store.test.ts
  • packages/control-plane/src/node/job-store.ts
  • packages/control-plane/src/node/migrate.test.ts
  • packages/control-plane/src/router.analytics.test.ts
  • packages/control-plane/src/router.autofix.test.ts
  • packages/control-plane/src/router.create-session.test.ts
  • packages/control-plane/src/router.policy.test.ts
  • packages/control-plane/src/router.session-prompt.test.ts
  • packages/control-plane/src/router.spawn-child.test.ts
  • packages/control-plane/src/routes/analytics.test.ts
  • packages/control-plane/src/routes/analytics.ts
  • packages/control-plane/src/routes/audit-events.test.ts
  • packages/control-plane/src/routes/automation-create.test.ts
  • packages/control-plane/src/routes/automation-crud.ts
  • packages/control-plane/src/routes/automation-runs.test.ts
  • packages/control-plane/src/routes/automation-slack-settings.ts
  • packages/control-plane/src/routes/automation-validation.test.ts
  • packages/control-plane/src/routes/automation-validation.ts
  • packages/control-plane/src/routes/body.test.ts
  • packages/control-plane/src/routes/catalog.ts
  • packages/control-plane/src/routes/channel-bindings.ts
  • packages/control-plane/src/routes/environment-secrets.test.ts
  • packages/control-plane/src/routes/environments-catalog.test.ts
  • packages/control-plane/src/routes/environments.test.ts
  • packages/control-plane/src/routes/environments.ts
  • packages/control-plane/src/routes/github-route.ts
  • packages/control-plane/src/routes/integration-settings.ts
  • packages/control-plane/src/routes/memories.ts
  • packages/control-plane/src/routes/memory-errors.ts
  • packages/control-plane/src/routes/model-preferences.ts
  • packages/control-plane/src/routes/provider-runtime-credentials.test.ts
  • packages/control-plane/src/routes/query.test.ts
  • packages/control-plane/src/routes/repos.ts
  • packages/control-plane/src/routes/repository-params.test.ts
  • packages/control-plane/src/routes/responses/stored-object-response.test.ts
  • packages/control-plane/src/routes/secret-request-schemas.test.ts
  • packages/control-plane/src/routes/session-child-spawn.ts
  • packages/control-plane/src/routes/session-children.ts
  • packages/control-plane/src/routes/session-create.ts
  • packages/control-plane/src/routes/session-export.test.ts
  • packages/control-plane/src/routes/session-export.ts
  • packages/control-plane/src/routes/session-index.ts
  • packages/control-plane/src/routes/session-media-artifacts.test.ts
  • packages/control-plane/src/routes/session-memories.ts
  • packages/control-plane/src/routes/sessions.ts
  • packages/control-plane/src/routes/shared.test.ts
  • packages/control-plane/src/routes/shared.ts
  • packages/control-plane/src/routes/skills.list.test.ts
  • packages/control-plane/src/routes/slack-notify.test.ts
  • packages/control-plane/src/routes/slack-notify.ts
  • packages/control-plane/src/routes/team-channel-bindings.ts
  • packages/control-plane/src/routes/team-ownership.ts
  • packages/control-plane/src/routes/team-secrets.test.ts
  • packages/control-plane/src/routes/teams.ts
  • packages/control-plane/src/routes/workspace-repository-authorization.ts
  • packages/control-plane/src/routing/authorization-evidence.ts
  • packages/control-plane/src/routing/hono-app.ts
  • packages/control-plane/src/routing/request-lifecycle.test.ts
  • packages/control-plane/src/routing/route-admission.ts
  • packages/control-plane/src/routing/route-params.test.ts
  • packages/control-plane/src/routing/team-admission.ts
  • packages/control-plane/src/sandbox/boot-phase.test.ts
  • packages/control-plane/src/sandbox/client.ts
  • packages/control-plane/src/sandbox/daytona-rest-client.ts
  • packages/control-plane/src/sandbox/execution-budget.test.ts
  • packages/control-plane/src/sandbox/lifecycle/alarm-boot-budget-effects.test.ts
  • packages/control-plane/src/sandbox/lifecycle/alarm-connecting-watchdog-effects.test.ts
  • packages/control-plane/src/sandbox/lifecycle/alarm-effects.test.ts
  • packages/control-plane/src/sandbox/lifecycle/alarm-heartbeat-effects.test.ts
  • packages/control-plane/src/sandbox/lifecycle/alarm-policy.test.ts
  • packages/control-plane/src/sandbox/lifecycle/alarm-policy.ts
  • packages/control-plane/src/sandbox/lifecycle/allocation-cleanup.test.ts
  • packages/control-plane/src/sandbox/lifecycle/boot-failure-message.ts
  • packages/control-plane/src/sandbox/lifecycle/decisions.test.ts
  • packages/control-plane/src/sandbox/lifecycle/decisions.ts
  • packages/control-plane/src/sandbox/lifecycle/eligibility.test.ts
  • packages/control-plane/src/sandbox/lifecycle/image-selection.test.ts
  • packages/control-plane/src/sandbox/lifecycle/image-selection.ts
  • packages/control-plane/src/sandbox/lifecycle/launch-context.test.ts
  • packages/control-plane/src/sandbox/lifecycle/launch-orchestration.test.ts
  • packages/control-plane/src/sandbox/lifecycle/manager-reconnect.test.ts
  • packages/control-plane/src/sandbox/lifecycle/manager.test.ts
  • packages/control-plane/src/sandbox/lifecycle/manager.ts
  • packages/control-plane/src/sandbox/lifecycle/pending-vm-respawn.test.ts
  • packages/control-plane/src/sandbox/lifecycle/ports.ts
  • packages/control-plane/src/sandbox/lifecycle/shutdown-policy.test.ts
  • packages/control-plane/src/sandbox/lifecycle/vm-resolve-alarm.test.ts
  • packages/control-plane/src/sandbox/lifecycle/vm-resolve.test-fixture.ts
  • packages/control-plane/src/sandbox/lifecycle/vm-resolve.test.ts
  • packages/control-plane/src/sandbox/lifecycle/vm-startup-reconciliation.test.ts
  • packages/control-plane/src/sandbox/lifecycle/vm-startup-reconciliation.ts
  • packages/control-plane/src/sandbox/lifecycle/watchdog-effects.ts
  • packages/control-plane/src/sandbox/managed-provider-env.test.ts
  • packages/control-plane/src/sandbox/provider-name.test.ts
  • packages/control-plane/src/sandbox/provider.test.ts
  • packages/control-plane/src/sandbox/providers/daytona-provider.terminal.test.ts
  • packages/control-plane/src/sandbox/providers/daytona-provider.test.ts
  • packages/control-plane/src/sandbox/providers/e2b-provider-shutdown.test.ts
  • packages/control-plane/src/sandbox/providers/e2b-provider.test-helpers.ts
  • packages/control-plane/src/sandbox/providers/modal-provider.test.ts
  • packages/control-plane/src/sandbox/providers/opencomputer-provider.test.ts
  • packages/control-plane/src/sandbox/providers/pending-vm-reference.test.ts
  • packages/control-plane/src/sandbox/providers/port-resolution.test.ts
  • packages/control-plane/src/sandbox/providers/vercel/base-snapshot.test.ts
  • packages/control-plane/src/sandbox/providers/vercel/provider.test.ts
  • packages/control-plane/src/sandbox/runtime-manifest.test.ts
  • packages/control-plane/src/sandbox/sandbox-env.test.ts
  • packages/control-plane/src/sandbox/sandbox-status.test.ts
  • packages/control-plane/src/scheduler/compose-automation-prompt.test.ts
  • packages/control-plane/src/scheduler/invocation-outcome.ts
  • packages/control-plane/src/scheduler/scheduler.test.ts
  • packages/control-plane/src/scheduler/scheduler.ts
  • packages/control-plane/src/scheduler/slack-completion.test.ts
  • packages/control-plane/src/session/alarm/handler.test.ts
  • packages/control-plane/src/session/alarm/handler.ts
  • packages/control-plane/src/session/alarm/scheduler.test.ts
  • packages/control-plane/src/session/artifact-metadata.test.ts
  • packages/control-plane/src/session/artifact-repository.test.ts
  • packages/control-plane/src/session/budget-service.test.ts
  • packages/control-plane/src/session/callback-delivery.test.ts
  • packages/control-plane/src/session/callback-delivery.ts
  • packages/control-plane/src/session/callback-notification-service.test.ts
  • packages/control-plane/src/session/callback-notification-service.ts
  • packages/control-plane/src/session/components.credentials.test.ts
  • packages/control-plane/src/session/components.ts
  • packages/control-plane/src/session/connection-authenticator-client-access.test.ts
  • packages/control-plane/src/session/connection-authenticator.test.ts
  • packages/control-plane/src/session/connection-authenticator.ts
  • packages/control-plane/src/session/create-session-input.test.ts
  • packages/control-plane/src/session/diffs/store.test.ts
  • packages/control-plane/src/session/enqueue-prompt-contract.test.ts
  • packages/control-plane/src/session/event-cursor.ts
  • packages/control-plane/src/session/event-repository.test.ts
  • packages/control-plane/src/session/event-stream.test.ts
  • packages/control-plane/src/session/http/handlers/attachments.handler.test.ts
  • packages/control-plane/src/session/http/handlers/child-session-summary.ts
  • packages/control-plane/src/session/http/handlers/participants.handler.test.ts
  • packages/control-plane/src/session/http/handlers/pull-request.handler.test.ts
  • packages/control-plane/src/session/http/handlers/session-budget.handler.test.ts
  • packages/control-plane/src/session/http/handlers/session-diffs.handler.test.ts
  • packages/control-plane/src/session/http/handlers/session-init.handler.test.ts
  • packages/control-plane/src/session/http/handlers/session-lifecycle.handler.test.ts
  • packages/control-plane/src/session/http/handlers/session-lifecycle.handler.ts
  • packages/control-plane/src/session/http/routes.test.ts
  • packages/control-plane/src/session/initialize.test.ts
  • packages/control-plane/src/session/initialize.ts
  • packages/control-plane/src/session/message-cursor.test.ts
  • packages/control-plane/src/session/message-queue.test.ts
  • packages/control-plane/src/session/message-queue.ts
  • packages/control-plane/src/session/message-repository.test.ts
  • packages/control-plane/src/session/message-repository.ts
  • packages/control-plane/src/session/message-router.ts
  • packages/control-plane/src/session/messenger.test.ts
  • packages/control-plane/src/session/participant-repository.test.ts
  • packages/control-plane/src/session/participant-service.test.ts
  • packages/control-plane/src/session/participant-service.ts
  • packages/control-plane/src/session/pinned.ts
  • packages/control-plane/src/session/ports.ts
  • packages/control-plane/src/session/presence-service.test.ts
  • packages/control-plane/src/session/presence-service.ts
  • packages/control-plane/src/session/provider-account-resolution.test.ts
  • packages/control-plane/src/session/public-session-id.test.ts
  • packages/control-plane/src/session/pull-request-service.test.ts
  • packages/control-plane/src/session/pull-request-snapshot.test.ts
  • packages/control-plane/src/session/repository-target.test.ts
  • packages/control-plane/src/session/runtime-client.test.ts
  • packages/control-plane/src/session/sandbox-access-reader.test.ts
  • packages/control-plane/src/session/sandbox-events/processor.test.ts
  • packages/control-plane/src/session/sandbox-events/processor.ts
  • packages/control-plane/src/session/sandbox-events/runtime.handler.test.ts
  • packages/control-plane/src/session/sandbox-push-service.test.ts
  • packages/control-plane/src/session/sandbox-repository.test.ts
  • packages/control-plane/src/session/sandbox-shutdown-repository.test.ts
  • packages/control-plane/src/session/sandbox-shutdown-safety.test.ts
  • packages/control-plane/src/session/services/session-attachment-storage.test.ts
  • packages/control-plane/src/session/services/session-attachment-storage.ts
  • packages/control-plane/src/session/session-attachment-repository.test.ts
  • packages/control-plane/src/session/session-attachment-resolver.test.ts
  • packages/control-plane/src/session/session-core-repository.test.ts
  • packages/control-plane/src/session/session-logger.test.ts
  • packages/control-plane/src/session/session-status-service.test.ts
  • packages/control-plane/src/session/session-status-service.ts
  • packages/control-plane/src/session/session-target-secrets.test.ts
  • packages/control-plane/src/session/spawn-context.test.ts
  • packages/control-plane/src/session/stop-execution.test.ts
  • packages/control-plane/src/session/title.ts
  • packages/control-plane/src/session/tunnel-urls.test.ts
  • packages/control-plane/src/skills/content-addressing.test.ts
  • packages/control-plane/src/skills/skill-markdown.test.ts
  • packages/control-plane/src/source-control/config.test.ts
  • packages/control-plane/src/source-control/provider-from-env.test.ts
  • packages/control-plane/src/source-control/repository-scope.test.ts
  • packages/control-plane/src/source-control/session-scope.test.ts
  • packages/control-plane/src/webhooks/automation-event.test.ts
  • packages/control-plane/src/webhooks/automation-webhook.ts
  • packages/control-plane/src/webhooks/pull-request-lifecycle.test.ts
  • packages/control-plane/test/conformance/memory-search-fixtures.ts
  • packages/control-plane/test/integration/analytics.test.ts
  • packages/control-plane/test/integration/autofix-recovery.test.ts
  • packages/control-plane/test/integration/automation-executor-permissions.test.ts
  • packages/control-plane/test/integration/automation-invocation-reads.test.ts
  • packages/control-plane/test/integration/automation-invocations.test.ts
  • packages/control-plane/test/integration/automation-team-execution.test.ts
  • packages/control-plane/test/integration/automation-team-grants.test.ts
  • packages/control-plane/test/integration/automations-slack-route.test.ts
  • packages/control-plane/test/integration/cleanup.ts
  • packages/control-plane/test/integration/environments-catalog.test.ts
  • packages/control-plane/test/integration/github-automation-routing.test.ts
  • packages/control-plane/test/integration/github-route.test.ts
  • packages/control-plane/test/integration/helpers.ts
  • packages/control-plane/test/integration/hono-route-catalog-conformance.test.ts
  • packages/control-plane/test/integration/image-build-credential-scope.test.ts
  • packages/control-plane/test/integration/integration-settings.test.ts
  • packages/control-plane/test/integration/invocation-fixtures.ts
  • packages/control-plane/test/integration/linear-integration-settings.test.ts
  • packages/control-plane/test/integration/managed-skills.test.ts
  • packages/control-plane/test/integration/memories-access.test.ts
  • packages/control-plane/test/integration/memories-routes.test.ts
  • packages/control-plane/test/integration/memories-search.test.ts
  • packages/control-plane/test/integration/memories.test.ts
  • packages/control-plane/test/integration/memory-test-helpers.ts
  • packages/control-plane/test/integration/migration-0085-team-default-visibility.test.ts
  • packages/control-plane/test/integration/ownership-test-helpers.ts
  • packages/control-plane/test/integration/prompt-enqueue.test.ts
  • packages/control-plane/test/integration/route-admission-matrix.test.ts
  • packages/control-plane/test/integration/sandbox-shutdown.test.ts
  • packages/control-plane/test/integration/sandbox-state-retention.test.ts
  • packages/control-plane/test/integration/scheduler-events.test.ts
  • packages/control-plane/test/integration/scheduler-slack-events.test.ts
  • packages/control-plane/test/integration/scheduler-slack-team-steering.test.ts
  • packages/control-plane/test/integration/scheduler.test.ts
  • packages/control-plane/test/integration/service-auth.test.ts
  • packages/control-plane/test/integration/session-access-routes.test.ts
  • packages/control-plane/test/integration/session-environment-ownership.test.ts
  • packages/control-plane/test/integration/session-export-store.test.ts
  • packages/control-plane/test/integration/session-export.test.ts
  • packages/control-plane/test/integration/session-lifecycle-alarm-recovery.test.ts
  • packages/control-plane/test/integration/session-provider-auth.test.ts
  • packages/control-plane/test/integration/session-scope-routes.test.ts
  • packages/control-plane/test/integration/session-shadow-audit.test.ts
  • packages/control-plane/test/integration/slack-channel-store.test.ts
  • packages/control-plane/test/integration/slack-notify.test.ts
  • packages/control-plane/test/integration/slack-post-gates.test.ts
  • packages/control-plane/test/integration/spawn-children.test.ts
  • packages/control-plane/test/integration/team-channel-bindings.test.ts
  • packages/control-plane/test/integration/team-grants.test.ts
  • packages/control-plane/test/integration/teams-routes.test.ts
  • packages/control-plane/test/integration/webhooks-github-pr-lifecycle.test.ts
  • packages/control-plane/test/integration/webhooks.test.ts
  • packages/control-plane/test/integration/websocket-client.test.ts
  • packages/control-plane/test/integration/websocket-sandbox.test.ts
  • packages/control-plane/test/integration/websocket-session-access.test.ts
  • packages/control-plane/test/smoke/run-smoke.mjs
  • packages/control-plane/vitest.config.ts
  • packages/control-plane/vitest.coverage.config.ts
  • packages/docs/content/docs/administration/analytics.mdx
  • packages/docs/content/docs/administration/audit-log.mdx
  • packages/docs/content/docs/administration/data-controls.mdx
  • packages/docs/content/docs/administration/deployment.mdx
  • packages/docs/content/docs/administration/meta.json
  • packages/docs/content/docs/administration/security.mdx
  • packages/docs/content/docs/administration/teams.mdx
  • packages/docs/content/docs/administration/workspace-access.mdx
  • packages/docs/content/docs/automations/first-automation.mdx
  • packages/docs/content/docs/automations/github-events.mdx
  • packages/docs/content/docs/automations/inbound-webhooks.mdx
  • packages/docs/content/docs/automations/index.mdx
  • packages/docs/content/docs/automations/multi-repository.mdx
  • packages/docs/content/docs/automations/schedules.mdx
  • packages/docs/content/docs/automations/slack-messages.mdx
  • packages/docs/content/docs/configure/environments.mdx
  • packages/docs/content/docs/configure/lifecycle-scripts.mdx
  • packages/docs/content/docs/configure/prebuilt-images.mdx
  • packages/docs/content/docs/configure/secrets.mdx
  • packages/docs/content/docs/getting-started/core-concepts.mdx
  • packages/docs/content/docs/getting-started/quickstart.mdx
  • packages/docs/content/docs/index.mdx
  • packages/docs/content/docs/integrations/github.mdx
  • packages/docs/content/docs/integrations/index.mdx
  • packages/docs/content/docs/integrations/linear.mdx
  • packages/docs/content/docs/integrations/slack.mdx
  • packages/docs/content/docs/models/agent-harnesses.mdx
  • packages/docs/content/docs/models/choosing-a-model.mdx
  • packages/docs/content/docs/models/provider-accounts.mdx
  • packages/docs/content/docs/reference/faq.mdx
  • packages/docs/content/docs/reference/sandbox-environment.mdx
  • packages/docs/content/docs/sessions/child-sessions.mdx
  • packages/docs/content/docs/sessions/follow-ups-and-stopping.mdx
  • packages/docs/content/docs/sessions/inbox-and-search.mdx
  • packages/docs/content/docs/sessions/multiplayer-and-sharing.mdx
  • packages/docs/content/docs/sessions/sandbox-tools.mdx
  • packages/docs/content/docs/sessions/session-page.mdx
  • packages/docs/package.json
  • packages/github-bot/README.md
  • packages/github-bot/package.json
  • packages/github-bot/src/github-auth.ts
  • packages/github-bot/src/handlers.ts
  • packages/github-bot/src/index.ts
  • packages/github-bot/src/model-selection.ts
  • packages/github-bot/src/payload-schemas.ts
  • packages/github-bot/src/review-start.ts
  • packages/github-bot/src/session-client.ts
  • packages/github-bot/src/session-startup.ts
  • packages/github-bot/src/session-target.ts
  • packages/github-bot/test/autofix-ingress.test.ts
  • packages/github-bot/test/github-auth.test.ts
  • packages/github-bot/test/handlers.test.ts
  • packages/github-bot/test/model-selection.test.ts
  • packages/github-bot/test/payload-schemas.test.ts
  • packages/github-bot/test/review-start-marker.test.ts
  • packages/github-bot/test/webhook.test.ts
  • packages/github-bot/vitest.config.ts
  • packages/linear-bot/README.md
  • packages/linear-bot/package.json
  • packages/linear-bot/src/__tests__/pure-functions.test.ts
  • packages/linear-bot/src/cached-resource.ts
  • packages/linear-bot/src/callbacks.complete.test.ts
  • packages/linear-bot/src/callbacks.scope.test.ts
  • packages/linear-bot/src/callbacks.ts
  • packages/linear-bot/src/classifier/index.test.ts
  • packages/linear-bot/src/classifier/index.ts
  • packages/linear-bot/src/classifier/repos.test.ts
  • packages/linear-bot/src/classifier/repos.ts
  • packages/linear-bot/src/completion/extractor.test.ts
  • packages/linear-bot/src/completion/extractor.ts
  • packages/linear-bot/src/control-plane.test.ts
  • packages/linear-bot/src/control-plane.ts
  • packages/linear-bot/src/environments.test.ts
  • packages/linear-bot/src/environments.ts
  • packages/linear-bot/src/index.ts
  • packages/linear-bot/src/kv-store.test.ts
  • packages/linear-bot/src/launch-admission.ts
  • packages/linear-bot/src/model-resolution.ts
  • packages/linear-bot/src/prompts.ts
  • packages/linear-bot/src/target-resolution.ts
  • packages/linear-bot/src/types.ts
  • packages/linear-bot/src/utils/integration-config.test.ts
  • packages/linear-bot/src/utils/integration-config.ts
  • packages/linear-bot/src/utils/linear-client.ts
  • packages/linear-bot/src/webhook-handler.harness.test.ts
  • packages/linear-bot/src/webhook-handler.test.ts
  • packages/linear-bot/src/webhook-handler.ts
  • packages/linear-bot/vitest.config.ts
  • packages/mcp-server/package.json
  • packages/modal-infra/README.md
  • packages/modal-infra/pyproject.toml
  • packages/modal-infra/tests/test_agent_slack_notify_env.py
  • packages/modal-infra/tests/test_code_server.py
  • packages/modal-infra/tests/test_sandbox_env_vars.py
  • packages/modal-infra/tests/test_sandbox_launch.py
  • packages/modal-infra/tests/test_sandbox_resources.py
  • packages/modal-infra/tests/test_ttyd.py
  • packages/sandbox-runtime/pyproject.toml
  • packages/sandbox-runtime/src/sandbox_runtime/activity_supervisor.py
  • packages/sandbox-runtime/src/sandbox_runtime/boot_event_relay.py
  • packages/sandbox-runtime/src/sandbox_runtime/boot_events.py
  • packages/sandbox-runtime/src/sandbox_runtime/bridge.py
  • packages/sandbox-runtime/src/sandbox_runtime/control_plane_fetch.py
  • packages/sandbox-runtime/src/sandbox_runtime/durable_files.py
  • packages/sandbox-runtime/src/sandbox_runtime/entrypoint.py
  • packages/sandbox-runtime/src/sandbox_runtime/event_forwarder.py
  • packages/sandbox-runtime/src/sandbox_runtime/harness/__init__.py
  • packages/sandbox-runtime/src/sandbox_runtime/harness/claude.py
  • packages/sandbox-runtime/src/sandbox_runtime/harness/claude_env.py
  • packages/sandbox-runtime/src/sandbox_runtime/harness/claude_logging.py
  • packages/sandbox-runtime/src/sandbox_runtime/harness/claude_tools.py
  • packages/sandbox-runtime/src/sandbox_runtime/harness/claude_translate.py
  • packages/sandbox-runtime/src/sandbox_runtime/harness/memory_tools.py
  • packages/sandbox-runtime/src/sandbox_runtime/harness/tool_results.py
  • packages/sandbox-runtime/src/sandbox_runtime/image_build_context_start.py
  • packages/sandbox-runtime/src/sandbox_runtime/managed_skills.py
  • packages/sandbox-runtime/src/sandbox_runtime/memories.py
  • packages/sandbox-runtime/src/sandbox_runtime/memory_contract.json
  • packages/sandbox-runtime/src/sandbox_runtime/memory_contract.py
  • packages/sandbox-runtime/src/sandbox_runtime/opencode_server.py
  • packages/sandbox-runtime/src/sandbox_runtime/runtime_manifest.json
  • packages/sandbox-runtime/src/sandbox_runtime/supervisor.py
  • packages/sandbox-runtime/src/sandbox_runtime/tools/_memory-contract.js
  • packages/sandbox-runtime/src/sandbox_runtime/tools/_memory.js
  • packages/sandbox-runtime/src/sandbox_runtime/tools/memory_read.js
  • packages/sandbox-runtime/src/sandbox_runtime/tools/memory_search.js
  • packages/sandbox-runtime/src/sandbox_runtime/tools/memory_write.js
  • packages/sandbox-runtime/src/sandbox_runtime/tools/slack-notify.js
  • packages/sandbox-runtime/tests/claude_fakes.py
  • packages/sandbox-runtime/tests/memory-tools.test.mjs
  • packages/sandbox-runtime/tests/test_boot_attach.py
  • packages/sandbox-runtime/tests/test_bridge_ack.py
  • packages/sandbox-runtime/tests/test_bridge_attachments.py
  • packages/sandbox-runtime/tests/test_bridge_cost_report.py
  • packages/sandbox-runtime/tests/test_bridge_event_buffer.py
  • packages/sandbox-runtime/tests/test_bridge_message_tracking.py
  • packages/sandbox-runtime/tests/test_bridge_push.py
  • packages/sandbox-runtime/tests/test_bridge_reconnection.py
  • packages/sandbox-runtime/tests/test_claude_env.py
  • packages/sandbox-runtime/tests/test_claude_harness.py
  • packages/sandbox-runtime/tests/test_claude_logging.py
  • packages/sandbox-runtime/tests/test_claude_trajectory.py
  • packages/sandbox-runtime/tests/test_claude_translate.py
  • packages/sandbox-runtime/tests/test_event_forwarder.py
  • packages/sandbox-runtime/tests/test_managed_skills.py
  • packages/sandbox-runtime/tests/test_memories.py
  • packages/sandbox-runtime/tests/test_opencode_client.py
  • packages/sandbox-runtime/tests/test_opencode_reasoning_contract.py
  • packages/sandbox-runtime/tests/test_opencode_step_ids.py
  • packages/sandbox-runtime/tests/test_prompt_stream.py
  • packages/sandbox-runtime/tests/test_push_operation.py
  • packages/sandbox-runtime/tests/test_repository_boot_phases.py
  • packages/sandbox-runtime/tests/test_supervisor_early_connect.py
  • packages/sandbox-runtime/tests/test_supervisor_lifecycle.py
  • packages/sandbox-runtime/tests/test_transport_diagnostics.py
  • packages/shared/package.json
  • packages/shared/src/app-name.test.ts
  • packages/shared/src/classification.test.ts
  • packages/shared/src/classification.ts
  • packages/shared/src/completion/extractor.test.ts
  • packages/shared/src/completion/extractor.ts
  • packages/shared/src/harnesses.test.ts
  • packages/shared/src/harnesses.ts
  • packages/shared/src/inline-prompt-flags.test.ts
  • packages/shared/src/inline-prompt-flags.ts
  • packages/shared/src/memory-tools.test.ts
  • packages/shared/src/memory-tools.ts
  • packages/shared/src/pull-request-tool.test.ts
  • packages/shared/src/rbac.test.ts
  • packages/shared/src/rbac.ts
  • packages/shared/src/service-auth.ts
  • packages/shared/src/slack/channel-contract.test.ts
  • packages/shared/src/slack/client.test.ts
  • packages/shared/src/slack/client.ts
  • packages/shared/src/slack/types.test.ts
  • packages/shared/src/slack/types.ts
  • packages/shared/src/triggers/github/normalizer.test.ts
  • packages/shared/src/triggers/github/normalizer.ts
  • packages/shared/src/triggers/github/webhook-types.ts
  • packages/shared/src/triggers/glob.test.ts
  • packages/shared/src/triggers/sentry/conditions.test.ts
  • packages/shared/src/triggers/slack/conditions.ts
  • packages/shared/src/triggers/testing.ts
  • packages/shared/src/triggers/types.test.ts
  • packages/shared/src/triggers/types.ts
  • packages/shared/src/types/analytics.ts
  • packages/shared/src/types/artifacts.test.ts
  • packages/shared/src/types/audit-events.test.ts
  • packages/shared/src/types/audit-events.ts
  • packages/shared/src/types/automations.test.ts
  • packages/shared/src/types/automations.ts
  • packages/shared/src/types/commit-signing.test.ts
  • packages/shared/src/types/environments.test.ts
  • packages/shared/src/types/github-identity.test.ts
  • packages/shared/src/types/image-builds.test.ts
  • packages/shared/src/types/index.ts
  • packages/shared/src/types/integrations.test.ts
  • packages/shared/src/types/integrations.ts
  • packages/shared/src/types/keyboard-shortcuts.ts
  • packages/shared/src/types/memories.test.ts
  • packages/shared/src/types/memories.ts
  • packages/shared/src/types/provider-accounts.ts
  • packages/shared/src/types/repository-catalog.test.ts
  • packages/shared/src/types/sandbox-events.test.ts
  • packages/shared/src/types/sandbox-events.ts
  • packages/shared/src/types/sandbox-shutdown.test.ts
  • packages/shared/src/types/session-access.ts
  • packages/shared/src/types/session-activity.test.ts
  • packages/shared/src/types/session-api.test.ts
  • packages/shared/src/types/session-api.ts
  • packages/shared/src/types/session-archive.test.ts
  • packages/shared/src/types/team-access.test.ts
  • packages/shared/src/types/team-access.ts
  • packages/shared/src/types/team-channel-bindings.test.ts
  • packages/shared/src/types/team-channel-bindings.ts
  • packages/shared/src/types/teams.test.ts
  • packages/shared/src/types/teams.ts
  • packages/shared/src/types/type-contracts.test.ts
  • packages/shared/vitest.config.ts
  • packages/slack-bot/package.json
  • packages/slack-bot/src/activity-status.ts
  • packages/slack-bot/src/app-home/models.test.ts
  • packages/slack-bot/src/app-home/slack-types.ts
  • packages/slack-bot/src/app.ts
  • packages/slack-bot/src/attachments.test.ts
  • packages/slack-bot/src/attachments.ts
  • packages/slack-bot/src/callbacks.test.ts
  • packages/slack-bot/src/callbacks.ts
  • packages/slack-bot/src/channel-bindings.ts
  • packages/slack-bot/src/classifier/cached-resource.ts
  • packages/slack-bot/src/classifier/catalog.ts
  • packages/slack-bot/src/classifier/control-plane.ts
  • packages/slack-bot/src/classifier/environments.test.ts
  • packages/slack-bot/src/classifier/environments.ts
  • packages/slack-bot/src/classifier/index.test.ts
  • packages/slack-bot/src/classifier/index.ts
  • packages/slack-bot/src/classifier/no-repository-classification.test.ts
  • packages/slack-bot/src/classifier/repos.test.ts
  • packages/slack-bot/src/classifier/repos.ts
  • packages/slack-bot/src/completion/consumer.test.ts
  • packages/slack-bot/src/completion/consumer.ts
  • packages/slack-bot/src/completion/delivery.test.ts
  • packages/slack-bot/src/completion/delivery.ts
  • packages/slack-bot/src/completion/extractor.test.ts
  • packages/slack-bot/src/completion/extractor.ts
  • packages/slack-bot/src/completion/media-upload.test.ts
  • packages/slack-bot/src/completion/media-upload.ts
  • packages/slack-bot/src/dm-utils.test.ts
  • packages/slack-bot/src/events/message-handler.ts
  • packages/slack-bot/src/forwarded-messages.test.ts
  • packages/slack-bot/src/index.test.ts
  • packages/slack-bot/src/inline-flags.test.ts
  • packages/slack-bot/src/inline-flags.ts
  • packages/slack-bot/src/interaction-payload.test.ts
  • packages/slack-bot/src/interaction-payload.ts
  • packages/slack-bot/src/interactions/target-selection.test.ts
  • packages/slack-bot/src/interactions/target-selection.ts
  • packages/slack-bot/src/messages/blocks.test.ts
  • packages/slack-bot/src/messages/context.test.ts
  • packages/slack-bot/src/pending-requests/pending-request-store.test.ts
  • packages/slack-bot/src/pending-requests/pending-request-store.ts
  • packages/slack-bot/src/routes/channel-info.test.ts
  • packages/slack-bot/src/routes/channel-info.ts
  • packages/slack-bot/src/routes/interactions.ts
  • packages/slack-bot/src/sessions/control-plane-client.test.ts
  • packages/slack-bot/src/sessions/control-plane-client.ts
  • packages/slack-bot/src/sessions/prompt-delivery.test.ts
  • packages/slack-bot/src/sessions/prompt-delivery.ts
  • packages/slack-bot/src/sessions/session-launcher.test.ts
  • packages/slack-bot/src/sessions/session-launcher.ts
  • packages/slack-bot/src/sessions/thread-session-store.test.ts
  • packages/slack-bot/src/sessions/thread-session-store.ts
  • packages/slack-bot/src/target-clarification.test.ts
  • packages/slack-bot/src/target-clarification.ts
  • packages/slack-bot/src/targets.test.ts
  • packages/slack-bot/src/types.ts
  • packages/slack-bot/vitest.config.ts
  • packages/web/package.json
  • packages/web/src/app/(app)/(sidebar)/analytics/page.test.tsx
  • packages/web/src/app/(app)/(sidebar)/analytics/page.tsx
  • packages/web/src/app/(app)/(sidebar)/automations/new/page.test.tsx
  • packages/web/src/app/(app)/(sidebar)/automations/new/page.tsx
  • packages/web/src/app/(app)/(sidebar)/automations/page.test.tsx
  • packages/web/src/app/(app)/(sidebar)/automations/templates/page.test.tsx
  • packages/web/src/app/(app)/(sidebar)/page-team-context.test.tsx
  • packages/web/src/app/(app)/(sidebar)/page.test-fixture.tsx
  • packages/web/src/app/(app)/(sidebar)/page.test.tsx
  • packages/web/src/app/(app)/(sidebar)/page.tsx
  • packages/web/src/app/(app)/(sidebar)/session/[id]/page.test.tsx
  • packages/web/src/app/(app)/(sidebar)/session/[id]/page.tsx
  • packages/web/src/app/(app)/(sidebar)/sessions/page.test.tsx
  • packages/web/src/app/(app)/(sidebar)/sessions/page.tsx
  • packages/web/src/app/api/analytics/breakdown/route.test.ts
  • packages/web/src/app/api/analytics/dashboard/route.test.ts
  • packages/web/src/app/api/analytics/pull-requests/route.test.ts
  • packages/web/src/app/api/analytics/summary/route.test.ts
  • packages/web/src/app/api/analytics/timeseries/route.test.ts
  • packages/web/src/app/api/audit-events/route.test.ts
  • packages/web/src/app/api/auth/[...auth]/route.test.ts
  • packages/web/src/app/api/environments/route.test.ts
  • packages/web/src/app/api/memories/[id]/approve/route.ts
  • packages/web/src/app/api/memories/[id]/archive/route.ts
  • packages/web/src/app/api/memories/[id]/reject/route.ts
  • packages/web/src/app/api/memories/[id]/restore/route.ts
  • packages/web/src/app/api/memories/[id]/revisions/route.ts
  • packages/web/src/app/api/memories/[id]/route.ts
  • packages/web/src/app/api/memories/preview/route.ts
  • packages/web/src/app/api/memories/route.ts
  • packages/web/src/app/api/memory-preferences/route.ts
  • packages/web/src/app/api/model-preferences/route.test.ts
  • packages/web/src/app/api/repos/route.test.ts
  • packages/web/src/app/api/sessions/[id]/budget/route.test.ts
  • packages/web/src/app/api/sessions/[id]/collaborator-candidates/route.test.ts
  • packages/web/src/app/api/sessions/[id]/collaborators/[userId]/route.test.ts
  • packages/web/src/app/api/sessions/[id]/export/route.test.ts
  • packages/web/src/app/api/sessions/[id]/memories/route.ts
  • packages/web/src/app/api/sessions/[id]/route.test.ts
  • packages/web/src/app/api/sessions/[id]/sandbox-access/route.test.ts
  • packages/web/src/app/api/sessions/[id]/visibility/route.test.ts
  • packages/web/src/app/api/sessions/batch-archive/route.test.ts
  • packages/web/src/app/api/sessions/inbox/route.test.ts
  • packages/web/src/app/api/sessions/route.test.ts
  • packages/web/src/app/api/sessions/route.ts
  • packages/web/src/app/api/settings/teams/route.test.ts
  • packages/web/src/app/api/skills/managed-skills-routes.test.ts
  • packages/web/src/app/api/teams/[id]/channel-bindings/linear/[linearTeamId]/route.ts
  • packages/web/src/app/api/teams/[id]/channel-bindings/route.ts
  • packages/web/src/app/api/teams/[id]/channel-bindings/slack/[channelId]/route.ts
  • packages/web/src/app/api/teams/[id]/repository-grants/[grantId]/route.test.ts
  • packages/web/src/app/api/teams/[id]/repository-grants/route.test.ts
  • packages/web/src/app/api/teams/[id]/secrets/[key]/route.test.ts
  • packages/web/src/app/api/teams/[id]/secrets/route.test.ts
  • packages/web/src/app/api/teams/[id]/sessions/route.test.ts
  • packages/web/src/app/api/teams/[id]/slack-channels/route.ts
  • packages/web/src/app/api/teams/route.test.ts
  • packages/web/src/components/analytics/analytics-cost-tab.tsx
  • packages/web/src/components/analytics/analytics-header.tsx
  • packages/web/src/components/analytics/analytics-kpi-items.test.ts
  • packages/web/src/components/analytics/analytics-kpi-items.ts
  • packages/web/src/components/analytics/analytics-kpis.tsx
  • packages/web/src/components/analytics/analytics-overview-tab.tsx
  • packages/web/src/components/analytics/analytics-panel.tsx
  • packages/web/src/components/analytics/analytics-people-tab.tsx
  • packages/web/src/components/analytics/analytics-pull-requests-tab.tsx
  • packages/web/src/components/analytics/analytics-ranked-bars.tsx
  • packages/web/src/components/analytics/analytics-table.test.tsx
  • packages/web/src/components/analytics/analytics-table.tsx
  • packages/web/src/components/analytics/analytics-trend-chart.tsx
  • packages/web/src/components/analytics/analytics-usage-tab.tsx
  • packages/web/src/components/analytics/cost-table.test.tsx
  • packages/web/src/components/analytics/cost-table.tsx
  • packages/web/src/components/analytics/dimension-table.test.tsx
  • packages/web/src/components/analytics/dimension-table.tsx
  • packages/web/src/components/analytics/harness-cards.test.tsx
  • packages/web/src/components/analytics/harness-cards.tsx
  • packages/web/src/components/analytics/model-bar-chart.test.tsx
  • packages/web/src/components/analytics/model-bar-chart.tsx
  • packages/web/src/components/analytics/people-table.test.tsx
  • packages/web/src/components/analytics/people-table.tsx
  • packages/web/src/components/analytics/pull-request-cards.tsx
  • packages/web/src/components/analytics/pull-request-chart.tsx
  • packages/web/src/components/analytics/pull-request-cost-table.test.tsx
  • packages/web/src/components/analytics/pull-request-cost-table.tsx
  • packages/web/src/components/analytics/pull-request-outcomes.test.tsx
  • packages/web/src/components/analytics/pull-request-outcomes.tsx
  • packages/web/src/components/analytics/pull-request-repo-table.tsx
  • packages/web/src/components/analytics/pull-request-sources.tsx
  • packages/web/src/components/analytics/repo-bar-chart.tsx
  • packages/web/src/components/analytics/repository-table.tsx
  • packages/web/src/components/analytics/runs-table.test.tsx
  • packages/web/src/components/analytics/runs-table.tsx
  • packages/web/src/components/analytics/session-sources.test.tsx
  • packages/web/src/components/analytics/session-sources.tsx
  • packages/web/src/components/analytics/session-status-summary.tsx
  • packages/web/src/components/analytics/summary-cards.test.tsx
  • packages/web/src/components/analytics/summary-cards.tsx
  • packages/web/src/components/analytics/timeseries-chart.tsx
  • packages/web/src/components/analytics/token-cards.test.tsx
  • packages/web/src/components/analytics/token-cards.tsx
  • packages/web/src/components/analytics/token-totals.tsx
  • packages/web/src/components/analytics/user-table.test.tsx
  • packages/web/src/components/analytics/user-table.tsx
  • packages/web/src/components/app-destinations.test.ts
  • packages/web/src/components/automations/automation-form-policy.test.ts
  • packages/web/src/components/automations/automation-form.tsx
  • packages/web/src/components/automations/automation-target-selection.test.ts
  • packages/web/src/components/automations/automation-target-selection.ts
  • packages/web/src/components/automations/automations-list.test.tsx
  • packages/web/src/components/automations/execution-activity.tsx
  • packages/web/src/components/automations/run-history.test.tsx
  • packages/web/src/components/automations/run-history.tsx
  • packages/web/src/components/automations/template-gallery.test.tsx
  • packages/web/src/components/media-lightbox.tsx
  • packages/web/src/components/safe-markdown.test.tsx
  • packages/web/src/components/safe-markdown.tsx
  • packages/web/src/components/sandbox-shutdown-banner.test.tsx
  • packages/web/src/components/sandbox-shutdown-banner.tsx
  • packages/web/src/components/screenshot-media.test.tsx
  • packages/web/src/components/session-actions.test.ts
  • packages/web/src/components/session-controls.test.tsx
  • packages/web/src/components/session-header.tsx
  • packages/web/src/components/session-right-sidebar.test.tsx
  • packages/web/src/components/session-right-sidebar.tsx
  • packages/web/src/components/session-scope-provider.tsx
  • packages/web/src/components/session-sidebar.test.tsx
  • packages/web/src/components/session-timeline-autofix.test.tsx
  • packages/web/src/components/session-timeline-scroll.test.tsx
  • packages/web/src/components/session-timeline.test.tsx
  • packages/web/src/components/session-visibility-control.tsx
  • packages/web/src/components/settings/appearance-settings.test.tsx
  • packages/web/src/components/settings/appearance-settings.tsx
  • packages/web/src/components/settings/audit-log-settings.test.tsx
  • packages/web/src/components/settings/audit-log-settings.tsx
  • packages/web/src/components/settings/environment-access.test.ts
  • packages/web/src/components/settings/environment-form.test.tsx
  • packages/web/src/components/settings/environment-form.tsx
  • packages/web/src/components/settings/integrations/github-auto-review-deprecation-notice.tsx
  • packages/web/src/components/settings/integrations/github-global-settings-section.tsx
  • packages/web/src/components/settings/integrations/github-integration-settings.test.tsx
  • packages/web/src/components/settings/integrations/github-repo-overrides-section.tsx
  • packages/web/src/components/settings/integrations/harness-select.tsx
  • packages/web/src/components/settings/integrations/linear-integration-settings.test.tsx
  • packages/web/src/components/settings/integrations/linear-integration-settings.tsx
  • packages/web/src/components/settings/integrations/slack-integration-settings.test.tsx
  • packages/web/src/components/settings/integrations/slack-integration-settings.tsx
  • packages/web/src/components/settings/memories-settings/index.test.tsx
  • packages/web/src/components/settings/memories-settings/index.tsx
  • packages/web/src/components/settings/memories-settings/memory-card.tsx
  • packages/web/src/components/settings/memories-settings/memory-collection.tsx
  • packages/web/src/components/settings/memories-settings/memory-editor.tsx
  • packages/web/src/components/settings/memories-settings/memory-history.tsx
  • packages/web/src/components/settings/memories-settings/use-memory-collection.ts
  • packages/web/src/components/settings/sandbox-settings-draft.test.ts
  • packages/web/src/components/settings/sandbox-timeout.test.ts
  • packages/web/src/components/settings/scm-settings-path.test.ts
  • packages/web/src/components/settings/settings-nav.test.tsx
  • packages/web/src/components/settings/settings-registry.test.ts
  • packages/web/src/components/settings/settings-registry.ts
  • packages/web/src/components/settings/skills-settings/skill-import-preview-race.test.tsx
  • packages/web/src/components/settings/skills-settings/skill-import.tsx
  • packages/web/src/components/settings/team-detail.tsx
  • packages/web/src/components/settings/teams-settings.test.tsx
  • packages/web/src/components/settings/workspace-settings.test.tsx
  • packages/web/src/components/settings/workspace-settings.tsx
  • packages/web/src/components/sidebar-layout.test.tsx
  • packages/web/src/components/sidebar/collaborators-section.directory.test.tsx
  • packages/web/src/components/sidebar/collaborators-section.tsx
  • packages/web/src/components/sidebar/memories-section.test.tsx
  • packages/web/src/components/sidebar/memories-section.tsx
  • packages/web/src/components/slack-notify-event.test.tsx
  • packages/web/src/components/slack-notify-event.tsx
  • packages/web/src/components/team-switcher.test.tsx
  • packages/web/src/components/team-switcher.tsx
  • packages/web/src/components/teams/channel-binding-editors/binding-editor.ts
  • packages/web/src/components/teams/channel-binding-editors/linear-binding-editor.tsx
  • packages/web/src/components/teams/channel-binding-editors/slack-binding-editor.tsx
  • packages/web/src/components/teams/team-channels.test.tsx
  • packages/web/src/components/teams/team-channels.tsx
  • packages/web/src/components/teams/team-page.test.tsx
  • packages/web/src/components/teams/team-page.tsx
  • packages/web/src/components/teams/team-repositories.test.tsx
  • packages/web/src/components/teams/team-repositories.tsx
  • packages/web/src/components/teams/teams-pages.test.tsx
  • packages/web/src/components/ui/icons.tsx
  • packages/web/src/components/ui/segmented-control.tsx
  • packages/web/src/components/ui/select.test.tsx
  • packages/web/src/components/ui/select.tsx
  • packages/web/src/hooks/use-active-team.test.tsx
  • packages/web/src/hooks/use-active-team.ts
  • packages/web/src/hooks/use-analytics.test.tsx
  • packages/web/src/hooks/use-analytics.ts
  • packages/web/src/hooks/use-automations.test.tsx
  • packages/web/src/hooks/use-automations.ts
  • packages/web/src/hooks/use-can-create-automation.ts
  • packages/web/src/hooks/use-environments.test.tsx
  • packages/web/src/hooks/use-environments.ts
  • packages/web/src/hooks/use-managed-skills.test.ts
  • packages/web/src/hooks/use-managed-skills.ts
  • packages/web/src/hooks/use-memories.test.ts
  • packages/web/src/hooks/use-memories.ts
  • packages/web/src/hooks/use-prompt-draft.ts
  • packages/web/src/hooks/use-prompt-input.test.tsx
  • packages/web/src/hooks/use-prompt-input.ts
  • packages/web/src/hooks/use-provider-authorization-code.ts
  • packages/web/src/hooks/use-repos.test.tsx
  • packages/web/src/hooks/use-repos.ts
  • packages/web/src/hooks/use-session-diff-selection.test.tsx
  • packages/web/src/hooks/use-session-diff-selection.ts
  • packages/web/src/hooks/use-session-socket.ts
  • packages/web/src/hooks/use-session-target-picker.test.ts
  • packages/web/src/hooks/use-session-target-picker.ts
  • packages/web/src/hooks/use-sidebar-sessions.test.tsx
  • packages/web/src/hooks/use-slack-channels.ts
  • packages/web/src/hooks/use-team-capabilities.ts
  • packages/web/src/hooks/use-teams-capabilities.test.tsx
  • packages/web/src/hooks/use-teams-isolation.test.tsx
  • packages/web/src/hooks/use-teams.test-support.tsx
  • packages/web/src/hooks/use-teams.test.tsx
  • packages/web/src/hooks/use-teams.ts
  • packages/web/src/hooks/use-warm-draft-session.test.tsx
  • packages/web/src/hooks/use-warm-draft-session.ts
  • packages/web/src/lib/analytics.test-fixture.ts
  • packages/web/src/lib/analytics.test.ts
  • packages/web/src/lib/analytics.ts
  • packages/web/src/lib/archive-session.test.ts
  • packages/web/src/lib/auth-session.test.tsx
  • packages/web/src/lib/auth-session.tsx
  • packages/web/src/lib/automation-invocation-status.ts
  • packages/web/src/lib/automation-templates.test.ts
  • packages/web/src/lib/automation-templates.ts
  • packages/web/src/lib/browser-api-json.ts
  • packages/web/src/lib/composer-access.test.ts
  • packages/web/src/lib/composer-access.ts
  • packages/web/src/lib/control-plane-query.test.ts
  • packages/web/src/lib/cron-presets.test.ts
  • packages/web/src/lib/diff-file-links.test.ts
  • packages/web/src/lib/env-paste.test.ts
  • packages/web/src/lib/github-autofix-feedback.test.ts
  • packages/web/src/lib/http-status.test.ts
  • packages/web/src/lib/image-builds.test.ts
  • packages/web/src/lib/keyboard-shortcuts.test.ts
  • packages/web/src/lib/me-teams-cache.test.ts
  • packages/web/src/lib/memories.test.ts
  • packages/web/src/lib/memories.ts
  • packages/web/src/lib/memory-action-proxy.ts
  • packages/web/src/lib/model-selection.test.ts
  • packages/web/src/lib/pr-artifacts.test.ts
  • packages/web/src/lib/pr-summary.test.ts
  • packages/web/src/lib/prompt-drafts.ts
  • packages/web/src/lib/prompt-request-id.test.ts
  • packages/web/src/lib/prompt-skill-completion.test.ts
  • packages/web/src/lib/provider-selection.test.ts
  • packages/web/src/lib/repo-label.test.ts
  • packages/web/src/lib/request-context.test.ts
  • packages/web/src/lib/restore-queued-prompt.test.ts
  • packages/web/src/lib/sandbox-provider.test.ts
  • packages/web/src/lib/scm.test.ts
  • packages/web/src/lib/select-eslint.test.ts
  • packages/web/src/lib/session-capabilities.test.ts
  • packages/web/src/lib/session-cost.test.ts
  • packages/web/src/lib/session-diffs.test.ts
  • packages/web/src/lib/session-discovery.test.ts
  • packages/web/src/lib/session-discovery.ts
  • packages/web/src/lib/session-file-links.tsx
  • packages/web/src/lib/session-harness.test.ts
  • packages/web/src/lib/session-harness.ts
  • packages/web/src/lib/session-inbox-api.test.ts
  • packages/web/src/lib/session-list.test.ts
  • packages/web/src/lib/session-read-state.test.ts
  • packages/web/src/lib/session-scope-refresh.test.tsx
  • packages/web/src/lib/session-scope.test.ts
  • packages/web/src/lib/session-scope.ts
  • packages/web/src/lib/session-snapshot.test.ts
  • packages/web/src/lib/session-socket/artifact-metadata.test.ts
  • packages/web/src/lib/session-socket/boot-phase.test.ts
  • packages/web/src/lib/session-socket/boot-phase.ts
  • packages/web/src/lib/session-socket/event-log.test.ts
  • packages/web/src/lib/session-socket/swr-revalidation.test.ts
  • packages/web/src/lib/session-target.test.ts
  • packages/web/src/lib/settings-proxy.test.ts
  • packages/web/src/lib/settings-proxy.ts
  • packages/web/src/lib/site-config.test.ts
  • packages/web/src/lib/swr-fetch-error.test.ts
  • packages/web/src/lib/swr-fetch-error.ts
  • packages/web/src/lib/tasks.test.ts
  • packages/web/src/lib/time.test.ts
  • packages/web/src/lib/timeline-virtual-rows.test.ts
  • packages/web/src/lib/timeline-virtual-rows.ts
  • packages/web/src/lib/warm-session.test.ts
  • packages/web/src/middleware.test.ts
  • packages/web/src/test/setup.ts
  • packages/web/vitest.config.ts
  • scripts/check-coverage.mjs
  • scripts/check-coverage.test.mjs
  • scripts/coverage-baseline.json
  • scripts/coverage-policy.ts
  • scripts/sql-portability-baseline.json
  • scripts/terraform-plan-comment.mjs
  • scripts/terraform-plan-comment.test.mjs
  • terraform/README.md
  • terraform/d1/migrations/0084_memories.sql
  • terraform/d1/migrations/0085_team_default_visibility.sql
  • terraform/environments/production/locals.tf
  • terraform/environments/production/terraform.tfvars.example
  • terraform/environments/production/tests/classifier_provider.tftest.hcl
  • terraform/environments/production/variables.tf
  • terraform/environments/production/workers-linear.tf
  • terraform/environments/production/workers-slack.tf

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@codos-reviewer codos-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking: 4 · Non-blocking: 0

The upstream sync introduces two cross-boundary disclosures (personal-memory metadata to other session readers and raw tool content to runtime logs), permits a team lead to bind an unrelated private Slack channel by ID, and makes team-owned memory previews disagree with the session they preview. Please address the concrete cases in the inline comments. Targeted verification: 445 GitHub-bot tests and 11 memory-service tests passed; these cases are not covered by those suites.

Comment thread packages/control-plane/src/routes/session-memories.ts
Comment thread packages/control-plane/src/routes/team-channel-bindings.ts
Comment thread packages/control-plane/src/routes/memories.ts
@rhlsthrm

rhlsthrm commented Oct 5, 2026

Copy link
Copy Markdown
Collaborator Author

Disposition of the four blocking findings

All four findings are in files this PR carries byte-identical from upstream e364a7ee (git diff --quiet origin/main HEAD -- <path> is clean for each). Under this fork's policy, upstream code is not patched here: a fork-local patch would add divergence the sync loop exists to remove. Each finding was reproduced on clean upstream e364a7ee before deciding.

Finding Reproduced on upstream? Disposition
session-memories.ts:29: personal-memory titles shown to other session readers Yes, for workspace sessions (not for private sessions) Working as designed upstream. docs/MEMORY.md defines this boundary: personal memories "can be included in shared sessions… visible to collaborators" (L16–18). Owner-only applies to the /memories management API (L122). GET /sessions/:id/memories is "readable with the session" (L134). Browser responses omit only the owner and hash (L150–151). The suggested filter would also leave the agent's boot context and memory_read exposing the same content. A change here is a product-policy proposal, not a defect fix.
team-channel-bindings.ts:89: a lead can bind a private channel by ID Yes, but the premise is mostly wrong The picker hides unbound private channels only from actors without automations.read (automation-slack-settings.ts:75-86), and every built-in role has that permission. So in default setups any lead can already see and bind every private channel the bot has joined. The documented rule (ColeMurray#2183, docs/integrations/SLACK.md:432-437) is that bot membership grants eligibility. The server has no reliable Slack identity for a web actor. Every fix changes who may bind private channels, which is a maintainer decision. No upstream PR was opened.
claude_translate.py:567: raw tool args/output in trajectory logs Yes (also text_preview, description_preview, error_preview, diagnostic_preview) Deliberate upstream decision. ColeMurray#2210's "Logging Policy" says the credential-sanitization layer "has been removed for parity with the existing OpenCode setup… Preview truncation is not credential redaction". Upstream tests pin raw previews (tests/test_claude_logging.py:46,55, tests/test_claude_translate.py:306). Open upstream ColeMurray#2212 is an older, competing design and does not cover this logger.
memories.ts:241: memory preview ignores team context Yes, with a different mechanism The repository half does not reproduce: team grants are a subset of a member's grants (workspace-repository-authorization.ts:65-93). The real defect is that environment memories of a team-owned environment are dropped from the preview (memory-access.ts:330-334), although a team session pins them. Fixed upstream in ColeMurray#2293 with a failing-before/passing-after integration test.

Each thread below gets a reply pointing here and is then resolved.

@github-actions

github-actions Bot commented Oct 5, 2026

Copy link
Copy Markdown

Terraform Validation Results

Validation job: abandoned
Check Secrets job: success

Step Status
Format Not reported
Init Not reported
Validate Not reported
Tests Not reported
Modal module tests Not reported

Pushed by: @rhlsthrm, Action: pull_request

@github-actions

github-actions Bot commented Oct 5, 2026

Copy link
Copy Markdown

Terraform Validation Results

Validation job: success
Check Secrets job: success

Step Status
Format Success
Init Success
Validate Success
Tests Success
Modal module tests Success

Pushed by: @rhlsthrm, Action: pull_request

@github-actions

github-actions Bot commented Oct 5, 2026

Copy link
Copy Markdown

Terraform Plan Results

Status: Success

Show Plan
terraform_data.sign_in_provider_gate: Refreshing state... [id=b29a3d55-0be5-fb92-10a9-027df10c4b75]
data.external.modal_source_hash[0]: Reading...
terraform_data.access_control_gate: Refreshing state... [id=2b965617-b42b-4b42-5ea5-a1c3c05f10be]
terraform_data.cloudflare_custom_domain_gate: Refreshing state... [id=09b89c9b-996a-d28b-1f9c-08760a492dac]
module.modal_app[0].null_resource.modal_secrets[0]: Refreshing state... [id=4371755998621267773]
null_resource.web_app_cloudflare_build[0]: Refreshing state... [id=6918680661690155785]
null_resource.slack_bot_build[0]: Refreshing state... [id=9088235487192680958]
random_password.service_auth_secret_github_bot: Refreshing state... [id=none]
random_password.service_auth_secret_linear_bot: Refreshing state... [id=none]
random_bytes.provider_accounts_encryption_key: Refreshing state...
random_password.service_auth_secret_slack_bot: Refreshing state... [id=none]
null_resource.github_bot_build[0]: Refreshing state... [id=1073509195618209737]
null_resource.control_plane_build: Refreshing state... [id=2292824058761615604]
random_password.service_auth_secret_web: Refreshing state... [id=none]
random_password.image_callback_token_pepper: Refreshing state... [id=none]
null_resource.linear_bot_build[0]: Refreshing state... [id=7007435095112115998]
module.github_kv[0].cloudflare_workers_kv_namespace.this: Refreshing state... [id=e0848d433a4f466cafd4ed5d140aad7d]
module.session_index_kv.cloudflare_workers_kv_namespace.this: Refreshing state... [id=ea0a253d5cb64d75a841acb88040cd2f]
module.linear_kv[0].cloudflare_workers_kv_namespace.this: Refreshing state... [id=777f94c3595f4de680c256a4e5fc6653]
cloudflare_d1_database.main: Refreshing state... [id=f747a908-5c69-45a1-86ab-ceb5250cf5e0]
cloudflare_r2_bucket.media: Refreshing state... [id=open-inspect-media-codos]
cloudflare_queue.github_autofix_dlq[0]: Refreshing state... [id=3a27213aeba149d4b7cbf2d3551842f8]
cloudflare_queue.github_autofix[0]: Refreshing state... [id=033a23f13783415385b2f8799416c20f]
cloudflare_queue.slack_completion_delivery[0]: Refreshing state... [id=247b1100bac2408684d6a75c1bca0d28]
cloudflare_queue.image_build_finalization: Refreshing state... [id=a0647323f7424e778b9d59da50dc55cf]
data.external.modal_source_hash[0]: Read complete after 0s [id=-]
local_file.web_app_wrangler_production[0]: Refreshing state... [id=d58ccd8dd2962c70f7cff2ffac9821e9e711af31]
cloudflare_queue.slack_completion_delivery_dlq[0]: Refreshing state... [id=396865e4939b4160937b2dc9ad5dabe1]
module.slack_kv[0].cloudflare_workers_kv_namespace.this: Refreshing state... [id=ab5c371c8bc04a938ff2f71809933aa0]
cloudflare_queue.image_build_finalization_dlq: Refreshing state... [id=61535c686d8546099cfddcf39833572b]
module.modal_app[0].null_resource.modal_deploy: Refreshing state... [id=5162646839236869035]
module.linear_bot_worker[0].cloudflare_worker.this: Refreshing state... [id=049cd48117bc48b9b4332683a97d0a0e]
module.slack_bot_worker[0].cloudflare_worker.this: Refreshing state... [id=375c2c6875904657bce05c62c8048c76]
module.linear_bot_worker[0].cloudflare_worker_version.this: Refreshing state... [id=9098db83-cca6-40ee-a770-bef402cefeba]
null_resource.d1_migrations: Refreshing state... [id=263751651589333239]
module.slack_bot_worker[0].cloudflare_worker_version.this: Refreshing state... [id=151dcc3c-23b9-4cda-bf47-f75da09ee657]
module.linear_bot_worker[0].cloudflare_workers_deployment.this: Refreshing state... [id=949431e0-4b86-4a3f-aae3-291f40f045dd]
module.slack_bot_worker[0].cloudflare_workers_deployment.this: Refreshing state... [id=7a44c68a-0e0c-4953-a266-695313371f72]
module.control_plane_worker.cloudflare_worker.this: Refreshing state... [id=3457352971a74b89be5ed3700db48a8e]
cloudflare_queue_consumer.slack_completion_delivery[0]: Refreshing state...
module.control_plane_worker.cloudflare_worker_version.this: Refreshing state... [id=5bc2ef23-0e55-46e1-84b8-1ef9452db4f5]
module.control_plane_worker.cloudflare_workers_deployment.this: Refreshing state... [id=1fa8f9f0-fd72-46cf-8dcc-bcd786913f23]
module.control_plane_worker.cloudflare_workers_cron_trigger.this[0]: Refreshing state... [id=open-inspect-control-plane-codos]
null_resource.web_app_cloudflare_deploy[0]: Refreshing state... [id=6654088337346185031]
cloudflare_queue_consumer.image_build_finalization: Refreshing state...
module.github_bot_worker[0].cloudflare_worker.this: Refreshing state... [id=fa832fd890a14336bc3c63305e9bc36f]
null_resource.web_app_cloudflare_secrets[0]: Refreshing state... [id=8981633407656564074]
module.github_bot_worker[0].cloudflare_worker_version.this: Refreshing state... [id=4146f4b0-e799-4a13-8582-abfd42a7ac9e]
module.github_bot_worker[0].cloudflare_workers_deployment.this: Refreshing state... [id=44b501f8-0300-4b57-b392-4019cb8609e5]
cloudflare_queue_consumer.github_autofix[0]: Refreshing state...

Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
  + create
  ~ update in-place
-/+ destroy and then create replacement

Terraform will perform the following actions:

  # local_file.web_app_wrangler_production[0] will be created
  + resource "local_file" "web_app_wrangler_production" {
      + content              = <<-EOT
            name = "open-inspect-web-codos"
            main = ".open-next/worker.js"
            compatibility_date = "2025-08-15"
            compatibility_flags = ["nodejs_compat", "global_fetch_strictly_public"]
            # Keep-names makes esbuild emit __name() calls, which leak into next-themes'
            # inline script and throw in the browser.
            keep_names = false
            
            # A custom-domain deployment has one canonical browser origin.
            workers_dev = true
            
            [vars]
            CONTROL_PLANE_URL = "https://open-inspect-control-plane-codos.opencodos.workers.dev"
            NEXT_PUBLIC_WS_URL = "wss://open-inspect-control-plane-codos.opencodos.workers.dev"
            NEXT_PUBLIC_SANDBOX_PROVIDER = "modal"
            NEXT_PUBLIC_APP_NAME = "Open-Inspect"
            NEXT_PUBLIC_APP_ICON_URL = ""
            
            [assets]
            directory = ".open-next/assets"
            binding = "ASSETS"
            
            [[services]]
            binding = "CONTROL_PLANE_WORKER"
            service = "open-inspect-control-plane-codos"
        EOT
      + content_base64sha256 = (known after apply)
      + content_base64sha512 = (known after apply)
      + content_md5          = (known after apply)
      + content_sha1         = (known after apply)
      + content_sha256       = (known after apply)
      + content_sha512       = (known after apply)
      + directory_permission = "0777"
      + file_permission      = "0777"
      + filename             = "../../..//packages/web/wrangler.production.toml"
      + id                   = (known after apply)
    }

  # null_resource.control_plane_build must be replaced
-/+ resource "null_resource" "control_plane_build" {
      ~ id       = "2292824058761615604" -> (known after apply)
      ~ triggers = { # forces replacement
          ~ "always_run" = "2026-10-05T14:25:23Z" -> (known after apply)
        }
    }

  # null_resource.d1_migrations must be replaced
-/+ resource "null_resource" "d1_migrations" {
      ~ id       = "263751651589333239" -> (known after apply)
      ~ triggers = { # forces replacement
          ~ "migrations_sha" = "892f8c9e8c97406e40bb30cde46ddb27e20071538596a544af88d48b300728b2" -> "fe214c9c4deb8e856064cb75c157291d2778c3033e71063a6c2a249004d785ed"
            # (1 unchanged element hidden)
        }
    }

  # null_resource.github_bot_build[0] must be replaced
-/+ resource "null_resource" "github_bot_build" {
      ~ id       = "1073509195618209737" -> (known after apply)
      ~ triggers = { # forces replacement
          ~ "always_run" = "2026-10-05T14:25:23Z" -> (known after apply)
        }
    }

  # null_resource.linear_bot_build[0] must be replaced
-/+ resource "null_resource" "linear_bot_build" {
      ~ id       = "7007435095112115998" -> (known after apply)
      ~ triggers = { # forces replacement
          ~ "always_run" = "2026-10-05T14:25:23Z" -> (known after apply)
        }
    }

  # null_resource.slack_bot_build[0] must be replaced
-/+ resource "null_resource" "slack_bot_build" {
      ~ id       = "9088235487192680958" -> (known after apply)
      ~ triggers = { # forces replacement
          ~ "always_run" = "2026-10-05T14:25:23Z" -> (known after apply)
        }
    }

  # null_resource.web_app_cloudflare_build[0] must be replaced
-/+ resource "null_resource" "web_app_cloudflare_build" {
      ~ id       = "6918680661690155785" -> (known after apply)
      ~ triggers = { # forces replacement
          ~ "always_run" = "2026-10-05T14:25:23Z" -> (known after apply)
        }
    }

  # null_resource.web_app_cloudflare_deploy[0] must be replaced
-/+ resource "null_resource" "web_app_cloudflare_deploy" {
      ~ id       = "6654088337346185031" -> (known after apply)
      ~ triggers = { # forces replacement
          ~ "always_run" = "2026-10-05T14:26:14Z" -> (known after apply)
        }
    }

  # module.control_plane_worker.cloudflare_worker.this will be updated in-place
  ~ resource "cloudflare_worker" "this" {
        id             = "3457352971a74b89be5ed3700db48a8e"
        name           = "open-inspect-control-plane-codos"
      ~ observability  = {
          ~ logs               = {
              + destinations       = (known after apply)
                # (4 unchanged attributes hidden)
            }
          ~ traces             = {
              + destinations       = (known after apply)
                # (3 unchanged attributes hidden)
            }
            # (2 unchanged attributes hidden)
        }
      ~ references     = {
          ~ dispatch_namespace_outbounds = [] -> (known after apply)
          ~ domains                      = [] -> (known after apply)
          ~ durable_objects              = [
              - {
                  - namespace_id   = "34735ba6d2804d67a82cf0bdf5a3175f" -> null
                  - namespace_name = "open-inspect-control-plane-codos_SessionDO" -> null
                  - worker_id      = "3457352971a74b89be5ed3700db48a8e" -> null
                  - worker_name    = "open-inspect-control-plane-codos" -> null
                },
            ] -> (known after apply)
          ~ queues                       = [
              - {
                  - queue_consumer_id = "4e24da4810c84b3e9e80ea014860d145" -> null
                  - queue_id          = "033a23f13783415385b2f8799416c20f" -> null
                  - queue_name        = "open-inspect-github-autofix-codos" -> null
                },
              - {
                  - queue_consumer_id = "f37fe99c4658470aa36767dfb68c3d6f" -> null
                  - queue_id          = "a0647323f7424e778b9d59da50dc55cf" -> null
                  - queue_name        = "open-inspect-image-build-finalization-codos" -> null
                },
            ] -> (known after apply)
          ~ workers                      = [
              - {
                  - id   = "049cd48117bc48b9b4332683a97d0a0e" -> null
                  - name = "open-inspect-linear-bot-codos" -> null
                },
              - {
                  - id   = "7aa4fa7a556a48708d1ebd7bbba3263a" -> null
                  - name = "open-inspect-web-codos" -> null
                },
              - {
                  - id   = "fa832fd890a14336bc3c63305e9bc36f" -> null
                  - name = "open-inspect-github-bot-codos" -> null
                },
              - {
                  - id   = "375c2c6875904657bce05c62c8048c76" -> null
                  - name = "open-inspect-slack-bot-codos" -> null
                },
            ] -> (known after apply)
        } -> (known after apply)
        tags           = []
      ~ updated_on     = "2026-10-05T14:25:30Z" -> (known after apply)
        # (6 unchanged attributes hidden)
    }

  # module.control_plane_worker.cloudflare_worker_version.this must be replaced
-/+ resource "cloudflare_worker_version" "this" {
      ~ annotations         = {
          + workers_message      = (known after apply)
          + workers_tag          = (known after apply)
          ~ workers_triggered_by = "create_version_api" -> (known after apply)
        } -> (known after apply)
      ~ bindings            = (sensitive value) # forces replacement
      ~ created_on          = "2026-10-05T14:25:35Z" -> (known after apply)
      ~ id                  = "5bc2ef23-0e55-46e1-84b8-1ef9452db4f5" -> (known after apply)
      + limits              = (known after apply)
      + main_script_base64  = (known after apply)
      ~ migration_tag       = "v1" -> (known after apply)
      ~ modules             = [
          - { # forces replacement
              - content_file   = "../../..//packages/control-plane/dist/index.js" -> null
              - content_sha256 = "3e33de33bcda44f9bd57d1c64347b2ac7d86f588c4a15276569f984a33c4cd91" -> null
              - content_type   = "application/javascript+module" -> null
              - name           = "index.js" -> null
            },
          + { # forces replacement
              + content_file   = "../../..//packages/control-plane/dist/index.js"
              + content_sha256 = "efdde37a149a677fd13f4fb28b2ab0496e50d92176ac6985a0fcb3ec5922a2ee"
              + content_type   = "application/javascript+module"
              + name           = "index.js"
            },
        ]
      ~ number              = 83 -> (known after apply)
      ~ source              = "terraform" -> (known after apply)
      ~ startup_time_ms     = 116 -> (known after apply)
      ~ urls                = [] -> (known after apply)
        # (6 unchanged attributes hidden)
    }

  # module.control_plane_worker.cloudflare_workers_deployment.this must be replaced
-/+ resource "cloudflare_workers_deployment" "this" {
      ~ annotations  = {
          + workers_message      = (known after apply)
          ~ workers_triggered_by = "deployment" -> (known after apply)
        } -> (known after apply)
      + author_email = (known after apply)
      ~ created_on   = "2026-10-05T14:25:40Z" -> (known after apply)
      ~ id           = "1fa8f9f0-fd72-46cf-8dcc-bcd786913f23" -> (known after apply)
      ~ source       = "terraform" -> (known after apply)
      ~ versions     = [ # forces replacement
          ~ {
              ~ version_id = "5bc2ef23-0e55-46e1-84b8-1ef9452db4f5" -> (known after apply)
                # (1 unchanged attribute hidden)
            },
        ]
        # (3 unchanged attributes hidden)
    }

  # module.github_bot_worker[0].cloudflare_worker.this will be updated in-place
  ~ resource "cloudflare_worker" "this" {
        id             = "fa832fd890a14336bc3c63305e9bc36f"
        name           = "open-inspect-github-bot-codos"
      ~ observability  = {
          ~ logs               = {
              + destinations       = (known after apply)
                # (4 unchanged attributes hidden)
            }
          ~ traces             = {
              + destinations       = (known after apply)
                # (3 unchanged attributes hidden)
            }
            # (2 unchanged attributes hidden)
        }
      ~ references     = {
          ~ dispatch_namespace_outbounds = [] -> (known after apply)
          ~ domains                      = [] -> (known after apply)
          ~ durable_objects              = [] -> (known after apply)
          ~ queues                       = [] -> (known after apply)
          ~ workers                      = [
              - {
                  - id   = "3457352971a74b89be5ed3700db48a8e" -> null
                  - name = "open-inspect-control-plane-codos" -> null
                },
            ] -> (known after apply)
        } -> (known after apply)
        tags           = []
      ~ updated_on     = "2026-10-05T14:25:40Z" -> (known after apply)
        # (6 unchanged attributes hidden)
    }

  # module.github_bot_worker[0].cloudflare_worker_version.this must be replaced
-/+ resource "cloudflare_worker_version" "this" {
      ~ annotations         = {
          + workers_message      = (known after apply)
          + workers_tag          = (known after apply)
          ~ workers_triggered_by = "create_version_api" -> (known after apply)
        } -> (known after apply)
      ~ bindings            = (sensitive value) # forces replacement
      ~ created_on          = "2026-10-05T14:25:41Z" -> (known after apply)
      ~ id                  = "4146f4b0-e799-4a13-8582-abfd42a7ac9e" -> (known after apply)
      + limits              = (known after apply)
      + main_script_base64  = (known after apply)
      + migration_tag       = (known after apply)
      ~ modules             = [
          - { # forces replacement
              - content_file   = "../../..//packages/github-bot/dist/index.js" -> null
              - content_sha256 = "23f9979b7b93a642f841ec5954878c060e916f0e5ea6346f182c0c0daf8b8efd" -> null
              - content_type   = "application/javascript+module" -> null
              - name           = "index.js" -> null
            },
          + { # forces replacement
              + content_file   = "../../..//packages/github-bot/dist/index.js"
              + content_sha256 = "956b5f1938147e55d3b480ac6201581881700e140ca79573722ff6d919bfb108"
              + content_type   = "application/javascript+module"
              + name           = "index.js"
            },
        ]
      ~ number              = 81 -> (known after apply)
      ~ source              = "terraform" -> (known after apply)
      ~ startup_time_ms     = 101 -> (known after apply)
      ~ urls                = [
          - "https://4146f4b0-open-inspect-github-bot-codos.opencodos.workers.dev",
        ] -> (known after apply)
        # (6 unchanged attributes hidden)
    }

  # module.github_bot_worker[0].cloudflare_workers_deployment.this must be replaced
-/+ resource "cloudflare_workers_deployment" "this" {
      ~ annotations  = {
          + workers_message      = (known after apply)
          ~ workers_triggered_by = "deployment" -> (known after apply)
        } -> (known after apply)
      + author_email = (known after apply)
      ~ created_on   = "2026-10-05T14:25:45Z" -> (known after apply)
      ~ id           = "44b501f8-0300-4b57-b392-4019cb8609e5" -> (known after apply)
      ~ source       = "terraform" -> (known after apply)
      ~ versions     = [ # forces replacement
          ~ {
              ~ version_id = "4146f4b0-e799-4a13-8582-abfd42a7ac9e" -> (known after apply)
                # (1 unchanged attribute hidden)
            },
        ]
        # (3 unchanged attributes hidden)
    }

  # module.linear_bot_worker[0].cloudflare_worker.this will be updated in-place
  ~ resource "cloudflare_worker" "this" {
        id             = "049cd48117bc48b9b4332683a97d0a0e"
        name           = "open-inspect-linear-bot-codos"
      ~ observability  = {
          ~ logs               = {
              + destinations       = (known after apply)
                # (4 unchanged attributes hidden)
            }
          ~ traces             = {
              + destinations       = (known after apply)
                # (3 unchanged attributes hidden)
            }
            # (2 unchanged attributes hidden)
        }
      ~ references     = {
          ~ dispatch_namespace_outbounds = [] -> (known after apply)
          ~ domains                      = [] -> (known after apply)
          ~ durable_objects              = [] -> (known after apply)
          ~ queues                       = [] -> (known after apply)
          ~ workers                      = [
              - {
                  - id   = "3457352971a74b89be5ed3700db48a8e" -> null
                  - name = "open-inspect-control-plane-codos" -> null
                },
            ] -> (known after apply)
        } -> (known after apply)
        tags           = []
      ~ updated_on     = "2026-10-05T14:25:24Z" -> (known after apply)
        # (6 unchanged attributes hidden)
    }

  # module.linear_bot_worker[0].cloudflare_worker_version.this must be replaced
-/+ resource "cloudflare_worker_version" "this" {
      ~ annotations         = {
          + workers_message      = (known after apply)
          + workers_tag          = (known after apply)
          ~ workers_triggered_by = "create_version_api" -> (known after apply)
        } -> (known after apply)
      ~ bindings            = (sensitive value) # forces replacement
      ~ created_on          = "2026-10-05T14:25:26Z" -> (known after apply)
      ~ id                  = "9098db83-cca6-40ee-a770-bef402cefeba" -> (known after apply)
      + limits              = (known after apply)
      + main_script_base64  = (known after apply)
      + migration_tag       = (known after apply)
      ~ modules             = [
          - { # forces replacement
              - content_file   = "../../..//packages/linear-bot/dist/index.js" -> null
              - content_sha256 = "7b42cf70800722f964d7272de95ecc31f5307b71f4a0a0b2d9d8f68aecc38417" -> null
              - content_type   = "application/javascript+module" -> null
              - name           = "index.js" -> null
            },
          + { # forces replacement
              + content_file   = "../../..//packages/linear-bot/dist/index.js"
              + content_sha256 = "1df7f712aece63700acf46161233a979cd1b69bd0555668623d62e294355f679"
              + content_type   = "application/javascript+module"
              + name           = "index.js"
            },
        ]
      ~ number              = 87 -> (known after apply)
      ~ source              = "terraform" -> (known after apply)
      ~ startup_time_ms     = 58 -> (known after apply)
      ~ urls                = [
          - "https://9098db83-open-inspect-linear-bot-codos.opencodos.workers.dev",
        ] -> (known after apply)
        # (6 unchanged attributes hidden)
    }

  # module.linear_bot_worker[0].cloudflare_workers_deployment.this must be replaced
-/+ resource "cloudflare_workers_deployment" "this" {
      ~ annotations  = {
          + workers_message      = (known after apply)
          ~ workers_triggered_by = "deployment" -> (known after apply)
        } -> (known after apply)
      + author_email = (known after apply)
      ~ created_on   = "2026-10-05T14:25:28Z" -> (known after apply)
      ~ id           = "949431e0-4b86-4a3f-aae3-291f40f045dd" -> (known after apply)
      ~ source       = "terraform" -> (known after apply)
      ~ versions     = [ # forces replacement
          ~ {
              ~ version_id = "9098db83-cca6-40ee-a770-bef402cefeba" -> (known after apply)
                # (1 unchanged attribute hidden)
            },
        ]
        # (3 unchanged attributes hidden)
    }

  # module.modal_app[0].null_resource.modal_deploy must be replaced
-/+ resource "null_resource" "modal_deploy" {
      ~ id       = "5162646839236869035" -> (known after apply)
      ~ triggers = { # forces replacement
          ~ "source_hash"       = "c3018aefde76d57f99f467233c071f0aa960ce34f7e98214578fc62296b28d80" -> "d91c42dd4469285f05295b7648cfaac2b1d9bd87bb38b03a8edff9b11c585ae7"
            # (4 unchanged elements hidden)
        }
    }

  # module.slack_bot_worker[0].cloudflare_worker.this will be updated in-place
  ~ resource "cloudflare_worker" "this" {
        id             = "375c2c6875904657bce05c62c8048c76"
        name           = "open-inspect-slack-bot-codos"
      ~ observability  = {
          ~ logs               = {
              + destinations       = (known after apply)
                # (4 unchanged attributes hidden)
            }
          ~ traces             = {
              + destinations       = (known after apply)
                # (3 unchanged attributes hidden)
            }
            # (2 unchanged attributes hidden)
        }
      ~ references     = {
          ~ dispatch_namespace_outbounds = [] -> (known after apply)
          ~ domains                      = [] -> (known after apply)
          ~ durable_objects              = [] -> (known after apply)
          ~ queues                       = [
              - {
                  - queue_consumer_id = "767c5dfe751c4852a536d98b836cdd94" -> null
                  - queue_id          = "247b1100bac2408684d6a75c1bca0d28" -> null
                  - queue_name        = "open-inspect-slack-completion-codos" -> null
                },
            ] -> (known after apply)
          ~ workers                      = [
              - {
                  - id   = "3457352971a74b89be5ed3700db48a8e" -> null
                  - name = "open-inspect-control-plane-codos" -> null
                },
            ] -> (known after apply)
        } -> (known after apply)
        tags           = []
      ~ updated_on     = "2026-10-05T14:25:24Z" -> (known after apply)
        # (6 unchanged attributes hidden)
    }

  # module.slack_bot_worker[0].cloudflare_worker_version.this must be replaced
-/+ resource "cloudflare_worker_version" "this" {
      ~ annotations         = {
          + workers_message      = (known after apply)
          + workers_tag          = (known after apply)
          ~ workers_triggered_by = "create_version_api" -> (known after apply)
        } -> (known after apply)
      ~ bindings            = (sensitive value) # forces replacement
      ~ created_on          = "2026-10-05T14:25:25Z" -> (known after apply)
      ~ id                  = "151dcc3c-23b9-4cda-bf47-f75da09ee657" -> (known after apply)
      + limits              = (known after apply)
      + main_script_base64  = (known after apply)
      + migration_tag       = (known after apply)
      ~ modules             = [
          - { # forces replacement
              - content_file   = "../../..//packages/slack-bot/dist/index.js" -> null
              - content_sha256 = "2d2f7f252c87f43ef3a09a72f1ab6c24f34c3bc26a45277bd78d5a5a0354bfca" -> null
              - content_type   = "application/javascript+module" -> null
              - name           = "index.js" -> null
            },
          + { # forces replacement
              + content_file   = "../../..//packages/slack-bot/dist/index.js"
              + content_sha256 = "c53be53064f2d8c1290a0585e487c6aea15cb2f69e7bc3bb3d918cf462b5e65b"
              + content_type   = "application/javascript+module"
              + name           = "index.js"
            },
        ]
      ~ number              = 85 -> (known after apply)
      ~ source              = "terraform" -> (known after apply)
      ~ startup_time_ms     = 55 -> (known after apply)
      ~ urls                = [
          - "https://151dcc3c-open-inspect-slack-bot-codos.opencodos.workers.dev",
        ] -> (known after apply)
        # (6 unchanged attributes hidden)
    }

  # module.slack_bot_worker[0].cloudflare_workers_deployment.this must be replaced
-/+ resource "cloudflare_workers_deployment" "this" {
      ~ annotations  = {
          + workers_message      = (known after apply)
          ~ workers_triggered_by = "deployment" -> (known after apply)
        } -> (known after apply)
      + author_email = (known after apply)
      ~ created_on   = "2026-10-05T14:25:26Z" -> (known after apply)
      ~ id           = "7a44c68a-0e0c-4953-a266-695313371f72" -> (known after apply)
      ~ source       = "terraform" -> (known after apply)
      ~ versions     = [ # forces replacement
          ~ {
              ~ version_id = "151dcc3c-23b9-4cda-bf47-f75da09ee657" -> (known after apply)
                # (1 unchanged attribute hidden)
            },
        ]
        # (3 unchanged attributes hidden)
    }

Plan: 17 to add, 4 to change, 16 to destroy.

─────────────────────────────────────────────────────────────────────────────

Saved the plan to: tfplan

To perform exactly these actions, run the following command to apply:
    terraform apply "tfplan"

Pushed by: @rhlsthrm

@rhlsthrm
rhlsthrm merged commit 6808370 into main Oct 5, 2026
104 of 133 checks passed
@rhlsthrm
rhlsthrm deleted the sync/upstream-2026-10-05 branch October 5, 2026 23:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants