Release dev to main - #147
Merged
Merged
Conversation
…+ align adopted verdict policy Adopted PRs (authoring_mode = adopted_external_pr) already respawn a Quay worker on changes_requested, so Quay owns their feedback loop. Previously adopted was treated as quay_owned for respawn but as synthetic for the Linear gate and the reviewer verdict policy, so a mixed-finding review on an adopted PR both respawned the worker (fixing non-blocking findings in-loop) AND filed a redundant Linear issue for those same findings. Treat adopted_external_pr like quay_owned for review disposition: - Eligibility gate (review_finding_linear_outbox.ts): loadEligibleFindings and loadCurrentFinding now restrict to authoring_mode = 'synthetic_review' only, so no review_finding_linear_issue outbox rows are enqueued for adopted PRs. - Reviewer verdict policy (pr_review.ts, composeTaskReviewBrief): classify adopted as quay_owned so non-blocking-only findings return changes_requested (worker fixes in-loop) instead of approve-with-notes. This closes the gap where, after removing adopted from the gate, a non-blocking-only finding on an adopted PR would be neither fixed nor filed. Intentional behavior change, not a pure bugfix: it redefines "adopted" as "Quay owns the feedback loop", justified because the worker already respawns. synthetic_review (human owns the branch) is unchanged: non-blocking findings still approve-with-notes and file a Linear issue as the sole capture. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Quay's review-finding -> Linear side effects are enqueued as durable outbox rows and delivered by the Python orchestrator (hermes-agent), not by Quay's own binary. The TypeScript `quay outbox deliver` path that also delivered them was dead code: nothing scheduled it. BRIX-1896 moves Linear delivery fully into the orchestrator, so this removes Quay's now-superseded parallel path. Removed: - `quay outbox deliver` subcommand + `handleOutboxDeliver` (dispatch.ts) and its help entry (help.ts). - Delivery functions in review_finding_linear_outbox.ts: processReviewFindingLinearIssueOutboxItem, deliverClaimedReviewFindingLinearIssue, and their delivery-only helpers (nextEligibleAtFromError, loadOutboxItem, renderLinearIssueBody, formatLineRange, parsePayload, linearIssueProviderIdempotencyKey, stableUuid). The enqueue side (enqueueReviewFindingLinearIssuesInOpenTxn and its queries/helpers) is unchanged; loadEligibleFindings and loadCurrentFinding are left untouched (owned by BRIX-1899). - LinearAdapter.createIssue (its only caller was the removed delivery handler) and its now-dead dependencies: LinearPort.createIssue, LinearCreateIssueInput/LinearCreatedIssue, resolveTeamIdByKey, CREATE_ISSUE_MUTATION, GET_TEAM_BY_KEY_QUERY, RawIssueCreatePayload, RawTeamsByKey/RawTeamNode, normalizeOptionalString. - The adapters.linear.default_issue_team_key config expectation (schema + linearAdapterOptionsFromConfig plumbing) and its docs; it was only read by the removed createIssue path and never set on the deployment. Tests: dropped the deliver-command/handler cases; kept enqueue coverage (the reattachment test now seeds the dedup-ledger link row directly instead of running the removed delivery handler). Depends on BRIX-1896 landing so the orchestrator owns delivery. Part of BRIX-1897. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Make review-finding -> Linear issue creation toggleable from the Quay admin UI: a global default (ON when unset) plus a per-repo tri-state override (inherit / on / off). The switch gates the enqueue in tick.ts — whether the review_finding_linear_issue outbox row is placed — not the drain. When off for a scope no outbox row is produced; findings are still persisted and still appear in the PR review. Only synthetic_review tasks reach this gate, so worker-authored (quay_owned) tasks are unaffected. Stacked on BRIX-1899 (narrows enqueue eligibility to synthetic_review). Layers: - settings: deployment_settings.review_finding_linear_enabled (boolean|null, NULL resolves to ON); read/write mirror the existing agent defaults. - migration: 0040 adds nullable-INTEGER tri-state columns (CHECK IN (0,1)) to deployment_settings and repos. - enqueue gate: review_finding_linear_policy.ts resolves repo-override-else- global-else-ON; tick's persistReviewFindings enqueues only when on. - api: deployment_settings.update + repo.update patches accept the field; global read model exposes review_findings.linear_enabled. - global UI: "Review findings" SubGroup + Toggle under §03 Adapters, distinct from the Linear adapter connectivity flag. - repo UI: "Review findings" SubGroup with Inherit/On/Off Segmented, feeding the Overview overrides counter. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ility BRIX-1899: restrict review-finding Linear issues to synthetic_review + align adopted verdict policy
…oggle BRIX-1898: admin-UI toggle for review-finding Linear issue creation
…liver BRIX-1897: remove dead TS outbox-deliver Linear handler
Follow-up to #135 (BRIX-1899) + #136 (BRIX-1897). `loadCurrentFinding` became dead once #136 removed its sole caller (`deliverClaimedReviewFindingLinearIssue`) while #135 owned the function's eligibility predicate — neither PR could delete it without a cross-PR modify/delete conflict. Now that both are on `dev`, drop it. Non-exported; typecheck + review_finding_linear_outbox tests green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rrentfinding BRIX-1897: remove now-dead loadCurrentFinding
A task's `ticket_snapshot` is captured once at creation and is the definition-of-done the reviewer enforces. When an operator changes scope mid-flight by editing the live Linear ticket, the frozen snapshot never updates, so the reviewer keeps enforcing stale acceptance criteria (this looped BRIX-1907). `resnapshot` gives operators an explicit, audited re-baseline. `quay task resnapshot <task_id> --reason <text>` re-fetches the task's Linear issue and re-composes the snapshot via the exact enqueue path (`fetchTicketContextWithIssue`), then replaces the single per-task `ticket_snapshot` artifact both worker and reviewer read (no version skew). Creation-time augmentations (dependency/hierarchy keys) it does not recompute are preserved verbatim. It emits a `ticket_resnapshotted` audit event carrying the required reason and a before/after diff, and supersedes the latest terminal review verdict so the next tick runs a fresh review against the new snapshot (a stale `changes_requested` no longer blocks re-review via the `terminal_verdict_exists` gate). Running it when the ticket is unchanged is a safe, still-audited no-op. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
fix(core): back off spawn failures (BRIX-1919)
…jection
BRIX-1920: GitHubAdapter.mergePullRequest hardcoded `gh pr merge --merge`,
which fails on squash-only repos ("Merge commits are not allowed on this
repository"). Before merging, read the repo's merge-method policy
(allow_merge_commit / allow_squash_merge / allow_rebase_merge) via
`gh api repos/{owner}/{repo}` and pass the matching flag. Preference order
among allowed methods is merge -> squash -> rebase, so merge-commit repos are
byte-identical to before and squash-only repos use `--squash`. The result is
cached per repo_id (an umbrella's child PRs share one repo). Raises a clear
error if the repo allows no merge method. Applies to every mergePullRequest
call site via the shared adapter.
BRIX-1921: a policy-rejected merge previously fell into the `unknown` bucket,
so the tick retried the identical doomed merge every cycle with no backoff.
Add a distinct non-retryable `method_not_allowed` kind to GitHubMergeError and
classify "not allowed on this repository" / "merge method not allowed" into it.
On a non-retryable merge failure the umbrella auto-merge path now parks the
task into `non_budget_loop` with the reason recorded instead of looping;
retryable failures (head_mismatch, transient not_mergeable) still retry.
Tests: adapter-level method selection per repo config (squash-only -> --squash,
merge-allowed -> --merge, rebase-only -> --rebase, none -> error), per-repo
caching, and classification; tick-level test that a non-retryable failure parks
the task and a second tick does not re-attempt the merge.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
fix(core): handle spawn-window missing worktrees (BRIX-1922)
fix(core): harden missing worktree recovery (BRIX-1922)
feat(cli): add task worktree recreation command (BRIX-1923)
Resolve conflicts from #145 (task recreate-worktree): both PRs add a new `task` subcommand, so keep both entries in dispatch routing, help metadata, and the CLI reference.
An umbrella workflow whose child tasks were all cancelled (observed on BRIX-1902) stayed `active` forever: `readReadyUmbrellaFinalPrWorkflows` gates the final PR on children reaching `merged_to_feature_branch` / `complete_without_quay`, which cancelled children never reach, and no other code path transitions the `umbrella_workflows` row to a terminal state. Add tick-time reconciliation that retires such umbrellas. Each tick, `readRetirableUmbrellaWorkflows` selects `active` umbrellas whose every expected child is linked to a Quay task that terminated as `cancelled` (the exact inverse of the readiness gate) and `retireUmbrellaWorkflow` transitions them to `cancelled`, emitting an `umbrella_retired` tick audit action. Guardrails preserved: umbrellas with a child still in progress, a child merged to the feature branch, a `complete_without_quay` success, a still-unlinked `expected` child, or already `completed` are untouched; no final PR is created, adopted, or dismissed. The `state = 'active'` UPDATE predicate makes re-runs idempotent no-ops. BRIX-1924 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…retire fix(umbrella): retire umbrella workflow when all children are cancelled (BRIX-1924)
…e-method fix(merge): use repo's allowed merge method and back off on policy rejection
…apshot feat: add `quay task resnapshot` to re-baseline a task's ticket snapshot
…ective fix(resnapshot): update task objective
…cli-docs docs: clarify resnapshot objective refresh
This was referenced Jul 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Objective
Release the current
devbranch tomainfor the next Quay patch release.v0.3.42origin/main:94ed23c413294949c50af0b11eaf890bb6589582origin/dev:f0c3e79195e0899569622a7f738d1b8d8e892f03v0.3.41Included PRs
Derived from
main...devcompare commits plus GitHub's associated PR API.quay task resnapshotto re-baseline a task's ticket snapshotDeferred Open PRs
None.
gh pr list --repo InverterNetwork/quay --state open --limit 100now shows only this release PR (#147).Validation
Initial release-candidate run in clean worktree
/private/tmp/quay-release-147-validate-20260714atorigin/devSHA2623a9ff6ec11dbe4ee2ee10aad9afd1cc78ed55.bun install --frozen-lockfile148 packages installed)QUAY_DATA_DIR=/private/tmp/quay-release-147-testdata-empty QUAY_CONFIG_DIR=/private/tmp/quay-release-147-testconfig-empty bun test1332 pass,5 skip,0 fail,6137 expect() calls,1337 tests across 224 filesbun run typecheckbun run buildValidation notes:
bun testwith ambient local Quay environment failed one validator child-process test because the child inherited the local Quay DB/config environment and hitSQLiteError: table identity_mappings already exists. The same focused test passed with isolatedQUAY_DATA_DIR/QUAY_CONFIG_DIR.Bun.serve({ port: 0 })could not bind inside the sandbox. The focused Slack timeout test and the full suite passed outside the sandbox.Post-review release-blocker fix #148 was validated in worktree
/private/tmp/quay-release-147-fix-resnapshotand merged intodev. Follow-up docs PR #149 aligned the user docs with that fix. The finalorigin/devSHA isf0c3e79195e0899569622a7f738d1b8d8e892f03.bun install --frozen-lockfilebun test packages/cli/tests/resnapshot/task_resnapshot.test.ts packages/cli/tests/core/worker_prompt.test.ts packages/cli/tests/adapters/test_github_adapter_merge_method.test.ts41 pass,0 fail,154 expect() callsbun run typecheckbun run buildenv QUAY_DATA_DIR=/private/tmp/quay-release-147-fix-testdata QUAY_CONFIG_DIR=/private/tmp/quay-release-147-fix-testconfig bun test1334 pass,5 skip,0 fail,6152 expect() calls,1339 tests across 224 files29325882122)git diff --checkfor #149 docs fix29326484809)f0c3e79195e0899569622a7f738d1b8d8e892f03(29326570408)Independent review finding addressed:
task_objective, prompt/admin/goal paths read the latest task-level artifacts, and audit hashes cover the exact stored snapshot content.task_objectivecontract.Release Procedure After Merge
After this PR is approved and merged by a human:
origin/mainand confirm it contains this PR's merge commit.v0.3.42.origin/mainSHA with the confirmedv*tag and push the tag.quay-linux-amd64quay-linux-arm64quay-darwin-amd64quay-darwin-arm64SHA256SUMSSHA256SUMS, and run--version.hermes-agentPR that updatesdeploy.values.yamlto the new Quay release tag.Rollback
Pin
hermes-agentback to the previous published Quay tag, currentlyv0.3.41, and rerun the installer.