Skip to content

fix(apply): prevent one-sided paired closes after live drift - #1042

Closed
vincentkoc wants to merge 1 commit into
mainfrom
fix/clawsweeper-close-guard-pairs
Closed

fix(apply): prevent one-sided paired closes after live drift#1042
vincentkoc wants to merge 1 commit into
mainfrom
fix/clawsweeper-close-guard-pairs

Conversation

@vincentkoc

@vincentkoc vincentkoc commented Aug 6, 2026

Copy link
Copy Markdown
Member

What Problem This Solves

Fixes an issue where ClawSweeper could approve a same-author issue/PR pair from
stale candidate context, then close one side after the counterpart changed,
became policy-ineligible, or could no longer be revalidated.

It also fixes close-time notes that described a PR as already closed before the
final live guards and close command had completed.

Why This Change Was Made

The apply workflow now uses one mutation-free close-reason policy evaluator for
both the current item and its paired counterpart. Candidate results remain a
cheap prefilter; the final path rechecks live stale-version, obsolete-fix,
comment-activity, lease, and pair state before the close-time note and again
immediately before closing.

Related-item refreshes preserve prior identity plus refresh errors, and a known
same-author pair fails closed when its live relation cannot be revalidated.
Confirmed-closed counterparts still enter the normal archive path. The
close-time PR note is status-neutral, and legacy ClawSweeper-owned notes are
updated before the final guards.

No release publishing, npm publishing, or live apply/close operation is part of
this change.

User Impact

Operators can expect paired issue/PR closes to remain atomic from the apply
workflow's perspective: one side is not closed when the other side has reopened,
become blocked by current policy, or cannot be refreshed safely.

PR comments no longer claim that a close already happened while a final live
guard can still keep the PR open.

Evidence

  • Frozen base: 0588bda948653c59a60b65c01d9ff3ce1f780df4.
  • Reviewed head: 1c23b39f3174cdd2a0f90ba9e2c1d7882cce454d.
  • Direct TypeScript build passed: ./node_modules/.bin/tsc -p tsconfig.json.
  • Focused runtime/policy proof passed: 112 tests, 112 passed, 0 failed.
  • Exact-head Codex review found no actionable defects; its direct build, lint,
    and 85 affected tests passed.
  • Independent committed-range ClawSweeper review found no code or security
    blocker against the exact frozen base/head.
  • Type-aware oxlint passed for all changed production files with warnings denied.
  • oxfmt and git diff --check passed.
  • Production TypeScript delta: +43 net lines.
  • Test delta: +215 net lines.
  • The merged fix(workflow): scope comment-only reconciliation #1040 touches workflow
    reconciliation only; it has no overlapping files or runtime ownership with
    this apply-close change.

Real Behavior Proof

Claim

ClawSweeper does not close one side of a same-author issue/PR pair when the
counterpart reopens, fails a current close policy, or cannot be revalidated.
No public close note claims success before final live guards pass.

Exercised surface

The proof executes the compiled apply-decision workflow with controlled GitHub
CLI fixtures, the real pair admission/terminal guard path, the real close-reason
policy evaluator, the close-time comment mutation path, and final lease/policy
sequencing.

Scenario or fixture

  • A counterpart is closed during initial context hydration, then reopens before
    terminal pair validation.
  • A counterpart is closed during initial hydration, then its terminal GitHub
    refresh fails.
  • stale_version_bug is disabled for the counterpart.
  • stale_insufficient_info gains recent human activity.
  • The counterpart becomes locked, closed, or unknown after admission.
  • Current-item stale-version and obsolete-fix policy changes occur after the
    close-time comment/lease step.
  • A legacy ClawSweeper-owned close note is updated before the final guards.

Command and environment

./node_modules/.bin/tsc -p tsconfig.json
node --test --test-concurrency=2 \
  test/apply-close-policy-guards.test.ts \
  test/apply-same-author-pair-close.test.ts \
  test/apply-stale-version-bug-policy.test.ts \
  test/apply-obsolete-fix-pr-policy.test.ts \
  test/apply-label-sync.test.ts \
  test/close-reasons.test.ts

Executed on macOS with Node 26.5.0 from head
1c23b39f3174cdd2a0f90ba9e2c1d7882cce454d, based on
0588bda948653c59a60b65c01d9ff3ce1f780df4.

Observed result

  • Both closed-to-open and closed-to-refresh-error counterparts produced
    skipped_same_author_pair; no close command ran.
  • Counterpart policy blockers prevented pair admission before queue mutation.
  • A confirmed-closed counterpart was queued for the existing archive path.
  • Final stale-version, obsolete-fix, pair, and lease changes prevented close
    after earlier candidate approval.
  • The close-time note says execution is conditional on final live guards.
  • An owned legacy note was patched before the final guard and close sequence.

Artifact or trace

The executable assertions are in:

  • test/apply-close-policy-guards.test.ts
  • test/apply-same-author-pair-close.test.ts
  • test/apply-label-sync.test.ts
  • test/close-reasons.test.ts

Limits

  • Blacksmith Testbox could not start because the repository has no matching
    workflow configuration.
  • AWS Crabbox hydration rejected pnpm/action-setup@v6.0.9; the no-hydrate
    fallback then hit coordinator error 1101 before a lease was created.
  • The full local coverage command remains blocked by the existing package mirror
    miss for pnpm@10.33.0; focused changed-surface proof passed.
  • The committed-range reviewer classified the current proof as controlled
    mock/fixture evidence and requested a redacted production-path apply trace
    before merge. This draft intentionally stops before that final merge gate.
  • No live GitHub item was applied, commented, or closed.
  • No npm or release publishing was performed.

OpenClaw Bay Impact

None. This changes internal apply-close policy and mutation sequencing only; it
does not change dashboard, observer, public status, or data-contract surfaces.

Architecture Notes

  • Root cause: pair and liveness facts were cached at candidate time and reused
    after later mutations.
  • Owner: apply close-policy evaluation and terminal apply sequencing.
  • Canonical fix: one policy evaluator, live terminal revalidation, and
    fail-closed relation refresh.
  • Removed paths: pair-start memoization and final reliance on cached
    stale-version/obsolete-fix candidate results.
  • Sibling coverage: issue/PR pair direction, stale-version, obsolete-fix,
    stale-insufficient-info, locked/closed/unknown state, legacy note migration,
    and dry-run sequencing.

@vincentkoc vincentkoc self-assigned this Aug 6, 2026
@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. P2 Normal priority bug or improvement with limited blast radius. merge-risk: 🚨 automation 🚨 Merging this PR could break CI, automerge, proof capture, label sync, or automation. labels Aug 6, 2026
@clawsweeper

clawsweeper Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Codex review: blocked before merge. Reviewed September 4, 2026, 4:57 AM ET / 08:57 UTC.

ClawSweeper review

What this changes

The PR refreshes paired-item eligibility before closing, shares close-reason checks, preserves failed-refresh identity, and makes pre-close comments conditional.

Merge readiness

Blocked before merge - 2 items remain

Keep open: useful live-policy hardening remains absent from main, and member-authored work is protected from cleanup. Neither previous finding is supported as an introduced defect.

Priority: P2
Reviewed head: 1c23b39f3174cdd2a0f90ba9e2c1d7882cce454d

Review scores

Measure Result What it means
Overall readiness 🦞 diamond lobster (5/6) PR readiness rating was derived from proof quality, review findings, security review, and reviewer confidence.
Proof confidence 🌊 off-meta tidepool Not applicable: Real behavior proof is not required for maintainer- or bot-authored pull requests.
Patch quality 🦞 diamond lobster (5/6) No actionable review findings were identified.

Verification

Check Result Evidence
Real behavior Not applicable Not applicable: Real behavior proof is not required for maintainer- or bot-authored pull requests.
Evidence reviewed 10 items Verified introduced scope: The pinned parent-to-head delta contains 14 files, 443 additions and 184 deletions. The workflow reconciliation changes belong to the base branch, not this PR.
Live terminal checks: The introduced code calls fresh stale-version and obsolete-fix guards and repeats pair validation before the close note and before closeItem.
Previous atomicity finding withdrawn: The pinned base already admitted a counterpart for later processing, closed the current item, and archived it independently. Failure of the second mutation is therefore a pre-existing limitation, not a regression introduced here. The PR body's atomicity claim nevertheless exceeds the implemented guarantee.
Findings None None.
Security None None.

How this fits together

ClawSweeper’s apply lane consumes reviewed issue and PR reports, checks live GitHub eligibility, and publishes comments or closes items. Same-author pair guards connect those decisions across related issues and pull requests.

flowchart TD
  A[Reviewed reports] --> B[Candidate eligibility]
  B --> C[Live GitHub state]
  C --> D[Pair and close-policy checks]
  D -->|Blocked| E[Keep items open]
  D -->|Allowed| F[Conditional close note]
  F --> G[Final guard checks]
  G -->|Blocked| E
  G -->|Allowed| H[Close and archive item]
Loading

Before merge

  • Resolve merge risk (P1) - GitHub reports merge conflicts, and main has since changed paired closeout and freshness receipts; the integrated result remains unreviewed.
  • Complete next step (P2) - Resolve conflicts with current main, narrow the body's atomicity claim, and add the outstanding redacted production-path apply trace; obtain a fresh review for the resulting head and body.
Agent review details

Security

None.

Review metrics

Metric Value Why it matters
Production and test growth Production +205/-162, net +43; tests +237/-22, net +215 The growth has a stated purpose: shared policy evaluation, terminal revalidation, and regression coverage.

Merge-risk options

Maintainer options:

  1. Decide the mitigation before merge
    Integrate the shared live-policy checks with main’s current closeout safeguards and describe their precise pre-mutation guarantee.
  2. Pause or close
    Do not merge this PR until maintainers decide whether the risk is worth taking.

Technical review

Best possible solution:

Integrate the shared live-policy checks with main’s current closeout safeguards and describe their precise pre-mutation guarantee.

Do we have a high-confidence way to reproduce the issue?

Yes, from source: main retains cached pair admission and candidate policy results across later operations. Runtime failure was not executed during this read-only review.

Is this the best way to solve the issue?

Yes for reducing stale-admission windows; the implementation does not provide an atomic two-item transaction, so the body should narrow that claim.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 41caa32f64b5.

Labels

Label justifications:

  • P2: This is a bounded apply-close correctness improvement without evidence of an active emergency.
  • rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🌊 off-meta tidepool and patch quality is 🦞 diamond lobster.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Not applicable: Real behavior proof is not required for maintainer- or bot-authored pull requests.

Evidence

What I checked:

  • Verified introduced scope: The pinned parent-to-head delta contains 14 files, 443 additions and 184 deletions. The workflow reconciliation changes belong to the base branch, not this PR. (1c23b39f3174)
  • Live terminal checks: The introduced code calls fresh stale-version and obsolete-fix guards and repeats pair validation before the close note and before closeItem. (src/clawsweeper-apply-close-execution.ts:259, 1c23b39f3174)
  • Previous atomicity finding withdrawn: The pinned base already admitted a counterpart for later processing, closed the current item, and archived it independently. Failure of the second mutation is therefore a pre-existing limitation, not a regression introduced here. The PR body's atomicity claim nevertheless exceeds the implemented guarantee. (src/clawsweeper-apply-close-execution.ts:311, 0588bda94865)
  • Previous changelog finding withdrawn: The contribution policy explicitly scopes the release-owned changelog restriction to openclaw/openclaw. It does not establish a prohibition on this ClawSweeper changelog entry. (CONTRIBUTING.md:15, 1c23b39f3174)
  • Meaningful work remains on main: Fetched main still memoizes same-author pair admission and uses candidate callbacks for stale-version and obsolete-fix checks. Main already has conditional closeout comments and newer linked-issue sequencing, so that overlap must be reconciled without treating the whole PR as implemented. (src/clawsweeper-apply-close-guards.ts:317, 41caa32f64b5)
  • Captured proof is fixture-based: The supplied body at sourceRevision b0a20b7a05b146629c9d274e467b25cd702ff48577505f918df5ce5f90de8a6c reports 112 passing tests on macOS with Node 26.5.0. Inspection confirms mocked GitHub CLI responses and dry-run pair scenarios; the body explicitly identifies the production-path apply trace as outstanding. (test/apply-same-author-pair-close.test.ts:544, 1c23b39f3174)

Likely related people:

  • Peter Steinberger: Suggested for follow-up; no historical authorship or introduction is verified. (role: unverified routing candidate; confidence: low)
  • Martin Cleary: Suggested for follow-up; no historical authorship or introduction is verified. (role: unverified routing candidate; confidence: low)

Rating scale

Score Internal tier Crab rank Meaning
6/6 S 🦀 challenger crab Exceptional readiness
5/6 A 🦞 diamond lobster Very strong readiness
4/6 B 🐚 platinum hermit Good normal PR; ordinary maintainer review
3/6 C 🦐 gold shrimp Useful, but confidence is limited
2/6 D 🦪 silver shellfish Proof or implementation needs work
1/6 F 🧂 unranked krab Not merge-ready
N/A NA 🌊 off-meta tidepool Rating does not apply

Overall follows the weaker of proof and patch quality.
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

Workflow

  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

History

Review history (41 earlier review cycles; latest 8 shown)
  • reviewed 2026-08-09T19:59:55.614Z sha 1c23b39 :: found issues before merge. :: [P2] Revalidate the pair inside the close mutation guard
  • reviewed 2026-08-09T21:04:35.013Z sha 1c23b39 :: needs changes before merge. :: [P2] Revalidate the pair in the close mutation guard | [P2] Remove the release-owned changelog entry
  • reviewed 2026-08-09T22:48:06.668Z sha 1c23b39 :: found issues before merge. :: [P2] Remove the release-owned changelog entry
  • reviewed 2026-08-09T23:58:43.858Z sha 1c23b39 :: found issues before merge. :: [P1] Keep the first pair item open until the counterpart is terminal | [P2] Remove the release-owned changelog entry
  • reviewed 2026-08-11T12:13:45.026Z sha 1c23b39 :: found issues before merge. :: [P1] Prevent the first close until the paired item is terminal | [P2] Remove the release-owned changelog entry
  • reviewed 2026-08-12T06:24:14.110Z sha 1c23b39 :: found issues before merge. :: [P1] Prevent a split close after the first pair mutation | [P2] Remove the release-owned changelog entry
  • reviewed 2026-08-22T02:18:36.040Z sha 1c23b39 :: found issues before merge. :: [P1] Keep the first pair item open until the counterpart is terminal
  • reviewed 2026-08-29T06:04:18.811Z sha 1c23b39 :: found issues before merge. :: [P1] Keep the first pair item open until the counterpart is terminal | [P2] Remove the release-owned changelog entry

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Aug 7, 2026
@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. and removed rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. labels Aug 9, 2026
@clawsweeper clawsweeper Bot added rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. merge-risk: 🚨 automation 🚨 Merging this PR could break CI, automerge, proof capture, label sync, or automation. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels Sep 4, 2026
@steipete

steipete commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Implemented in #1499, which integrates the paired-close repair with current main and preserves @vincentkoc's contribution. The compiled apply CLI and native GitHub client prove that locking, failed refresh, and reopening of the counterpart keep the parent open, while stable pairs retain their existing close order. The replacement retains current lease, source and managed-locale guards, and makes no atomic remote-close claim. Closing this superseded draft after the replacement merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P2 Normal priority bug or improvement with limited blast radius. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants