Skip to content

Improve merger post-approval instructions — exhaustive GitHub merge-blocker checklist - #2382

Merged
lsm merged 33 commits into
devfrom
space/improve-merger-post-approval-instructions-exhaustive-github
Aug 7, 2026
Merged

Improve merger post-approval instructions — exhaustive GitHub merge-blocker checklist#2382
lsm merged 33 commits into
devfrom
space/improve-merger-post-approval-instructions-exhaustive-github

Conversation

@lsm

@lsm lsm commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Closes #856.

Redesigns the post-approval merge flow: the Merger's only job is to merge. On any merge failure it reports the blockers to the Reviewer (the re-approval authority) and waits; the Reviewer re-checks, coordinates the coder, re-approves the (possibly changed) head on GitHub, and signals the Merger to continue; the Merger re-verifies and retries. This replaces the earlier Category A–F self-diagnosis + conflict loop (the merger never self-diagnoses or self-approves), resolving the never-approve-vs-never-merge-unreviewed tension by making the Reviewer the re-approval authority.

Adds Post-Approval ↔ Review channels to the Coding/Research/Coding-with-QA workflows (+ migration 171 to backfill existing Spaces), extends the reviewer prompts with post-approval blocker handling, and rewrites the merge template (~424 → ~150 lines). The Fullstack workflow's approval authority is QA, so its post-approval re-approval routing is left for a follow-up.

…al [#856]

When `gh pr merge` fails for a non-conflict reason, the merger now runs an
exhaustive Category A-F diagnostic checklist (branch-protection/ruleset, PR
state, reviews, CI/checks, permission/access, GitHub mechanics) in order
before escalating to space-agent. mergeStateStatus from step 1 narrows the
category, then each diagnosed blocker routes to its actor: self-fix + retry
(rerun CI, switch method, use --queue), message the coder, or step h for
reviewer/operator needs. The merger never assumes a "GitHub bug" or gives up
silently. Step h keeps the blocked-merge escalation as the final fallback for
cycle-cap exhaustion, routed human/review blockers, or undeterminable failures.

@lsm lsm left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

🤖 Review by glm-5.1 (Zhipu GLM)

Model: glm-5.1 | Client: HyperNeo | Provider: Zhipu GLM

Recommendation: REQUEST_CHANGES

The checklist structure, A→F ordering, diagnose-before-escalate flow, reinforced hard rules, and tests are all solid, and the conflict loop / step-3h escalation guarantees are cleanly preserved. But three of the concrete diagnostic commands hand the merger commands that error at the shell — exactly the "looks like a GitHub bug" failure shape this checklist exists to prevent. All verified against the installed gh v2.97.0.

P1 — three diagnostic commands are invalid:

  1. F1 gh pr merge {{pr_url}} --queuegh pr merge has no --queue flag (only --squash | --rebase | --auto | --disable-auto | --admin). For a merge-queue-required branch, the plain gh pr merge {{pr_url}} --squash already enqueues / enables auto-merge per gh's own help; --queue errors. ⚠️ The new test also locks in this broken command verbatim (expect(text).toContain('gh pr merge {{pr_url}} --queue')) — update it to match the fix.

  2. B3 gh pr view {{pr_url}} --json headRefheadRef is not a valid gh pr view JSON field (Unknown JSON field: "headRef"). Use headRefName (returns an empty string when the branch is deleted). Verified empirically against this PR.

  3. B4 gh pr view {{pr_url}} --json baseRef — same problem: baseRef is invalid. Use baseRefName.

P3 — minor (not blocking, happy to defer):

  • The mergeStateStatus table lists BLOCKED/BEHIND/UNSTABLE/CLEAN/DIRTY but omits real enum values OUT_OF_DATE, HAS_HOOKS, UNKNOWN. An unlisted status just falls through to the full A→F sweep (still correct, just less direct); a catch-all row ("any other status → run the full checklist in order") would close the gap. Note MergeStateStatus.DRAFT is deprecated — drafts surface as BLOCKED, and B2's isDraft check is the authoritative detector (correct as-is).

Once the three commands are corrected (and the F1 test assertion updated), this is good to go. The surrounding design — mergeStateStatus narrowing, category ordering matching the task's hard rules, hard-rules reinforcement, and diagnose-before-escalate — is exactly right.

Comment thread packages/daemon/src/lib/space/workflows/post-approval-merge-template.ts Outdated
Comment thread packages/daemon/src/lib/space/workflows/post-approval-merge-template.ts Outdated
Comment thread packages/daemon/src/lib/space/workflows/post-approval-merge-template.ts Outdated
Address PR #2382 review feedback — three diagnostic commands in the checklist
were invalid and would error at the shell (verified on gh v2.97.0):
- B3: `--json headRef` -> `headRefName` (Unknown JSON field otherwise)
- B4: `--json baseRef` -> `baseRefName`
- F1: there is no `--queue` flag on the merge command; a merge-queue-required
  base branch is enqueued by the plain `--squash` attempt (or `--auto`)

Also add a mergeStateStatus catch-all row (OUT_OF_DATE / HAS_HOOKS / UNKNOWN)
and split Category E (escalate) from Category F (F1 self-fix, F2 escalate).
Tests now assert the valid fields/flags and the absence of the invalid ones.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 704e9978d4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/daemon/src/lib/space/workflows/post-approval-merge-template.ts Outdated
Comment thread packages/daemon/src/lib/space/workflows/post-approval-merge-template.ts Outdated
Comment thread packages/daemon/src/lib/space/workflows/post-approval-merge-template.ts Outdated
Comment thread packages/daemon/src/lib/space/workflows/post-approval-merge-template.ts Outdated
Comment thread packages/daemon/src/lib/space/workflows/post-approval-merge-template.ts Outdated
Comment thread packages/daemon/src/lib/space/workflows/post-approval-merge-template.ts Outdated
Comment thread packages/daemon/src/lib/space/workflows/post-approval-merge-template.ts Outdated
Comment thread packages/daemon/src/lib/space/workflows/post-approval-merge-template.ts Outdated
Comment thread packages/daemon/src/lib/space/workflows/post-approval-merge-template.ts Outdated

@lsm lsm left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

🤖 Review by glm-5.1 (Zhipu GLM)

Model: glm-5.1 | Client: HyperNeo | Provider: Zhipu GLM

Recommendation: APPROVE

All three P1s are fixed and re-verified against gh v2.97.0:

  • F1 --queue removed → plain gh pr merge {{pr_url}} --squash enqueues a merge-queue-required base branch (or --auto), with an explicit "there is NO --queue flag" note. Categories E/F cleanly split (E escalate, F1 self-fix, F2 escalate).
  • B3--json headRefName ... "is empty".
  • B4--json baseRefName.

P3 catch-all row added (OUT_OF_DATE / HAS_HOOKS / UNKNOWN → run the per-category checks, with an OUT_OF_DATE/A10 hint).

Tests now carry both positive assertions (valid fields/flags present) and negative guards (invalid forms absent); the not.toContain('--json headRef\')guard correctly distinguishes the broken form fromheadRefName`. Changed test file 59/0 pass, storage shard 1884/1884 pass locally, lint clean, all 3 threads resolved.

CI note (verified, not just trusted): in run 31119419888 four jobs (1-core, 4-space-storage, 5-space-runtime-a, 5-space-runtime-b) failed at the GitHub-internal "Set up job" step ("Failed to resolve action download info") — a runner infra failure; no test code ran. Confirmed locally those shards are green. A fresh run (31120465435) is in progress; required-status branch protection will block the merge until CI is green.

LGTM — zero outstanding findings.

@lsm lsm left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

🤖 Review by glm-5.1 (Zhipu GLM)

Model: glm-5.1 | Client: HyperNeo | Provider: Zhipu GLM

Recommendation: REQUEST_CHANGES (revising my prior APPROVE)

A third-party bot reviewer posted 9 comments. I validated each independently rather than rubber-stamping, and five are real correctness/robustness bugs — two of them contradict this repo's own code patterns. The prior round's fixes (valid gh fields/flags) stand; these are deeper issues in the diagnostic logic itself, so I'm revising my recommendation.

Should-fix (each verified by me):

  1. B1 --json mergeable "false" (line 240) — mergeable is a string enum (MERGEABLE/CONFLICTING/UNKNOWN), not a boolean. I confirmed it returns "MERGEABLE", and this repo's own presets.ts/pr-ready-validator.ts compare it as strings (eq: ['mergeable','MERGEABLE']). "false" never matches. Fix: compare to CONFLICTING.

  2. A9 git log --format=%G? (line 229) — no commit range, so it scans all local history. The template's own steps a/e are meticulous about fetching the PR head and scoping to base..head; A9 breaks that rule. In a restarted/cache-missed session (wrong branch) or with any unsigned base-history commit, this false-positives and triggers a needless force-push. Fix: git log --format=%G? origin/$BASE..$HEAD_OID (fetch both refs first, per step a).

  3. C1 changes-requested (lines 252-255) — the reviews API returns history; a reviewer who requested-changes-then-approved leaves a stale CHANGES_REQUESTED. Matching any historical entry misroutes the coder on a common scenario. A2 already uses the better reviewDecision. Fix: use the effective latest review per author, or gate on reviewDecision.

  4. A1 rerun on in-progress checks (lines 212-215) — the trigger is "fail or in_progress," but gh run rerun --failed (confirmed: "Rerun only failed jobs") reruns nothing/errors on a still-running run. Fix: for in_progress/pending, wait (or use --auto); only --failed-rerun completed failures.

  5. Step h missing the "undeterminable" branch (line 282) — the file-level comment (lines 59-61) says step h fires on "a genuinely undeterminable failure," but the step-h text only lists human/operator blockers + cycle cap. If step g's APIs fail or no category matches, the agent has no terminating action. Fix: add "OR step g could not determine a category" to step h.

Defer (P3 — valid but lower-value):

  • CLEAN row (line 206): "retry the merge" can loop on a CLEAN-but-permission/method error — add "retry once, then continue to E/F if it fails the same way."
  • C1/D2 gh api (lines 253, 262): omit --hostname <host> — breaks GitHub Enterprise; the template extracts <host> elsewhere.
  • A4 code-owner (line 222): a CODEOWNERS-path change alone doesn't confirm the blocker — verify the branch requires it and an owner hasn't approved before routing.
  • A14 push restrictions (line 236): unlike A12 (force-push)/A13 (deletion), base-branch push restrictions DO gate who can merge (a merge writes the branch) — don't lump them together.

The core design remains sound; these tighten the diagnostic commands to match the template's own established patterns (scoped fetch, string-enum mergeable, effective reviewDecision). Once the five should-fix items land, this is good to go.

Address chatgpt-codex-connector bot review on PR #2382 (1 P1 + 8 P2s). Every
diagnostic command the checklist hands the merger must actually work at the
shell and route correctly:
- P1 CLEAN: mergeable (rules out A-D) is NOT "transient, just retry" — the
  merge already failed, so read the failure output and check Categories E/F
  (permissions, merge method, merge queue) before retrying.
- B1 `mergeable` is the enum MERGEABLE/CONFLICTING/UNKNOWN, not a boolean
  (matches the repo's own pr-ready-validator.ts).
- A1: pending/in_progress checks are WAITED on (or --auto), not rerun —
  `gh run rerun` errors on an unfinished run.
- A9: signature check scoped to the base..head range, not the whole repo
  history (which would blame the coder for unsigned base commits).
- C1: use the latest review / aggregate reviewDecision, not a stale
  historical CHANGES_REQUESTED entry a later APPROVED supersedes.
- A4: a CODEOWNERS path match routes only if owner review is required AND
  unsatisfied.
- A14: push restrictions CAN block a merge (merging writes to the base
  branch); only A12/A13 are non-blocking.
- D2: pass `--hostname <host>` so GitHub Enterprise queries the right host.
- Step h: undeterminable failures (no category match, or a diagnostic API
  error) fall through to step h instead of looping forever.

Updates existing assertions and adds a locking test; 72 workflow tests pass.

@lsm lsm left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

🤖 Review by glm-5.1 (Zhipu GLM)

Model: glm-5.1 | Client: HyperNeo | Provider: Zhipu GLM

Recommendation: APPROVE

Commit a54a836a resolves all five should-fix items from my prior round, verified independently — and also picks up the four P3s:

  • B1 mergeable now compared as the enum CONFLICTING ("never a boolean") — consistent with this repo's own pr-ready-validator.ts.
  • A9 signature check scoped to "ONLY the base..head commits" — no more whole-repo scan / false force-push.
  • C1 rewritten to use reviewDecision + "LATEST review per reviewer" — stale superseded CHANGES_REQUESTED no longer misroutes.
  • A1 now waits on in_progress/pending checks and only --failed-reruns completed failures ("gh run rerun errors on an unfinished run").
  • Step h now explicitly covers "diagnostic APIs themselves error / NO Category A-F item matches," with a matching "go straight to step h" fallback in the step-g hard-rules paragraph.

P3s landed too: CLEAN no longer blindly retries (checks E/F first); D2 passes --hostname; A4 requires owner review to be required AND unsatisfied; A14 correctly treated as a merge blocker (merging writes the base branch) while A12/A13 stay non-blocking.

A new "review round 2" test locks these in with positive + negative assertions; changed file 60/0 pass, lint clean, all 12 review conversations resolved.

CI: the check_failed notifications on run 31120465435 were all conclusion: cancelled — the new push superseded that run and GitHub cancelled its in-progress jobs (not real failures). A fresh run on a54a836a is in progress; required-status branch protection gates the merge until green.

Zero outstanding findings. LGTM.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a54a836a88

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/daemon/src/lib/space/workflows/post-approval-merge-template.ts Outdated
Comment thread packages/daemon/src/lib/space/workflows/post-approval-merge-template.ts Outdated
Comment thread packages/daemon/src/lib/space/workflows/post-approval-merge-template.ts Outdated
Comment thread packages/daemon/src/lib/space/workflows/post-approval-merge-template.ts Outdated

@lsm lsm left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

🤖 Review by glm-5.1 (Zhipu GLM)

Model: glm-5.1 | Client: HyperNeo | Provider: Zhipu GLM

Recommendation: REQUEST_CHANGES (revising my prior APPROVE — the bot's second pass found real issues in the round-3 fixes themselves, one of which I introduced by endorsing the scoped-%G? approach)

P1 — --auto returns without merging (destructive potential). A1's new "gh pr merge --auto" option (line 219) only enables auto-merge — gh's own help says "If required checks have not yet passed, auto-merge will be enabled," and it returns exit 0 without merging. Steps 4–6 assume a real merge, so an agent could delete the head branch, save a "merged" result artifact, and complete the task while the PR is still open (and a premature git push --delete could even break the pending auto-merge). Fix: drop --auto and say "wait for the pending check to complete, then retry step 3 (--squash)"; OR keep it but add an explicit gate: "--auto only enables auto-merge — do NOT proceed to steps 4–6 until gh pr view --json state shows MERGED." (Simplest/safest is to remove it.)

P2 — signature check uses the wrong verifier (destructive false-positive). A9's scoped git log --format=%G? is local verification — it depends on the merger machine's gpg.ssh.allowedSignersFile/keyring, not GitHub's record. An SSH-signed commit GitHub verifies can show E locally → the template tells the agent to message the coder for a needless force-push. Branch protection uses GitHub's verification. Fix: query GitHub's authoritative result, e.g. gh api repos/<owner>/<repo>/commits/<SHA> --jq '.commit.verification.verified' per PR commit (base..head), instead of local %G?. (Credit to the bot — my round-3 "scope it" fix was insufficient; local verification is the wrong tool.)

P2 — C1's condition likely never matches. C1 gates on "reviewDecision is REVIEW_REQUIRED and latest review is CHANGES_REQUESTED," but per GitHub's reviewDecision enum an active change request reports CHANGES_REQUESTED, not REVIEW_REQUIRED — the compound never matches, so an active change request falls through to undeterminable/step-h instead of routing to the coder. Fix: gate on the aggregate reviewDecision == CHANGES_REQUESTED (it already accounts for superseded reviews) — drop the REVIEW_REQUIRED clause.

P3 — A1 should restrict to required checks. Plain gh pr checks includes optional checks; an optional red check would trigger a needless rerun + coder misroute. gh pr checks --required exists ("Only show checks that are required") — use it in A1.

These are the last loose ends I'd want closed before merge; the P1 and the signature P2 have real destructive potential (premature complete / needless force-push). After these, the runbook should be in solid shape. The other categories (A2/A3/A4/A8/A10/A11/A14/B/D2/E/F1/step-h) look correct.

…#856]

Round-4 review (bot + reviewer) on PR #2382 — fixes for issues found in the
prior round's changes:
- P1 A1 --auto: enabling auto-merge only ENABLES it and returns before the
  merge happens (confirmed via gh pr merge --help). A1 now says "do NOT enable
  auto-merge — wait for the check, then retry the step-3 merge" and gates
  steps 4-6 on `state` == MERGED.
- P3 A1 --required: use `gh pr checks --required` so an optional red check
  does not trigger a needless rerun + coder misroute.
- P2 C1: gate on aggregate `reviewDecision == CHANGES_REQUESTED` (not
  REVIEW_REQUIRED — mutually exclusive enum values), superseded only by a
  later APPROVED.
- P2 A9: signature check now uses GitHub verification
  (`gh api .../commits/<SHA> --jq .commit.verification.verified`), not local
  `git log --format=%G?` which depends on the machine GPG/SSH allowed-signers
  config and can disagree with GitHub.

72 workflow tests pass.

@lsm lsm left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

🤖 Review by glm-5.1 (Zhipu GLM)

Model: glm-5.1 | Client: HyperNeo | Provider: Zhipu GLM

Recommendation: APPROVE

Commit c853064e resolves all four round-4 items, verified independently — and the fixes are cleaner than the round-3 changes that triggered them:

  • P1 --auto: A1 now explicitly "do NOT enable auto-merge — wait for the check, then retry the step-3 merge," plus a hard gate "Only proceed to steps 4-6 once state is MERGED." The premature-merge footgun is gone.
  • P2 A9 signatures: switched to GitHub's authoritative gh api --hostname <host> repos/<owner>/<repo>/commits/<SHA> --jq .commit.verification.verified per PR commit — explicitly NOT local git log %G? (which depends on the machine's GPG/SSH allowed-signers). Bonus: carries --hostname for GHES.
  • P2 C1: gates on the aggregate reviewDecision == CHANGES_REQUESTED (not the mutually-exclusive REVIEW_REQUIRED), with the superseded-by-later-APPROVED note.
  • P3 A1: gh pr checks {{pr_url}} --required (excludes optional checks).

Tests updated (round-3 locking test rewritten with the new assertions); changed file 60/0 pass, lint clean, 16/16 review conversations resolved.

My independent read: these are correct and introduce no new attackable surface (the --auto option is removed rather than refined, A9 uses GitHub's own record, C1 is simplified). One minor completeness nit, not blocking: A9 doesn't spell out how to enumerate the base..head commit SHAs first (e.g. gh api repos/.../pulls/<n>/commits) — a competent agent will derive it, and the verification approach itself is right.

CI: the check_failed flood on run 31121202624 was all conclusion: cancelled (the c853064e push superseded a54a836a's run). A fresh run is pending on c853064e; required-status branch protection gates the merge.

Zero outstanding findings. LGTM.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c853064ecc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/daemon/src/lib/space/workflows/post-approval-merge-template.ts Outdated
Comment thread packages/daemon/src/lib/space/workflows/post-approval-merge-template.ts Outdated
Comment thread packages/daemon/src/lib/space/workflows/post-approval-merge-template.ts Outdated
Comment thread packages/daemon/src/lib/space/workflows/post-approval-merge-template.ts Outdated
Round-5 bot review on PR #2382 — four consistency/correctness fixes:
- A1: gh run rerun is Actions-only; an external-provider required check has no
  RUN_ID, so retrigger it via the provider (re-push or its own rerun command).
- step 3g: re-fetch fresh mergeStateStatus (state + check rollup) before
  narrowing — the step-1 snapshot can be stale once the merge fails (base
  advanced / check changed), and a stale CLEAN would wrongly rule out A-D.
- C2: a pending review only blocks if the required approvals are not yet met
  (reviewDecision != APPROVED) and that reviewer is required.
- Hard rules: exempt genuinely in-flight pending checks/reviews from the
  "never sit and poll" rule (waiting for them is correct), with a re-check
  method (gh pr checks --required --watch).

72 workflow tests pass.

@lsm lsm left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

🤖 Review by glm-5.1 (HyperNeo)

Model: glm-5.1 | Client: HyperNeo | Provider: HyperNeo

Recommendation: REQUEST_CHANGES — one focused P2 fix before merge.

Follow-up to my round-5 APPROVE. The bot posted 4 new P2 comments on c853064e; I evaluated each independently against installed gh (v2.97.0) and this repo's actual CI setup. Verdict: 1 actionable P2, 1 minor P3, 2 dismissed.

P2 — Re-query mergeStateStatus after a failed merge, before narrowing (bot discussion_r3730716109) — ACTIONABLE

The step-1 mergeStateStatus is a point-in-time snapshot. Between step 1 and the step-3 merge attempt the base can advance (CLEAN→BEHIND) or a check can turn red (CLEAN→UNSTABLE). Step g then narrows categories from the STALE value. The CLEAN branch (L206-209) explicitly says it "rules out Categories A-D" and steers to "check Categories E/F" — so a stale CLEAN skips A1/D1/D2 (the very gh pr checks --required / commit-status calls that would catch a newly-failed check) and the merger escalates as "unmatched" (step h). That is a false-negative escalation that defeats the checklist, and the "read the failure output" clause scopes itself to E/F so it does not recover.

Fix is cheap and local: at the top of step g, before applying the narrowing, re-query gh pr view {{pr_url}} --json mergeStateStatus,mergeable,state and use the fresh value. The loop already re-queries after a blocker is resolved (L301-303) — mirror that before the initial narrowing. Closes the asymmetry.

P3 — Exempt in-flight checks from "never sit and poll" (bot discussion_r3730716101) — minor, optional

A1 says "wait for the check to finish, then retry"; the hard rule at L300 says "never sit and poll." They do not truly conflict (a pending in-flight check is not an actionable blocker), but one clause ("never sit and poll on an actionable blocker — an in-flight check per A1 is not actionable") removes the ambiguity. Optional; the P2 re-query gives a natural recheck point.

Dismissed — External non-Actions required checks (bot discussion_r3730716099)

Premise is technically right (gh run rerun takes an Actions run-id; an external CI check has none; gh pr checks --json exposes link/workflow but no run-id). But (a) this repo's CI is GitHub Actions only (CLAUDE.md: lint/typecheck/unit/integration are all Actions workflows), so every required check here has an extractable run-id in its link URL; and (b) the existing A1 fallback ("if still failing after 2 reruns, message the coder") is ALREADY the correct action for an external check — the merger cannot rerun external CI, only the coder/provider can. Adding provider-type branching handles a scenario that does not occur here, against the repo's "no error handling for impossible scenarios" rule.

Dismissed — C2 pending-review misroute (bot discussion_r3730716105)

A2 gates on the aggregate reviewDecision; if approvals are satisfied, reviewDecision=APPROVED and A2 does not route to step h. The bot's edge case (approvals-met + an extra unsubmitted pending review) is therefore not reachable as a Category-C blocker, and the checklist's "run the check, then take its action" framing already requires confirming an item is the actual blocker before acting. GitHub does not let an unsubmitted pending review block a merge.

Net

One real P2 (stale mergeStateStatus narrowing) with a one-line re-query fix, directly in the feature being delivered. The rest are a minor clarity nit or over-engineering for a scenario this repo does not hit. After the P2 lands I will re-verify tests and re-approve.

Comment thread packages/daemon/src/lib/space/workflows/post-approval-merge-template.ts Outdated
#856]

Per reviewer Round-6 adjudication on PR #2382, revert two over-engineered
items the bot suggested but the reviewer dismissed:
- A1 external-provider branching: this repo CI is GitHub Actions only, so
  every required check has an extractable run-id; the existing "message coder"
  fallback is already the correct action for any other check.
- C2 conditional pending-review routing: A2 already gates on the aggregate
  reviewDecision (approvals-met -> APPROVED -> A2 does not route), and GitHub
  does not let an unsubmitted pending review block a merge, so the edge case
  is not reachable.

Retained (reviewer-endorsed): the fresh mergeStateStatus re-query at the top
of step g (71a9935) and the exemption of in-flight pending checks from the
"never sit and poll" hard rule (71a9935).

72 workflow tests pass.

@lsm lsm left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

🤖 Review by glm-5.1 (HyperNeo)

Model: glm-5.1 | Client: HyperNeo | Provider: HyperNeo

Recommendation: APPROVE.

Round-7 fresh review of head 1a044bb9 (verified independently, not relayed from claims).

Round-6 items — all correctly resolved:

  • P2 (stale mergeStateStatus) — FIXED. Step g now re-queries gh pr view {{pr_url}} --json state,mergeStateStatus,statusCheckRollup at the top and narrows on the fresh value, closing the stale-CLEAN false-negative that would have skipped the A1/D CI checks. Confirmed statusCheckRollup is a valid field (live query on this PR returned valid JSON, exit 0).
  • P3 (in-flight-check exemption) — FIXED. Hard-rules paragraph now has an explicit EXCEPTION clause: an IN_PROGRESS/pending check or review is not an actionable blocker — wait via gh pr checks --required --watch or a periodic re-query. --watch is a valid flag. This resolves the A1-vs-"never sit and poll" tension.
  • Dismissed items correctly reverted. The external non-Actions-check branching (discussion_r3730716099) and the C2 conditional routing (discussion_r3730716105) were reverted in 1a044bb9. Net diff vs my round-5 APPROVE base shows ZERO change to A1/C2, confirming the simple forms are restored — the right call on the simplicity tradeoff for this Actions-only repo.

Verification at stable head 1a044bb9:

  • Tests: 60 pass / 0 fail (257 expect() calls). (An earlier local failure was a transitional worktree artifact — HEAD advanced 71a9935→1a044bb9 mid-read — not a real failure at any commit.)
  • lint, typecheck, knip, session-guards, db-schema-parity, space-task-handler-tests: all pass.
  • Net PR scope: 2 files (template +132/-1, test +151) — surgical.
  • Review conversations: 21 threads, 0 unresolved.
  • PR: OPEN, mergeable=MERGEABLE (no conflict), targets dev.

One out-of-scope note (NOT a blocker): bun run check exits 1 at check:test-quality, flagging provider-registry.test.ts:748 (describe('inferPersistableProviderForModel')). This is pre-existing — that file is untouched by this PR and the flagged test is present at the merge-base with dev (a37544140). It belongs in a separate PR; fixing it here would be scope creep into an unrelated test.

Clean to merge (squash, no --delete-branch). Returning to APPROVE.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1a044bb977

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/daemon/src/lib/space/workflows/post-approval-merge-template.ts Outdated
Comment thread packages/daemon/src/lib/space/workflows/post-approval-merge-template.ts Outdated
Comment thread packages/daemon/src/lib/space/workflows/post-approval-merge-template.ts Outdated
Comment thread packages/daemon/src/lib/space/workflows/post-approval-merge-template.ts Outdated
Comment thread packages/daemon/src/lib/space/workflows/post-approval-merge-template.ts Outdated
Comment thread packages/daemon/src/lib/space/workflows/post-approval-merge-template.ts Outdated
Comment thread packages/daemon/src/lib/space/workflows/post-approval-merge-template.ts Outdated
…klist [#856]

Two clear internal-consistency bugs from the bot round-7 pass:
- A2 ordering: A2 (review count) fired before C1, so a PR whose aggregate
  reviewDecision is CHANGES_REQUESTED routed to step h (reviewer) instead of
  C1 (coder work). A2 now restricts to REVIEW_REQUIRED and defers
  CHANGES_REQUESTED to C1.
- F1: recommended --auto, contradicting A1 explicit prohibition (same
  enables-not-merges hazard). F1 now says do NOT add --auto; wait for
  state == MERGED.

The other round-7 bot items (changed-head re-review P1, external-CI re-raise,
C2/exemption, headRefName, D2 status filter) are deferred to the reviewer
adjudication — several re-raise Round-6-dismissed items or are conditional
edge cases, and the bot contradicted its own round-2 headRefName advice.

72 workflow tests pass.

@lsm lsm left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

🤖 Review by glm-5.1 (HyperNeo)

Model: glm-5.1 | Client: HyperNeo | Provider: HyperNeo

Recommendation: REQUEST_CHANGES — withdrawing my round-7 APPROVE.

I submitted this for approval at round 7, but the bot's new P1 (plus several P2s) on head 1a044bb9 are real and I missed them. Independent verification below. The P1 is a merge-integrity gap, so the approval must not proceed until it is fixed.

P1 — Re-review a changed head before retrying the merge (bot r3730801484) — BLOCKING

Confirmed asymmetry in the current head:

  • Conflict path (step e, L160-190): after a coder force-push the merger re-runs step 1/2, diffs approved_head_oid..current_head, inspects the FULL delta, and posts a fresh APPROVED/COMMENT before re-merge — "the approval no longer covers the new commits ... re-approve on every retry."
  • Non-conflict path (hard rules, L308-310): "After a routed blocker is resolved (coder pushes...), re-run the step 1 and step 2 checks, then retry the merge." — NO head-delta inspection, NO re-approval.

The non-conflict blockers A9 (sign + force-push), A10 (rebase + force-push), B3 (recreate branch), D1 (fix workflow + push), D4 (push to retrigger) are ALL resolved by a coder push that changes the head OID. A10 (rebase) is a very common path. In a repo without "dismiss stale approvals on push" — and this template explicitly targets arbitrary repos — the merger merges rebased/force-pushed code the reviewer never saw, covered only by the stale approval. That is exactly the failure step e exists to prevent.

Fix: make the hard-rules resolution path mirror step e for ANY coder push that changes the head — capture the approved head OID; after the coder pushes, compare OIDs; if changed, inspect the full delta and post a fresh review before retrying the merge. Conflict fixes already do this; non-conflict fixes must too.

P2 — F1 --auto contradicts A1 (bot r3730801488)

F1 (L297-299) recommends "add --auto for auto-merge," but A1 (L220-224) explicitly prohibits it: "--auto only ENABLES auto-merge and returns before the merge actually happens ... proceed only once state is MERGED." Verified gh pr merge --help: --auto = "Automatically merge only after necessary requirements are met" — i.e. it returns before the merge and the PR can stay open (async merge outside session control). --auto was deliberately dropped from A1 in round 4 for this footgun; F1 reintroduces it. Drop --auto from F1; for a merge queue, retry the plain merge and verify state == MERGED (same as A1).

P2 — A2 misroutes CHANGES_REQUESTED past C1 (bot r3730801510)

A2 (L229-231) fires on "required approving-review count not met" → step h. But reviewDecision=CHANGES_REQUESTED also satisfies "count not met," so the ordered checklist hits A2 → step h (engage reviewer) BEFORE reaching C1, which correctly routes CHANGES_REQUESTED to the CODER. Engaging the reviewer first is wrong — they already reviewed (changes requested); the coder must act first. Restrict A2 to reviewDecision=REVIEW_REQUIRED and let CHANGES_REQUESTED fall through to C1.

P2 — C2 contradicts the EXCEPTION clause (bot r3730801494) — partly my round-7 miss

C2 (L281-282) routes every pending review to step h, but the round-7 EXCEPTION (L305-308) says a pending review is NOT actionable — "wait ... instead of messaging or escalating." Direct contradiction. I introduced this tension by adding the EXCEPTION; the revert of the C2 conditional in 1a044bb9 left them at odds. Resolve one of two ways: scope the EXCEPTION to CHECKS only (a pending review that is required to meet the approval count IS actionable → C2 stands for reviews), or gate C2 on "approvals not met AND that reviewer required." I lean toward scoping the EXCEPTION to checks.

P3 — B3 tests the ref NAME, not existence (bot r3730801501)

headRefName is the recorded branch name (string metadata), not a live-ref check — it stays populated after the branch/fork is deleted, so B3's "headRefName is empty" test may never match. Verify the head ref actually resolves (the headRef object goes null on deletion, or query the head repo's git ref). Rare path, safe degradation (escalate), but the diagnostic is unreliable. Minor.

P3 — D2 should filter to required status contexts (bot r3730801508)

/commits/<SHA>/status aggregates ALL legacy status contexts; an OPTIONAL failing legacy status flips the aggregate to failure and D2 misroutes to the coder. This is the same class of issue as the A1 --required filter added in round 4 — compare individual statuses against the contexts required by branch protection before acting. Minor (legacy statuses are rare in Actions-only repos, but the template targets arbitrary repos).

Dismissed — External non-Actions checks (bot r3730801492, re-raise)

Same item dismissed in round 6. The "template targets arbitrary repos" point is fair, but the existing A1 fallback ("if still failing after 2 attempts, message the coder") is ALREADY the correct terminal action for an external check — the merger cannot rerun external CI, only the coder/provider can. The worst case is 1-2 wasted gh run rerun attempts before that fallback fires; no incorrect merge. Adding provider-type branching for a scenario that degrades safely is over-engineering against the repo's simplicity rule. Not blocking.

Net

One blocking P1 (head re-review on non-conflict coder pushes — merge integrity) and three real P2s (F1 --auto, A2/C1 ordering, C2/EXCEPTION contradiction) to fix before merge; two minor P3s; one re-raise dismissed. Withdrawing the round-7 approval request until at least the P1 and the P2s land.

@lsm lsm left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

🤖 Review by glm-5.1 (HyperNeo)

Model: glm-5.1 | Client: HyperNeo | Provider: HyperNeo

Recommendation: REQUEST_CHANGES — round-9. Two items remain (1 P1 + 1 P2); then I approve.

Verified at head 22e6df0be: tests 60/0 (259 expect), PR OPEN + MERGEABLE.

Confirmed fixed in 22e6df0be (verified):

  • F1 --auto: removed; now "Do NOT add --auto ... wait for state == MERGED." ✓
  • A2/C1 ordering: A2 gates on reviewDecision == REVIEW_REQUIRED and routes CHANGES_REQUESTED to C1 ("skip to C1"). ✓

Still open — P1 (head re-review). My decision: IMPLEMENT.
The coder deferred this to me; my call is to implement it. The template targets arbitrary repos (cannot assume "dismiss stale approvals on push," which is opt-in — and the safety argument also requires required reviews to be enabled; without either, the gap is fully exposed). A10 rebase is a common head-changing path. And the conflict path (step e) already enforces head-delta + fresh review for head-changing pushes — the non-conflict path must be consistent. Fix (low cost): in the hard-rules resolution clause, after a coder push that changes the head OID, apply step-e's head-delta inspection and post a fresh review before retrying — the approval only covers the head it was given. (Decision also posted on the thread.)

Still open — P2 (C2/EXCEPTION contradiction). Must fix.
Not addressed in 22e6df0be. C2 (L281-282) routes pending reviews to step h, but the round-7 EXCEPTION (L305-308) says a pending review is not actionable (wait, don't escalate) — a direct contradiction I introduced. Minimal correct fix: scope the EXCEPTION to CHECKS only ("a check," not "a check or review"). A pending check is never actionable (wait); a pending review needed to satisfy the approval count IS actionable (C2 → step h). The two clauses then no longer overlap. One-word change.

Optional (will NOT block): B3 (verify the head ref resolves, not just headRefName); D2 (filter legacy /commits/<SHA>/status to required contexts, parallel to A1 --required). Nice-to-haves for a later hardening pass.

Dismissed: external non-Actions checks (re-raise; the "message the coder" fallback is already the correct terminal action).

Convergence: once the P1 and the C2/EXCEPTION fix land, I will re-verify and APPROVE. I will not block on the two P3s.

lsm added 2 commits August 6, 2026 13:39
… R8/R9) [#856]

Address the reviewer Round-8/9 blocking items on PR #2382:
- P1: the non-conflict resolution path now mirrors conflict-loop step e for any
  coder push that changes the head. After a routed blocker is resolved, if the
  current headRefOid differs from the one step 1 captured, the merger inspects
  the full delta vs the approved head and posts a FRESH review before retrying
  (no merging unreviewed rebases/signature-fixes in repos without
  auto-dismiss-stale-approvals).
- P2 C2/EXCEPTION: scoped the "never sit and poll" EXCEPTION to CHECKS only
  ("a CHECK ... IN_PROGRESS / pending"); a pending review remains actionable
  via C2. Removes the contradiction.
- P3 B3: tests the head ref itself (git/refs/heads/<headRefName> 404s on
  deletion) instead of the headRefName string, which stays populated.
- P3 D2: notes the /commits/<SHA>/status aggregate includes optional contexts;
  confirm the failing status is required before routing.

(F1 --auto and A2/C1 ordering were fixed earlier at 22e6df0; external
non-Actions checks remain dismissed.)

72 workflow tests pass.
…ws [#856]

Per the reviewer refined preference on the C2 thread (R9): dropping
"pending review in progress" from C2 escalation is strictly better than
scoping the EXCEPTION to checks (option a left the misroute of escalating
an extra pending review when approvals are already met). Now:
- C2 pending review in progress is NOT escalated — the EXCEPTION wait
  covers it (an extra pending review beyond a satisfied requirement does
  not block). C3 (required team review) / C4 (dismissed request) escalate.
- The EXCEPTION again covers both checks and reviews ("a check or review").

P1 (changed-head re-review) was implemented at 0c3a852. 72 tests pass.

@lsm lsm left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

🤖 Review by glm-5.1 (HyperNeo)

Model: glm-5.1 | Client: HyperNeo | Provider: z.ai

Round-10 re-verify at f6e69ed67. C2/EXCEPTION is resolved exactly as agreed — the EXCEPTION now covers checks and reviews (wait, don't escalate), C2 defers a pending review to it (no longer escalates an extra pending review when approvals are met), and C3/C4 still escalate. A2/C1 ordering, F1 --auto, B3 ref-existence, and the D2 required-context caveat all landed cleanly. 60/0 tests (264 expect), 0 unresolved threads.

One item remains — P1, the changed-head guard has no baseline (can't fire).

The guard (L321-325) says: if the coder PUSHED … "the current headRefOid differs from the one step 1 captured" … "inspect the FULL delta vs the approved head." But:

  • Step 1 (L76) captures only state,mergeStateStatus,statusCheckRollup + baseRefName — it does not capture headRefOid. The only headRefOid captures (L113, L170) live inside the conflict path (steps a/e), which this non-conflict path never runs. So "the one step 1 captured" points at a capture that doesn't exist.
  • A transient capture wouldn't persist anyway: the template itself documents (L82-85) that each Bash call is a fresh shell where $BASE must be re-derived every call. The conflict path works only because step b persists approved_head_oid in an artifact — which the non-conflict path never creates.

Net: the guard references a baseline that doesn't exist, so it cannot detect a changed head, so it cannot prevent merging on a stale approval — which is the entire point of the P1 fix.

Fix — one clause, reusing an existing fetch. Establish the approved head from the latest APPROVED/COMMENTED review's commit_id (the head at approval time, recoverable anytime). The template already fetches reviews in step c (gh api --hostname <host> repos/<owner>/<repo>/pulls/<number>/reviews); each review carries commit_id. Verified live on this PR: reviews carry commit_id (e.g. f53a54413…), distinct from the current head f6e69ed67… — so current headRefOid != latest review commit_id correctly flags a coder push, across fresh shells, no transient capture needed.

Suggested wording for L321-325:

BUT if the coder PUSHED to resolve it (A9/A10/B3/D1/D4), compare the current headRefOid to the APPROVED HEAD — the commit_id of the latest APPROVED or COMMENTED review (fetch via the step-c review API; it is the head at approval time and survives across fresh shells, unlike a step-1 shell variable). If they differ, do NOT merge on the stale approval … mirror conflict-loop step e — git diff "<approved commit_id>".."$CUR_HEAD" — and post a FRESH review before retrying.

This is the last item. Once it lands I re-verify and APPROVE — I'm not blocking on anything else (B3/D2 already done; external-CI dismissed).

Recommendation: REQUEST_CHANGES — round-10. One P1 remains (changed-head guard baseline); C2/EXCEPTION and every other item are resolved.

Comment thread packages/daemon/src/lib/space/workflows/post-approval-merge-template.ts Outdated
Bot P1: the changed-head guard compared the current headRefOid to "the one
step 1 captured", but step 1 captures no headRefOid (only state/
mergeStateStatus/statusCheckRollup/baseRefName) and a transient capture would
not survive the fresh shell of a later Bash call, so the baseline was undefined
and the guard could not fire. The guard now recovers the APPROVED head = the
commit_id of the latest APPROVED/COMMENTED review (via the paginated reviews
API) — the head at approval time, durable across fresh shells.

72 workflow tests pass.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fdc8b8d1b6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/daemon/src/lib/space/workflows/built-in-workflows.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f63a8e8583

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/daemon/src/lib/space/workflows/post-approval-merge-template.ts Outdated
Comment thread packages/daemon/src/lib/space/workflows/built-in-workflows.ts Outdated
…icate merger) [#856]

The post-approval merger sub-session (created by spawnPostApprovalSubSession)
has no node_execution row, so it was invisible to ALL message-delivery paths
(AgentMessageRouter peers, ChannelRouter.activateNode). A Reviewer reply over
Review→Post-Approval would lazy-activate a DUPLICATE merger session.

Fix: AgentMessageRouter now accepts a findPostApprovalSessionId callback. When
building the peers list, if the task has a live postApprovalSessionId and an
agent declared in nodeGroups that has no node_execution (the merger), the live
session is added to peers — so messages route to the existing session instead
of activating a new one.

Wired in TaskAgentManager.buildNodeAgentMcpServerForSession via taskRepo lookup.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 03cdc06e8a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/daemon/src/lib/space/runtime/agent-message-router.ts Outdated
Comment thread packages/daemon/src/lib/space/runtime/agent-message-router.ts Outdated
Comment thread packages/daemon/src/lib/space/workflows/post-approval-merge-template.ts Outdated
Comment thread packages/daemon/src/lib/space/workflows/built-in-workflows.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 273704b884

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/daemon/src/storage/schema/m171-backfill-post-approval-review-channels.ts Outdated
Comment thread packages/daemon/src/lib/space/workflows/built-in-workflows.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d5bfc21a0e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/daemon/src/lib/space/workflows/post-approval-merge-template.ts Outdated
Comment thread packages/daemon/src/lib/space/workflows/built-in-workflows.ts Outdated
Comment thread packages/daemon/src/lib/space/runtime/task-agent-manager.ts Outdated
…856]

Addresses the post-approval redesign review round (3 inline comments) and
completes the duplicate-merger-session fix.

1. Approval authority is now derived, not hard-coded.
   The merger template addressed blockers to "Review" by default, but in the
   Fullstack workflow QA is the approval authority and BOTH Review and QA are
   reachable — so a blocker could misroute to Review. dispatchPostApproval now
   derives {{approval_authority}} from the approving/submitting node (Review for
   Coding/Research, QA for Fullstack) and the merge template addresses it
   directly. The blocker report message is also self-instructing (it tells the
   authority to re-approve the current head and reply), so it works even for a
   Space whose authority prompt predates the redesign paragraph.

2. Backfill the post-approval re-approval paragraph for existing Spaces.
   Existing template-linked workflows retain the pre-redesign QA/Reviewer
   prompt (no paragraph). The appended paragraph is now a retired-prompt
   variant so mergeNodeStructuralFieldsFromTemplate restores it on re-stamp.

3. Liveness-gate the merger session in delivery paths.
   AgentMessageRouter.findPostApprovalSessionId returns the id only when
   isSessionAlive confirms it, so a merger that died mid-wait is not treated as
   a live peer (which would inject the continue message into a dead session).

4. Complete the duplicate-merger fix (#11).
   ChannelRouter.deliverMessage knew about the live merger only via
   AgentMessageRouter's peers list, but its own lazy-activateNode step still
   created a pending node_execution for the Post-Approval node, so the tick loop
   spawned a DUPLICATE merger. ChannelRouter now skips activateNode when the
   target node declares a post-approval route and a live merger session exists.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 14cb60c86c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/daemon/src/lib/space/runtime/task-agent-manager.ts Outdated
Comment thread packages/daemon/src/lib/space/workflows/post-approval-merge-template.ts Outdated
…uting [#856]

Second review round on the post-approval redesign.

- Scope the live merger session to its target agent only. The peers fix mapped
  the merger session to every declared-but-unactivated agent, so a message to an
  unrelated inactive node (e.g. an unused branch) would be injected into the
  merger. AgentMessageRouter now maps it only under the post-approval route's
  targetAgent (resolved via findPostApprovalTargetAgentName); covered by a new
  over-matching test.

- Bind the INITIAL merge to the approved head. The first attempt did not verify
  the approval covered the current head or pass --match-head-commit, so a push
  that changed the head after approval could merge an unreviewed head. Step 3 now
  captures headRefOid, confirms the latest review covers it, and binds the merge
  with --match-head-commit (matching the retry path).

- Require "Recommendation: APPROVE" in the COMMENTED own-PR fallback. GitHub
  stores both APPROVE and REQUEST_CHANGES from the PR owner as COMMENTED; without
  the marker a changes-requested review or plain comment could be accepted as
  approval and a rejected head merged. Both step 3 and 3d now require the marker.

- Unresolvable-blocker reply. The reviewer/QA prompts now instruct replying with
  reason "unresolvable" for administrative blockers (merge permission, ruleset),
  and the merger's step 3c escalates to space-agent on that signal instead of
  waiting indefinitely.

- QA own-PR COMMENTED fallback. QA has no post_review tool, so the QA prompt now
  prescribes the accepted COMMENTED fallback via a direct reviews API call.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fd23cb661b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/daemon/src/lib/space/workflows/built-in-workflows.ts Outdated
Comment thread packages/daemon/src/lib/space/workflows/built-in-workflows.ts Outdated
Comment thread packages/daemon/src/lib/space/runtime/task-agent-manager.ts Outdated
Third review round.

- Register post_review for QA (not just the Reviewer). QA is now a review-capable
  approval authority, so it re-approves via the same centralized tool the Reviewer
  uses, which posts the marked review (own-PR COMMENTED fallback with the
  "Recommendation: APPROVE" body marker, and the PR URL host). This replaces the
  QA prompt's hand-rolled reviews-API fallback, which (a) omitted the
  "Recommendation: APPROVE" marker the merger requires and would have been
  rejected, and (b) did not pass the hostname, breaking GitHub Enterprise PRs.

- Non-lazy (in-memory) liveness for the post-approval merger session in both
  delivery paths. The lazy isSessionAlive can report a persisted-but-unrehydrated
  merger as alive after a daemon restart (the merger has no NodeExecution to
  rehydrate from); treating it as live would skip activation and crash
  injectSubSessionMessage ("Sub-session not found"). Both the AgentMessageRouter
  callback and ChannelRouter.resolveLivePostApprovalSession now prefer an
  in-memory probe that returns true only when the session is actually registered.
  The dead-merger channel-router test now proves the in-memory probe overrides
  the lazy false-positive.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1e3f569772

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/daemon/src/lib/space/workflows/built-in-workflows.ts Outdated
Comment thread packages/daemon/src/lib/space/workflows/built-in-workflows.ts Outdated
Comment thread packages/daemon/src/lib/space/workflows/built-in-workflows.ts Outdated
…iew guidance [#856]

Fourth review round.

- PR_MERGER_SLOT_PROMPT is behavioural-only: it no longer hard-codes "Reviewer" as
  the blocker authority. The merge procedure (first user turn) carries the
  {{approval_authority}} token; a slot prompt naming "Reviewer" is higher priority
  and would override it, so in the Fullstack workflow the Merger could route a
  blocker to Review instead of QA. The slot prompt now says "the approval
  authority" and defers to the Runtime Execution Contract.

- Move the QA post-approval paragraph to AFTER the QA slot procedure (it was
  embedded in FULLSTACK_QA_PROMPT, before the steps that end with "call
  approve_task()"). On a blocker resume the green-path "call approve_task as your
  final action" step could otherwise lead QA to re-approve the already-approved
  task and stop without signalling the Merger. Appended after the steps, the
  paragraph is the final applicable behaviour and explicitly overrides that step
  for blocker cycles.

- Correct the own-PR re-approval guidance in the QA and Reviewer paragraphs:
  request APPROVE via post_review (the tool auto-retries as a marked COMMENT
  review carrying "Recommendation: APPROVE" on an own-PR). The prior wording told
  the agent to request COMMENT directly, which lands an UNMARKED comment the
  Merger rejects.

New regression tests: merger slot prompt is behavioural-only (no "Reviewer");
QA paragraph placement after the approve_task step; QA requests APPROVE not COMMENT.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 07ac26fe74

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/daemon/src/lib/space/runtime/channel-router.ts Outdated
…de routes) [#856]

Fifth review round.

The duplicate-merger skip guard in ChannelRouter.deliverMessage checked
targetNode.postApproval — whether the TARGET node declares a post-approval route.
But post-approval-validator allows a route declared on one node to target an agent
in ANOTHER node. For such cross-node routes the guard failed both ways: the real
target node (no declaration) was activated, letting the tick loop spawn a
duplicate merger; and a message to the declaring node (not the target) would
incorrectly skip activation.

The guard now keys on the dispatched route's target agent: it collects every
post-approval targetAgent (node-level routes plus the legacy workflow-level
route) and skips activation only when the target node CONTAINS one of those
agents and a live merger session exists. The AgentMessageRouter
findPostApprovalTargetAgentName callback now also falls back to the legacy
workflow-level route.

New cross-node test: route declared on the Review node, target agent in the
Post-Approval node, live session present — activation is correctly skipped for
the Post-Approval node (which does not itself declare the route).

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: aefd242fe4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/daemon/src/lib/space/runtime/agent-message-router.ts Outdated
Comment thread packages/daemon/src/lib/space/runtime/task-agent-manager.ts Outdated
…sk-agent route [#856]

Sixth review round (2 items).

- Prefer the recorded live merger over stale executions. The over-matching guard
  refused to map the live postApprovalSessionId if ANY merger node_execution
  existed, so a stale execution (a terminal row with an old session, or a pending
  row left by the pre-fix duplicate-activation path) shadowed the live merger —
  the approval authority's continuation reached the stale execution instead of
  the waiting merger and the loop stalled. AgentMessageRouter now keeps the live
  merger as the delivery target for its agent unless an execution already
  represents that exact session, dropping same-agent peers pointing at a different
  session. New test: stale merger execution + live session → message reaches the
  live session.

- Resolve the same dispatched route. findPostApprovalTargetAgentName and
  ChannelRouter.getPostApprovalTargetAgents returned the first declaration
  unconditionally, but PostApprovalRouter skips the legacy 'task-agent' target
  and dispatches the first VALID route. For a workflow with a task-agent route
  before a merger route, the live session was registered under 'task-agent'
  instead of the dispatched merger agent. Both now mirror the router's selection
  (skip 'task-agent', nodes-then-legacy order, first valid). New channel-router
  test: a task-agent-only route does not skip activation.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fcd399bd04

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/daemon/src/lib/space/workflows/post-approval-merge-template.ts Outdated
…ep [#856]

Seventh review round (1 item).

Step 3e (cycle cap / escalation) hard-coded "Post-Approval ↔ Review loop". In the
Fullstack workflow the blocker loop is Post-Approval ↔ QA while a separate Review
channel also exists; if they have different maxCycles, the Merger would inspect
the wrong budget and wait or escalate on an unrelated route. Use
{{approval_authority}} (as the blocker handoff in 3b already does) and tell the
Merger to read the Post-Approval ↔ {{approval_authority}} budget specifically.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a6b08fe488

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/daemon/src/storage/schema/m171-backfill-post-approval-review-channels.ts Outdated
Comment thread packages/daemon/src/lib/space/runtime/task-agent-manager.ts
…review for authority slots [#856]

Eighth review round (2 items).

- Migration 171 now remaps backfilled channel endpoints to the persisted node names
  via their stable agent slots ('merger' -> Post-Approval, 'reviewer' -> Review,
  'qa' -> QA), querying space_workflow_nodes. A template-linked built-in with
  renamed nodes previously got unusable channels (canonical literals naming no
  node); now they resolve to the renamed names, matching mergeChannelsFromTemplate.
  New test: renamed nodes -> channels use the renamed endpoints.

- post_review is now granted based on the slot being the workflow's approval
  authority (the end node), not just the agent's reviewer/qa preset. A customized
  agent assigned to the Fullstack qa slot (different handle) still gets the tool its
  slot prompt tells it to use; the Post-Approval/merger node never qualifies.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3d903428c2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/daemon/src/storage/schema/m171-backfill-post-approval-review-channels.ts Outdated
…al schema) [#856]

Ninth review round.

Migration 171 eagerly prepared its space_workflow_nodes lookup statement, so on a
partial schema that has the full space_workflows columns but lacks
space_workflow_nodes, SQLite threw "no such table" and aborted the migration (and
daemon startup) instead of taking the documented fallback path. The statement is
now prepared only when the table exists; the canonical-name fallback applies
otherwise. New test drops space_workflow_nodes and asserts the migration is a
no-op-with-fallback rather than throwing.

(The CI migrations-b timeouts on the prior commit were unrelated — the shard
passes locally in ~40s; they were CI-load flakes.)
@lsm
lsm merged commit a44f3c9 into dev Aug 7, 2026
36 checks passed
@lsm
lsm deleted the space/improve-merger-post-approval-instructions-exhaustive-github branch August 7, 2026 02:03
lsm added a commit that referenced this pull request Aug 7, 2026
…2) [#851]

Adds a nullable space_tasks.post_approval_source_node_id column (migration 172
— 171 was taken by the Post-Approval ↔ Review channel backfill in #2382) plus
type / repository mapping and the test-DB schema entry. Migration 172 also
backfills the column from pending_completion_submitted_by_node_id for in-flight
review / crash-stranded approved rows, so an upgrading database does not lose
the source node when the pending field is later cleared on approval.
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.

1 participant