Skip to content

Release v2.58.0 - #6216

Merged
atomantic merged 290 commits into
releasefrom
main
Sep 4, 2026
Merged

Release v2.58.0#6216
atomantic merged 290 commits into
releasefrom
main

Conversation

@atomantic

Copy link
Copy Markdown
Owner

Release v2.58.0

Released: 2026-09-04

Highlights

CoS / agent orchestration

  • CoS runs can now split into architect/implementer/reviewer roles, each with its own reasoning-effort setting, instead of one monolithic pass.
  • A run that ships clean code for the wrong task is now held for review instead of merging silently.
  • pr-reviewer's Stage 3 can run as an attachable TUI session you can watch and interact with, rather than only headless.
  • pr-reviewer stages that produce no output are now blocked instead of being silently re-spawned, and a stage that produces multiple conflicting outputs is resolved consistently.
  • Per-app provider overrides were renamed to per-app options, and the run toggle now reads "Enabled" instead of the ambiguous "Run".
  • Agent worktrees now attach to fork PR head branches, so external contributor PRs are actually workable by the CoS pipeline.
  • Fork detection now classifies by owner alone, so renaming a fork no longer disables it.
  • Fixed a reviewer-chain gap where a claim-work reviewer override pinned for GitHub/GitLab/PLAN.md runs silently didn't apply to a JIRA ticket run's play button.

Local LLM / model management

  • Slotstream checkpoints can now be downloaded directly from Models → LLMs, with correct byte accounting and unfinished checkpoints hidden until complete; a weightless repo is refused up front.
  • Local model tuning (context window, pinned settings) now survives daemon-unreachable conditions and context-window reloads instead of resetting.
  • A local provider whose offered models have disappeared from its daemon is now reported as not-ready rather than silently stale.
  • Ollama-backed Claude harnesses get a pinned 128K context window, and the numCtx migration correctly stands down when OLLAMA_CONTEXT_LENGTH is already set.
  • A large local prompt's prefill is now budgeted so a big context window doesn't look like a wedged/hung run.

Animation / sprites / rigging

  • A new RigPanel UI drives retargeting end-to-end: clip picker, diagnostic preview, and write handoff.
  • Rigged animated records can now be exposed to CoS avatars.
  • The degenerate-frame probe is memoized on frame content, cutting redundant sprite-processing work.

Reliability and data integrity

  • Fixed a real race where the PromptManager variable race reappeared after a prior fix only relocated it; unsaved prompt-stage edits are now guarded consistently.
  • Bulk-star, media-collection moves, and yt-dlp import cancellation now report failure/cancellation accurately instead of a false success.
  • FableLoom's asset manifest and restorable-field set were both missing coverage that caused older peers to erase delivery plans/beat outlines on sync — fixed.
  • Tribe now reports emails/phones shared by more than one contact, helping catch duplicate-identity records.
  • safeJSONParse's scalar-parsing change had broken object-shape assumptions downstream — guarded, and the related isValidJSON fork was inlined back into safeJSONParse to stop the two from drifting.

Performance

Windows & platform fixes

  • The in-app update now actually runs on Windows instead of reporting a phantom success.
  • npm install's inline audit no longer stalls install paths.
  • Fixed a path-separator mismatch in the Slotstream in-flight check on Windows.

Accessibility & UI polish

  • Swept sub-44px icon buttons tree-wide and widened the tap-target guard.
  • Practice rating hints are now visible as button subtext (with the redundant tooltip removed), and their accessible name is fixed after the change.
  • Fixed mobile responsive layout regressions in POST tests and the songbook transpose readout.

Full Changelog

Full Diff: v2.57.0...v2.58.0

atomantic and others added 30 commits September 3, 2026 17:03
… a project-start sink (#5920)

`pipeline/episodeVideo.js` importing `creativeDirector/completionHook.js` was the
only static edge running pipeline -> creativeDirector, and the CD tool registry
starts a Series Autopilot in the other direction — together they closed a
22-module strongly-connected component, the largest in `server/services`. In a
static ESM cycle whichever member evaluates first sees `undefined` for the
others' bindings, so any top-level const derived from an import in the ring is a
TDZ crash waiting on a module-ordering change.

New leaf `creativeDirector/projectStartSink.js` inverts that one edge: the
pipeline depends on the sink, the completion hook registers the concrete starter
on it at module evaluation, and `server/index.js` imports the hook for that side
effect at boot. An unregistered request throws rather than silently dropping the
start, because a CD project that never advances is otherwise invisible.

Also applied the barrel rule the issue names: `planAdvance.js` and
`creative/tools/pipeline.js` now import the modules that DECLARE the autopilot
symbols instead of re-entering the `seriesAutopilot.js` barrel from outside the
package. Deferring an import with `await import()` would have hidden the cycle
from the guard without removing the hazard, so it was not used.

The component is gone, not shrunk — `findImportCycleComponents` reports nothing
in that half of the graph, and the #5920 baseline entry is deleted from
KNOWN_CYCLIC_COMPONENTS in serviceImportCycles.test.js.
…ed (#6013)

Review follow-up: the job lingers in the map until closeJobAfterDelay evicts
it, so guarding cancel on the canceled flag alone made a cancel for a completed
import answer ok:true. Mark the job done in the kickoff's finally and require a
running status.
…per-step reasoning (#5992)

A CoS task resolves one provider and one model for its whole run, so a user
who wants strong reasoning for the planning also pays that model's rate for
the mechanical editing. This adds an opt-in orchestration profile: three roles
(architect plans and delegates, implementer executes one spec, reviewer checks
it), each with its own provider/model/effort.

- `server/lib/orchestrationProfile.js` owns the vocabulary, the normalizer, and
  the six-part spec contract a context-free delegated lane needs. Its
  `parseReasoningDirective` NEVER rounds an unsupported rung — a substituted
  level would run a step at an effort nobody chose while reporting success.
- `selectModelForRole` sits alongside `selectModelForTask`, which now resolves
  through the architect role; with no profile the selection is unchanged.
- `resolveStepEffort` resolves a delegated step's rung as spec directive → role
  default → run effort, instead of one effort for the whole run.
- The architect doctrine renders into both prompt paths and is empty for every
  `direct`-mode task, which is the default, so an install that configures no
  profile behaves exactly as before.

Named `orchestrationMode` rather than the issue's `executionMode`: agent
metadata already carries an `executionMode` meaning tui/runner/direct, and
reusing the name — including the value `direct` — for an unrelated axis would
have made both unreadable.
…r a manual Run

Resume and Relaunch both requeued the paused agent's task and stopped there.
The requeue only makes a task ELIGIBLE — what spawns it is the automatic
dequeue `completeAgent` schedules, and that path admits pending user tasks
plus auto-approved system tasks under CoS auto-run in `execute` mode. So on
an install with auto-run off, or for a task still awaiting approval, the task
sat `pending` until the user opened the task list and pressed Run. One click
became two, on the screen the user had just acted from.

`resumeAgent` now force-spawns the task it requeued, through `forceSpawnTask`
— the same door "Run now" uses — so it inherits those refusals rather than
restating them. A stopped/paused daemon, an unreachable runner, a task needing
approval, and a full agent pool all still mean "leave it queued"; the refusal
comes back as `spawnHold` so the dialog names it instead of toasting a resume
that silently didn't start. Relaunch is a pause plus a resume, so it inherits
the dispatch through that composition.

Deliberately not pushed deeper into `reviveBlockedTask` or the `tasks:changed`
unblock listener: those are shared with the autonomous revival paths
(investigation retry, orphan cooldown, completion cleanup), where force-spawning
would strip the auto-run gate that withholds unattended spawns. Both doors into
the new dispatch are a human clicking a button.

Both dialogs render the outcome through one shared helper so neither can say
"queued" for a run that already started, or omit the reason it didn't.
… name the new-task resume outcome

A spawn registers its agent as running BEFORE it flips the task off pending,
and the refusal that lands in that window is forceSpawnTask's own holder guard
— so reading the task status alone still saw 'pending' and reported a hold for
a run already under way. Check the running-agent holder too.

AgentsTab had no 'new-task' wording, so a resumed replacement task that the
server started reported only the generic 'Created resume task'.
hoist the SongBook import Save action into PageHeader so it stays above the fold
fix: cancel yt-dlp audio imports reliably when no child process is running
replace real sleeps and a 22.7M-element Python fixture in the detachedSpawn and trellis2 runner suites
Break the peerSync <-> peerSyncReceive import cycle by extracting the subscription store to a leaf
break the 22-module seriesAutopilot/creativeDirector import cycle with a project-start sink
start a resumed CoS agent's task immediately instead of leaving it pending for a manual Run
…PERATIONAL.md under data/ (#6032)

GOALS.md lives at the repo root and docs/GOALS_OPERATIONAL.md lives
under docs/ — neither exists under data/. Corrected the documented
tree to match.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…6033)

The documented template list (vite+express, node-server, static) no
longer matches SCAFFOLD_TEMPLATES in server/lib/validation.js, so
following the docs produces a template name that fails validation.
Updated the list to the 6 real templates and added the 2 scaffold
endpoints missing from the table (GET /api/scaffold/directories,
POST /api/scaffold/templates/create).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…tion (#6059)

The test asserted `.not.toContain('wt-a'/'wt-b')` against the raw
`git worktree list --porcelain` output, which always includes the
parent sandbox's own entry. When that entry's random mkdtemp() suffix
happens to start with 'a' or 'b', the substring can coincidentally
appear inside the parent's own path and the assertion false-fails
(~3.2% chance per prefix).

Replaced it with a parse of the porcelain output into worktree
entries (mirroring the parsing resetGitWorktreeSandbox itself already
does in gitTestRepo.js, which drops the first entry as always being
the parent) and assert exactly 1 entry remains. This avoids the
collision and also sidesteps comparing full paths directly, which git
can respell on Windows (see the assertPath test in this same file,
#6003).

Verified by forcing the exact collision deterministically (parent
sandbox created at a path ending in `wt-b-XXXXXX`): confirmed the old
assertion fails in that case and the new one does not.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…d set (#6010)

server/lib/conflictJournal.js's RESTORABLE_FIELDS.fableLoom (documented
as the single source of truth for conflict restore/merge) was missing
productionStatus, protagonistCharacterId, protagonistWardrobeId, and
protagonistWardrobeLocked, even though records.js already treats them
as restorable. Concretely: restoring a conflict via "Restore All"
silently stripped those 4 fields, and "merge fields" rejected them
outright with ERR_VALIDATION — a real data-loss path for protagonist
continuity and production sign-off after a sync conflict.

Added the 4 fields to close the gap. Added restore-all and
merge-fields coverage in conflictJournalResolver.test.js, split so the
protagonist-fields case and the productionStatus case don't collide
with mutateLoom's own (unrelated, intentional) rule that clears
productionStatus whenever editorial content actually changes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ure (#6018)

bulkStar in MediaCollectionDetail.jsx ignored updateAnnotation's
result and always fired a success toast, while useMediaAnnotations.js
already toasted an individual error for each failure — contradictory
toasts, plus the success toast lied about items that were actually
reverted.

updateAnnotation now takes a { silent } option and returns { ok, entry }
instead of a bare entry — entry alone can't signal success/failure
because the server legitimately returns entry: null on a real success
too (an unstar with no note clears the annotation entirely). bulkStar
passes { silent: true }, counts successes/failures, and shows one
consolidated toast for all-success, all-failure, and partial-failure.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
server/routes/update.test.js had zero tests for /api/update/sync-fork
despite the route implementing 7 distinct error codes plus success —
regressions in schema validation, status codes, or error mapping had
no automated guard.

Added the 9 cases from the issue's Fix section: success with default
and custom branch, all 4 pre-flight 400s (NO_ORIGIN, NOT_GITHUB,
ALREADY_UPSTREAM, NOT_A_FORK), 502 GIT_UNAVAILABLE, 409 FORK_DIVERGED
(asserting the recovery guidance in the message), 502
FORK_SYNC_FAILED, and a schema rejection on an invalid branch name.
No production code changed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Add an opt-in orchestrated CoS mode with per-role provider/model and per-step reasoning effort
Break the pipeline manuscriptReview <-> manuscriptFix static import cycle
Render practice rating hints as visible button subtext (#6000)
Fix songbook transpose readout width collapsing mobile controls bar (#5999)
Break the loraDatasetCaption <-> loraDatasetGenerate static import cycle (#5917)
Rigged + animated image-to-3D records are selectable through the avatar
variant namespace (rigged-<modelId>, same traversal guard), listed with
server-computed clip coverage, offered in the CoS avatar-style selector,
and played back with a deterministic present-clip fallback for uncovered
states. Eidoverse player-model wiring stays open: no GLB player surface
exists on main (human/cos avatars are VRM-typed for the external host).
… landed

A recent main commit split the rating button's text into a label span
plus a visible hint span, which made the button's accessible name the
full label+hint string instead of just the label — breaking
SongBookViewer.test.jsx's 'Solid' button lookup and, with it, CI on
this branch. Pin the accessible name back to the label via aria-label.
…-location

docs: fix ARCHITECTURE.md directory tree (GOALS.md / GOALS_OPERATIONAL.md location)
feat: expose rigged animated records to CoS avatars
docs: fix app-wizard.md template list and scaffold endpoints table
atomantic and others added 29 commits September 3, 2026 22:04
A suite that writes into the developer's live `data/` is invisible: unlike a
read leak, persisting fixture bytes over their records changes nothing about
whether assertions pass. #6171 was the proof — `providerUsage.test.js` wrote its
fixture quota cards over the machine's real `data/provider-quotas.json`, then
invalidated the sync checksum so peers pulled the fabricated values.

Close that half at runtime, the way `db.js` already refuses row writes to a
non-test database. `lib/testDataIsolation.js` throws when a write resolves
inside the real data root under the test runner, naming the path and the
`createTempDataRoot()` escape hatch. It fires from `atomicWrite`, `ensureDir`'s
create path (an existing dir is a no-op, so read-only suites stay quiet), new
`writeFile`/`appendFile`/`copyFile` wrappers in `fileCore.js`, and
`collectionStore`'s record delete — so the next raw writer inherits the guard
instead of having to remember an import. `aiToolkit/` is untouched, per its
self-containment rule.

It found six real leaks on its first run:

  - `backup.test.js` — `vi.doUnmock` also drops the file-level `vi.mock`, so
    every later suite resolved PATHS.data to the real tree and `runBackup`
    rewrote the user's genuine `data/backup/state.json` on every run.
  - `providers.readiness.test.js` and `loraTraining/captionLeakStaging.test.js`
    — took the MACHINE-WIDE heavy-local-job claim in the live tree, the file
    that gates the user's real local renders.
  - `sharing/integration.test.js` — a hand-rolled PATHS proxy listed `data`,
    `images` and `videos` by hand, so the later-added `imageRefs` still pointed
    at `data/image-refs` and the importer copied bundled sheets there.
  - `assetHash.test.js` and `modelAbuseGuard.materialize.test.js` — wrote
    fixtures into the real tree deliberately, swept up only when nothing threw.

Supporting changes: `isTestRunner` moves out of `db.js` into a dependency-free
`lib/runtimeEnv.js` (the file primitives must not pull in `pg`, and the many
suites spelling `vi.mock('../lib/db.js', () => ({ query }))` were stripping it
out of the graph for every other consumer); `lib/pathContainment.js` owns the
root-inclusive containment and ancestor-canonicalizing helpers, kept a leaf so
`fileCore` reaches them without dragging `errorHandler`/`paths` into every
suite's closure; the guard itself loads through a memoized `await import()`
behind `isTestRunner()`, so production never loads it and the tree-wide import
budget is unchanged. `mockPathsDataRoot.js` gains `lazyTempDataRoot` /
`cleanupTempDataRoots` so the hoisting hazard is explained once rather than in
each suite that redirects a data root.

Writes only: reads stay covered by the two-run probe, and roughly forty services
still reach `PATHS.*` with raw `fs`. Both limits are stated in the module header
rather than implied away, with the sweep tracked separately.
…ment

Local review found three defects in the guard shipped in the previous commit.

The one that mattered: `writeFile`, `appendFile` and `copyFile` FOLLOW a
symlinked destination, but the guard judged only the link's own location. A
fixture symlink inside a temp root pointing at `data/provider-quotas.json`
therefore wrote straight through into live data — the exact leak the guard
exists to stop. Both landing sites are now checked, resolved through `readlink`
+ `canonicalizePath` rather than `realpathSync` so a DANGLING link (one naming a
file the real tree has not created yet) still reports its target.

`isPathAtOrInsideDir` also reported nothing as inside a filesystem or drive
root: those already end in the separator, so anchoring on `root + sep` compared
against `//`. Unreachable from today's `<install>/data` root, but the helper is
a new public export whose contract promises otherwise.

And the `..`-climb case in the guard's own test was vacuous — `path.join`
normalizes its arguments, so the value under test arrived already collapsed and
the assertion held even with `resolve()` removed. Rebuilt by concatenation,
alongside new relative-path, symlink and filesystem-root cases.

Also routes `services/runner.js`'s raw write of `data/runs/<id>/output.txt`
through the guarded wrapper (`agentRunTracking.js` writes the same file), and
exempts the guard's contract test from the static isolation rule: it has to name
the real root to prove a refusal, and every assertion against a real path
asserts the call rejects.
The rebase onto main tightened importScoping.test.js's tree-wide budget
just enough that this file's static import of testDataIsolation.js (and
its pathContainment.js closure) pushed the suite to 85,129 instantiations,
85 over the 85,000 ceiling. fileCore.js already lazy-loads the same guard
behind isTestRunner() for exactly this reason; mirror that pattern here
instead of raising the budget.
spawn a restricted public-review TUI as a direct PTY instead of hosting it in a login shell
# Conflicts:
#	server/services/sprites/walk.test.js
…ier-report

feat: report Tribe emails/phones shared by more than one person
…/ leak

CI caught this after the rebase: the annotated-regen route stages its
init-image snapshot under PATHS.imageRefs (ensureDir + write), and this
suite never redirected PATHS away from the real install tree, so it wrote
that snapshot into the developer's live data/image-refs on every run. It
only looked green locally because that directory already existed from
prior runs — ensureDir's create-path guard is a no-op against an existing
dir, so the write went unnoticed until a fresh checkout (or a first-time
directory) exposed it. This is the same class of leak #6176 already fixed
in six other files; this one's #7.

Also mocks lib/paths.js alongside lib/fileUtils.js: pathSafety.js's
resolveGalleryImage/resolveImageRef/resolveImageInputPath read PATHS from
paths.js directly, so the fileUtils.js redirect alone left the runner's
own re-validation of the staged path checking against the real root.
…l defaults

A `/do:next` claim resolves its reviewers from the claim-work task metadata
FIRST and only falls back to the install-wide Code Review Defaults. Both manual
claim surfaces seeded their reviewer display from `GET /api/code-review/defaults`
alone, which cannot see that override — so a claim-work pin saved months earlier
kept running codex + claude while every reviewer control on screen showed the
antigravity chain the user had since configured. The Issues tab, which offers no
reviewer picker at all, showed nothing.

- New `GET /api/apps/:id/claim-reviewers` resolves the chain through the same
  `resolveClaimWorkMetadata` → `resolveClaimReviewerConfig` path
  `buildClaimWorkTask` uses to fill the prompt's `{reviewers}` token, and reports
  `source` (`task-override` vs `defaults`) so the UI can name the layer that won.
- `useClaimReviewers` backs both surfaces. A failed lookup stays unresolved
  rather than reporting an empty chain — "couldn't ask" must not read as "merges
  with no review".
- The run drawer seeds its untouched picker from that resolution and, on an
  override, points at Chief of Staff → Schedule rather than Models → Code
  Reviewers. The Issues tab renders the same read-only summary beside its
  provider pin.
- `REVIEWER_OVERRIDE_KEYS` / `hasReviewerOverride` replace the hand-listed roster
  in GlobalConfigControls, so the picker's "Use system Code Review Defaults"
  reset clears exactly what the server counts as an override; the client mirror
  is pinned by the existing parity test.
… clearable

Cleanup on the claim-reviewer lookup, plus the one gap that made its advice
unfollowable.

- `claimReviewersFrom` / `resolveAppClaimReviewers` (cosTaskGenerator) now own the
  layer precedence for both the claim builder and the lookup route. The route had
  hand-copied that chain, which is the drift the lookup exists to prevent.
- `hasReviewerOverride` keys on `REVIEWER_LIST_OVERRIDE_KEYS`, not the full
  roster: `reviewStopMode` / `reviewerApplies` are slashdo run flags and a claim
  prompt has no flag string to put them in, so neither can change which reviewers
  run. Reporting a stop-mode as the source sent the user to clear a pin that
  wasn't supplying the list they were looking at. The wide roster stays for the
  picker's reset, which does clear both.
- `ClaimReviewerSource` renders the "where this came from" sentence for both
  surfaces; they had already diverged on which panel they pointed at.
- The reviewer picker — and the "Use system Code Review Defaults" reset beside it
  — now render for claimFlow task types. Their shipped metadata sets neither
  `openPR` nor `reviewLoop`, so the picker never appeared for `claim-work`: the
  override every claim obeys had no control anywhere that could clear it, while
  the claim surfaces told the user to come here and do exactly that.
- `useClaimReviewers` returns the payload or `null` instead of a 9-field sentinel
  with a derivable `resolved` flag, which flattens the drawer's seeding memo.
- Trimmed the retold rationale to the resolution site, and the route's response
  test down to what the route itself decides — the resolution it previews is
  covered behaviorally on the shared resolver.

Follow-ups filed: #6208 (the picker persists a defaults snapshot as an override,
which is what manufactured the stale pin) and #6210 (the JIRA play button skips
the claim-work layer its own docstring promises to honor).
- ClaimReviewerSource sent the user to "this app's Automation tab" to clear the
  override. The reviewer picker is rendered only by GlobalConfigControls, reached
  only through Chief of Staff → Schedule; the Automation tab has no such control,
  so that half of the sentence was a dead end. Names the one screen that works.
- The apiApps doc said `task-override` means the defaults "were never consulted".
  resolveReviewerConfig falls back per FIELD, so a task pinning only `reviewers`
  still takes its models and usernames from the defaults.
- IssuesTab carried an empty-reviewers branch saying a Claim "will merge without
  one". claimSafeReviewers never returns an empty list, so the branch was
  unreachable and its claim was wrong either way.
fix: preserve active model tuning across context-window reloads (#6200)
CI's smoke-boot step (npm run smoke) starts the real server and
deliberately sets NODE_ENV=test to select the file-backend escape hatch
documented in AGENTS.md — it is not a Vitest suite. The #6176 write guard
gated on isTestRunner() (NODE_ENV==='test' OR VITEST), so that legitimate
real boot got treated as a test writing into its own data/ tree and every
startup write (usage.json, instances.json, cos/, brain/, voice-timers.json,
loops) was refused, crashing the smoke-boot job in CI.

Add isVitestRunner() (VITEST only) and use it everywhere the guard decides
whether to fire: fileCore.js's ensureDir/atomicWrite/writeFile/appendFile/
copyFile, collectionStore's record delete, and userActions.js's local
read+write guard. Left isTestRunner() itself, and the backend-selection
call sites that key on it (postRunStore.js, userActions.js's isFile,
sprites/records.js, db.js's non-test-database refusal), unchanged — those
correctly want the broader "NODE_ENV=test OR VITEST" signal.

Verified: `npm run smoke` now boots clean, and the guard still throws for
an actual Vitest suite writing outside its redirected data root.
refuse test writes into the install's real data/ tree at runtime
show which reviewers a manual claim will actually run
…ze-walkset

test(sprites): hoist lockAllAnchors + parallelize buildFinalizedWalkSet's writes
…ion dirs

Grok writes prompt_history.jsonl directly inside a cwd-keyed sessions
folder, as a sibling of the per-session-id directories. Treating every
entry as a session id crashed the reconciler with ENOTDIR trying to
read <file>/summary.json. Fixes #6218.
pitchDetect's throttle test waited on a real 120ms clock, so CPU
contention could starve the unthrottled setTimeout(intervalMs: 1) loop
down to the same tick count as the throttled one; switch it to fake
timers like the rest of the file already does.

localLlm's plain-install tests ran the real disk-space preflight
against the actual filesystem, so a host with less free space than a
curated model's advertised size (16.5GB for Qwen3.8-27B) hit a false
DISK_INSUFFICIENT before ever reaching downloadModel/pullModel; inject
an abundant fake statfsImpl so these tests no longer depend on host
disk capacity.
…RA play-button prompt

resolveClaimReviewerPrompt resolved the Code Review Defaults alone, so a reviewer chain pinned for claims reached GitHub/GitLab/PLAN.md runs but silently not JIRA ones, and GET /api/apps/:id/claim-reviewers previewed a chain the JIRA run would not use. It now takes the app and layers claim-work metadata over the defaults through the same claimReviewersFrom the scheduled path uses; buildJiraTicketTask passes its app through.
fix([issue-6210]): layer the claim-work reviewer override into the JIRA play-button prompt
@atomantic
atomantic merged commit 68df48e into release Sep 4, 2026
12 checks passed
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