Skip to content

fix(thread-ownership): bound forwarder conflict handling#101968

Closed
mushuiyu886 wants to merge 2 commits into
openclaw:mainfrom
mushuiyu886:fix/followup-101743
Closed

fix(thread-ownership): bound forwarder conflict handling#101968
mushuiyu886 wants to merge 2 commits into
openclaw:mainfrom
mushuiyu886:fix/followup-101743

Conversation

@mushuiyu886

@mushuiyu886 mushuiyu886 commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Preserve Thread Ownership 409 ownership-conflict cancellation when the forwarder conflict body is oversized or malformed.
  • Keep the 64 KiB bounded conflict-body read and log unreadable conflict bodies with owner reported as unknown.
  • Keep the Slack mention bypass cache capped at 2000 entries, evicting the oldest remembered thread under high-cardinality mention traffic.

What Problem This Solves

Thread Ownership treats a forwarder 409 as the ownership-conflict signal: another agent owns the Slack thread, so the outgoing thread reply must be cancelled. The first patch bounded the conflict JSON read, but an oversized or malformed 409 body could throw before the cancellation return and fall into the outer fail-open ownership-check catch. That made a conflict response capable of allowing a send.

This update keeps the bounded read but moves parse/overflow handling inside the 409 branch. The 409 status remains authoritative, so unreadable conflict bodies only degrade owner attribution to unknown; they no longer change cancellation into fail-open delivery.

User Impact

  • Why it matters / User impact: In multi-agent Slack deployments, a 409 ownership conflict is the message-delivery guard that prevents one agent from replying into a thread owned by another. A bad conflict body should not bypass that guard. The repaired branch still bounds forwarder response reads and the mention cache, but preserves the user-visible cancellation semantics for all observed 409 conflicts.

Origin / follow-up

Follow-up to #101743, which targets the same Thread Ownership hardening area.

This PR keeps the patch focused on the Thread Ownership extension and updates the existing #101968 repair path after ClawSweeper identified the 409 cancellation regression. It does not close an issue; it is a focused follow-up PR intended to provide a maintainer-reviewable root-cause fix with fresh before/after behavior evidence.

Competition / linked PR analysis

The linked PR #101743 is the known related open PR for this Thread Ownership behavior area. ClawSweeper also reported overlapping hardening PR coverage, so the canonical landing path remains a maintainer decision if another PR is preferred.

This PR's narrower advantage is the now-explicit 409 conflict invariant plus proof quality: the verification drives the production Thread Ownership plugin entrypoint hooks (message_sending and message_received) against a real local HTTP forwarder, compares origin/main-style behavior to this repaired branch, and records small, oversized, and malformed 409 conflict responses plus mention-cache eviction behavior.

  • Related open PR scan: fix(thread-ownership): cap mention cache and bound forwarder JSON reads #101743 is the surfaced linked candidate for this exact Thread Ownership follow-up. ClawSweeper reported additional overlapping hardening coverage; this PR should be reconciled by maintainers against that canonical landing path, but the local repair is intentionally limited to preserving 409 cancellation while keeping the bounded read and cache cap.

Scope / source-of-truth boundary

  • Scope boundary: The patch only changes extensions/thread-ownership: the local extension API barrel, the Thread Ownership plugin entrypoint, and focused regression tests. It does not change Slack routing, channel ingestion, the ownership forwarder API path, request body, SSRF policy, timeout, config schema, or any other extension.
  • Source-of-truth boundary: The source of truth for ownership conflicts remains the forwarder HTTP status 409. The conflict body is only optional attribution for logging. The source of truth for bypassing ownership checks remains the plugin's {channel}:{thread} mention map populated by message_received.
  • Architecture boundary: The changed code sits after OpenClaw has normalized Slack hook context into message_sending / message_received events and before the Thread Ownership plugin posts to the configured forwarder. The proof covers that plugin hook boundary plus the HTTP forwarder boundary.
  • Architecture / source-of-truth check: The canonical source-of-truth contract remains unchanged: forwarder 409 means another owner and must cancel the send; mention map state means the agent was directly mentioned in that Slack thread and can skip the ownership check. The patch only changes the parser/read boundary for optional owner attribution and the retention invariant for mention-map state.
  • Out-of-scope boundary: This does not redefine Thread Ownership ownership semantics, add a new forwarder contract, change Slack ingestion, change plugin configuration, or introduce a new compatibility path.

Real behavior proof

  • Behavior or issue addressed: Thread Ownership no longer lets unreadable forwarder 409 conflict bodies convert an ownership conflict into fail-open send delivery. It also keeps the hard 64 KiB conflict-body read limit and the 2000-entry Slack @mention bypass cache cap.

  • Canonical reachability path: User/config/input → schema/type/ingestion/normalization → runtime object → request/effect: a Slack channel event reaches OpenClaw's plugin runtime as a normalized message_received or message_sending hook call; Thread Ownership resolves ctx.channelId, ctx.conversationId, event.replyToId, event.threadId, and event.metadata; message_received records the canonical {channel}:{thread} key for direct agent @mentions; message_sending checks that runtime map and otherwise posts {"agent_id": agent.id} to /api/v1/ownership/{channelId}/{threadTs}; any forwarder 409 cancels the outgoing Slack thread send even if optional owner JSON is oversized or malformed.

  • Boundary crossed: The proof registered the production Thread Ownership plugin entrypoint and drove the real message_sending and message_received hook handlers. The ownership check crossed a real loopback HTTP socket to a local forwarder process returning 200 and 409 responses. The changed code does not call Slack's SaaS API directly; its channel boundary is the OpenClaw Slack hook payload, and its service boundary is the Thread Ownership forwarder HTTP request.

  • Shared helper / provider constraint check: The patch uses readProviderJsonResponse from openclaw/plugin-sdk/provider-http, the shared bounded JSON response helper backed by readResponseWithLimit. The mention cache cap uses pruneMapToMaxSize from openclaw/plugin-sdk/collection-runtime, matching the shared Map-pruning helper used by other request/memory guard caches.

  • Real environment tested: Local OpenClaw worktree at /media/vdb/code/ai/aispace/openclaw-worktrees/pr-101968, PR repair head 97d609c880df0196158f86a0507ed5ac82d6e4b9. The proof used Node with tsx, the production Thread Ownership plugin entrypoint, normalized Slack hook payloads, and a local HTTP forwarder bound to 127.0.0.1.

  • Exact steps or command run after this patch:

    node --import tsx "$EVIDENCE_DIR/thread-ownership-live-proof.mjs" \
      "$EVIDENCE_DIR/before-thread-ownership/index.ts" before \
      "$EVIDENCE_DIR/thread-ownership-before.json"
    
    node --import tsx "$EVIDENCE_DIR/thread-ownership-live-proof.mjs" \
      "$TASK_WORKTREE/extensions/thread-ownership/index.ts" after \
      "$EVIDENCE_DIR/thread-ownership-after.json"
    
    git diff --check
    node scripts/run-vitest.mjs extensions/thread-ownership/index.test.ts
  • Evidence after fix:

    thread-ownership live proof before passed; evidence=/media/vdb/code/ai/aispace/openclaw-pr-101968-evidence/thread-ownership-before.json
    thread-ownership live proof after passed; evidence=/media/vdb/code/ai/aispace/openclaw-pr-101968-evidence/thread-ownership-after.json
    git diff --check: passed
    node scripts/run-vitest.mjs extensions/thread-ownership/index.test.ts: 24 tests passed
    

    After-patch evidence excerpt:

    {
      "smallConflict": { "cancel": true },
      "oversizedConflict": { "cancel": true },
      "malformedConflict": { "cancel": true },
      "newestMentionSkippedForwarder": true,
      "oldestMentionTriggeredForwarder": true,
      "logs": {
        "info": [
          "thread-ownership: cancelled send to C123:1000.0001 — owned by agent-b",
          "thread-ownership: cancelled send to C123:1000.0002 — owned by unknown",
          "thread-ownership: cancelled send to C123:1000.0003 — owned by unknown"
        ],
        "warn": [
          "thread-ownership: conflict body unreadable (Error: thread-ownership forwarder conflict: JSON response exceeds 65536 bytes), cancelling send",
          "thread-ownership: conflict body unreadable (Error: thread-ownership forwarder conflict: malformed JSON response), cancelling send"
        ]
      }
    }
  • Observed result after fix: A small 409 conflict body cancels the outgoing Slack thread send and logs the owner. An oversized 409 conflict body trips the 64 KiB bounded read, logs JSON response exceeds 65536 bytes, records owner as unknown, and still returns { cancel: true }. A malformed 409 conflict body logs malformed JSON response, records owner as unknown, and still returns { cancel: true }. After 2001 Slack @mention threads, the oldest remembered thread hits the forwarder again while the newest remembered thread still skips the forwarder, proving oldest-entry eviction without breaking the bypass for recent mentions.

  • What was not tested: Production deployment load profile, real workspace traffic volume, and non-Thread-Ownership integrations. The changed code path itself is below Slack event ingestion and does not call Slack's external API; the proof exercises the OpenClaw hook payload boundary and the forwarder HTTP boundary that this patch changes.

  • Fix classification: Root cause fix.

Review findings addressed

  • RF-001: Fixed. Oversized and malformed 409 conflict bodies are caught inside the 409 branch and still return { cancel: true }, so unreadable conflict bodies no longer fall through to the outer fail-open catch.
  • RF-002: Accepted and documented tradeoff. The 2000-entry mention cap intentionally evicts the oldest high-cardinality mention keys, sending older threads back through the forwarder. The after-proof shows oldestMentionTriggeredForwarder: true and newestMentionSkippedForwarder: true, so recent direct mentions keep the bypass while memory stays bounded.
  • RF-003: Disclosed for maintainer reconciliation. fix(thread-ownership): cap mention cache and bound forwarder JSON reads #101743 and ClawSweeper-reported overlapping hardening PR coverage may overlap this behavior; this PR is intentionally narrow and now fixes the 409 cancellation semantics before maintainers choose the canonical landing path.
  • RF-004: Fixed with a narrow repair. The patch preserves 409 cancellation semantics while keeping the bounded conflict-body read and the mention cache cap.
  • RF-005: Fixed at extensions/thread-ownership/index.ts:201-205. Owner parsing failures now degrade to owner = "unknown"; they do not change the cancellation decision.
  • RF-006: Verified. git diff --check passed with no whitespace errors.
  • RF-007: Verified. node scripts/run-vitest.mjs extensions/thread-ownership/index.test.ts passed with 24 tests.

Regression Test Plan

  • Target test file: extensions/thread-ownership/index.test.ts
  • Scenario locked in: message_sending cancels when the forwarder returns 409 with a normal owner body, an oversized owner body, or malformed JSON. message_received retains only the newest 2000 mentioned-thread keys, so the oldest high-cardinality mention returns to the forwarder while the newest mention still skips the forwarder.
  • Why this is the smallest reliable guardrail: The guardrail is intentionally narrow: it hits the two changed invariants in the Thread Ownership test file and relies on live proof for the plugin-entrypoint plus HTTP-forwarder behavior, so future changes cannot reintroduce fail-open 409 conflicts, unbounded conflict-body reads, or unbounded mention-cache retention without a focused failure.

Commands run:

git diff --check
node scripts/run-vitest.mjs extensions/thread-ownership/index.test.ts

Observed result:

Test Files  1 passed (1)
Tests  24 passed (24)
[test] passed 1 Vitest shard in 13.88s

Merge risk

  • Risk labels considered: merge-risk: 🚨 message-delivery, merge-risk: 🚨 availability, merge-risk: 🚨 compatibility.
  • Risk explanation: This touches message-delivery gating because a valid ownership conflict cancels a Slack thread send. It also touches availability because oversized response bodies and high-cardinality mention traffic can affect the plugin process. Compatibility risk is low because no config shape, forwarder endpoint, request payload, timeout, or normal successful response semantics changed.
  • Why acceptable: Valid and unreadable 409 conflicts now consistently cancel sends, successful forwarder responses still allow sends, and non-409 forwarder/network/unexpected failures still use the existing fail-open policy. The cache cap only sends older high-cardinality mention entries back through the existing forwarder check while retaining the newest entries.

Risk / Compatibility

  • Message-delivery behavior for valid small 409 conflicts is preserved: the send is still cancelled.
  • Malformed or oversized 409 conflicts now match the conflict status semantics instead of the generic fail-open error path.
  • Non-409 forwarder/network/unexpected errors keep the existing fail-open behavior.
  • The mention cache still expires entries after five minutes and now also keeps only the newest 2000 entries.
  • The cap value matches the existing Slack thread starter cache size pattern, limiting memory growth without changing normal low-cardinality behavior.

Patch quality notes

  • Patch quality notes: Diff is limited to three Thread Ownership files: production entrypoint, extension API barrel, and focused regression tests. Production imports stay inside the extension's local ./api.ts barrel, which re-exports plugin SDK helpers instead of deep-importing core internals from the extension. No unrelated cleanup, broad refactor, dependency changes, lockfile changes, or docs-only changes are included.

Maintainer-ready confidence

  • Maintainer-ready confidence: High. The root cause is at two local boundaries, the diff is small, related PR overlap is disclosed, and proof covers before/after behavior for all changed paths: bounded forwarder 409 reads, unreadable conflict-body cancellation, and max-size mention cache eviction.

What was not changed

  • What did NOT change: No Slack channel routing or conversation ID canonicalization changes; no ownership forwarder API path, request body, timeout, or SSRF policy changes; no Thread Ownership plugin configuration shape changes; no changes outside extensions/thread-ownership; no unrelated cleanup or refactor.

Root Cause

  • Root cause: The root source is a parser/error-propagation invariant violation in the 409 conflict branch: optional owner JSON parsing was allowed to throw into the same outer catch used for generic ownership-check failures, so a conflict status could be transformed into fail-open send delivery. Separately, the mention bypass cache relied only on time-based expiry, so high-cardinality message_received traffic could keep adding unique {channel}:{thread} keys until TTL cleanup.

  • Why this is root-cause fix: The fix changes the response-consumption boundary where the incorrect propagation happened: 409 is handled first as the authoritative conflict signal, and owner body parsing is contained inside that branch. Parser overflow or malformed JSON now affects only owner attribution, not the cancellation decision. The cache change fixes the retention invariant at the only write point by pruning immediately after each mention key is inserted, so the map cannot exceed the configured maximum regardless of inbound mention cardinality.

@clawsweeper

clawsweeper Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed July 7, 2026, 11:19 PM ET / 03:19 UTC.

Summary
The PR bounds Thread Ownership forwarder conflict-body parsing, preserves cancellation for unreadable 409 conflicts, caps the Slack mention bypass cache, and adds focused regression tests.

PR surface: Source +25, Tests +78. Total +103 across 3 files.

Reproducibility: yes. at source level: current main's 409 branch can throw from resp.json() into the outer fail-open catch, and mentionedThreads has only TTL cleanup. I did not execute the PR tests in this read-only review.

Review metrics: 2 noteworthy metrics.

  • Runtime Guardrails: 1 response cap added, 1 cache cap added. Both guardrails affect Thread Ownership runtime behavior and message-delivery decisions under malformed conflicts or high-cardinality mention traffic.
  • Open Overlap: 2 open related PRs found. Maintainers should pick one canonical Thread Ownership path before merging overlapping bounded-read/cache work.

Stored data model
Persistent data-model change detected: serialized state: extensions/thread-ownership/index.test.ts, vector/embedding metadata: extensions/thread-ownership/api.ts. Confirm migration or upgrade compatibility proof before merge.

Root-cause cluster
Relationship: canonical
Canonical: #101968
Summary: This PR is the strongest current candidate for the narrow Thread Ownership 409/cap repair; related open PRs overlap but are weaker or broader for this exact path.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🦞 diamond lobster
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Choose the canonical Thread Ownership landing path and close or narrow the overlapping PRs after that decision.

Risk before merge

Maintainer options:

  1. Merge The Narrow Thread Ownership Fix (recommended)
    Accept the bounded 409 read, cancellation-preserving conflict behavior, and 2000-entry mention cap in this PR as the canonical Thread Ownership hardening path.
  2. Adjust The Mention Cap First
    If 2000 entries is not the desired retention threshold, ask for a focused cap change plus updated eviction proof before merge.
  3. Pause For Broader Overlap
    If maintainers prefer the broader response-read PR, keep this PR paused until that branch is conflict-free and explicitly owns the same 409 cancellation semantics.

Next step before merge

  • No automated repair is needed; maintainers should reconcile the overlapping PRs and accept the message-delivery cap semantics before merge.

Maintainer decision needed

  • Question: Should this PR be the canonical Thread Ownership landing path for bounded 409 reads and mention-cache pruning, or should maintainers prefer one of the overlapping PRs after it is narrowed or repaired?
  • Rationale: The patch is correct and proven, but merging one of several overlapping branches affects Slack message-delivery semantics and determines which related PRs should be retired.
  • Likely owner: vincentkoc — This PR is assigned to @vincentkoc, and recent Thread Ownership hook/config commits make them the clearest routing owner for the cap and overlap decision.
  • Options:
    • Land This PR As Canonical (recommended): Accept the 2000-entry mention cap and cancellation-preserving 409 semantics here, then close or narrow the overlapping Thread Ownership PRs.
    • Prefer The Broader PR: Pause this PR only if maintainers want the broader bounded-read branch to own Thread Ownership after its conflicts and overlap are resolved.
    • Request A Cap Change: Ask the author to adjust the 2000-entry cap and update tests/proof if maintainers want a different retention threshold.

Security
Cleared: The diff adds no dependency, workflow, permission, secret-handling, artifact-download, or new code-execution surface; it reduces response-body memory exposure on this plugin path.

Review details

Best possible solution:

Land one canonical Thread Ownership fix that bounds 409 reads and mention-cache growth while preserving 409 cancellation; this PR currently looks like the narrowest candidate, with overlapping PRs narrowed or closed after maintainer reconciliation.

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

Yes at source level: current main's 409 branch can throw from resp.json() into the outer fail-open catch, and mentionedThreads has only TTL cleanup. I did not execute the PR tests in this read-only review.

Is this the best way to solve the issue?

Yes, this is the best current fix shape: it uses shared bounded-reader and Map-pruning helpers inside the Thread Ownership plugin while preserving the established 409 cancellation signal. The main alternative PRs are either missing this corrected invariant or broader/conflicting.

AGENTS.md: found and applied where relevant.

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

Label changes

Label changes:

  • add P2: This is focused bundled-plugin message-delivery/resource hardening with limited blast radius and no evidence of an active outage.
  • add merge-risk: 🚨 message-delivery: Merging changes when Slack thread replies are cancelled or sent for unreadable 409 conflicts and evicted mention-bypass entries.
  • add proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes after-fix terminal proof driving the production Thread Ownership plugin hooks against a loopback HTTP forwarder, plus before/after outputs and focused Vitest results.
  • add rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • add status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR body includes after-fix terminal proof driving the production Thread Ownership plugin hooks against a loopback HTTP forwarder, plus before/after outputs and focused Vitest results.

Label justifications:

  • P2: This is focused bundled-plugin message-delivery/resource hardening with limited blast radius and no evidence of an active outage.
  • merge-risk: 🚨 message-delivery: Merging changes when Slack thread replies are cancelled or sent for unreadable 409 conflicts and evicted mention-bypass entries.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR body includes after-fix terminal proof driving the production Thread Ownership plugin hooks against a loopback HTTP forwarder, plus before/after outputs and focused Vitest results.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes after-fix terminal proof driving the production Thread Ownership plugin hooks against a loopback HTTP forwarder, plus before/after outputs and focused Vitest results.
Evidence reviewed

PR surface:

Source +25, Tests +78. Total +103 across 3 files.

View PR surface stats
Area Files Added Removed Net
Source 2 30 5 +25
Tests 1 78 0 +78
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 3 108 5 +103

What I checked:

  • PR head preserves 409 cancellation: At PR head, the 409 branch treats the status as authoritative, catches owner-body parse/overflow failures locally, logs owner as unknown, and still returns { cancel: true }. (extensions/thread-ownership/index.ts:200, 97d609c880df)
  • Current main fail-open path: Current main parses 409 bodies with resp.json() before returning cancel, so malformed JSON can throw into the outer ownership-check catch that allows the send. (extensions/thread-ownership/index.ts:191, a24f15dc4d9e)
  • Bounded reader contract: readProviderJsonResponse reads via readResponseWithLimit and throws labeled errors on overflow or malformed JSON, which is why the PR's local 409 catch is required for cancellation semantics. (src/agents/provider-http-errors.ts:315, a24f15dc4d9e)
  • Cache-pruning contract: pruneMapToMaxSize deletes oldest insertion-ordered Map entries until the cache fits the requested maximum size, matching the PR's oldest-mention eviction behavior. (src/infra/map-size.ts:13, a24f15dc4d9e)
  • Sibling Slack cache pattern: The Slack thread starter cache already uses a 2000-entry cap with pruneMapToMaxSize, supporting the PR's cap choice as a local pattern rather than a new config surface. (extensions/slack/src/monitor/thread.ts:28, a24f15dc4d9e)
  • Regression coverage added: PR-head tests cover oversized and malformed 409 conflict bodies returning cancel, plus oldest-entry mention-cache eviction after 2001 Slack mention threads. (extensions/thread-ownership/index.test.ts:272, 97d609c880df)

Likely related people:

  • vincentkoc: Live PR assignment points to @vincentkoc, and recent commits changed Thread Ownership live config, startup fallback, and mention matching around the same hook path. (role: recent area contributor and live assignee; confidence: high; commits: 65ae1e54de31, 834e50f83cf0, 4ed2ea5035b4; files: extensions/thread-ownership/index.ts, extensions/thread-ownership/index.test.ts)
  • steipete: Authored and committed the original Thread Ownership landing commit and appears repeatedly in related plugin SDK and Thread Ownership history. (role: feature landing and recent area contributor; confidence: high; commits: 51296e770c70, 827b0de0ce74, 4fa5092cdc39; files: extensions/thread-ownership/index.ts, extensions/thread-ownership/index.test.ts, extensions/thread-ownership/api.ts)
  • DarlingtonDeveloper: The original landing commit says it landed Thread Ownership from @DarlingtonDeveloper, including Slack message_sending hook wiring and regression tests. (role: introduced feature behavior; confidence: high; commits: 51296e770c70; files: extensions/thread-ownership/index.ts, extensions/thread-ownership/index.test.ts)
  • Jacob Tomlinson: A prior commit routed the same outbound Thread Ownership request path through fetchWithSsrFGuard, which is the response path this PR now bounds. (role: adjacent runtime-safety contributor; confidence: medium; commits: f92c92515bd4; files: extensions/thread-ownership/index.ts)
  • gumadeiras: Migrated Thread Ownership to scoped plugin SDK imports, relevant to this PR's new SDK helper exports through the local api barrel. (role: SDK boundary contributor; confidence: medium; commits: 7c96d821129a; files: extensions/thread-ownership/index.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

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.

How this review workflow works
  • 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.
Review history (1 earlier review cycle)
  • reviewed 2026-07-08T02:39:51.660Z sha abf347e :: needs changes before merge. :: [P1] Preserve cancellation when 409 JSON parsing fails

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. 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. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. labels Jul 8, 2026
@knoal

knoal commented Jul 13, 2026

Copy link
Copy Markdown

A/B verified locally against base SHA. Ran vitest with the PR's test file against the PR's fix (B) and against the base's fix (A).

Result: CLEAN A/B

A (PR test + base fix): FAIL - 1 test failed
B (PR test + PR fix):   PASS

The new test cancels when the forwarder conflict JSON exceeds the bound fails on base (the conflict payload exceeds the buffer limit and isn't cancelled), passes with the fix. Failing-first signature is correct. Looks ready to merge.

@github-actions github-actions Bot added duplicate This issue or pull request already exists close:duplicate Closed as duplicate dedupe:child Duplicate issue/PR child in dedupe cluster labels Jul 18, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Thanks for the fix. This is now covered by the landed #98941 / commit 9d0836e.

Evidence: overlapping changed hunks; shared file(s): extensions/thread-ownership/api.ts, extensions/thread-ownership/index.test.ts, extensions/thread-ownership/index.ts.

Closing #101968 as a duplicate.

@github-actions github-actions Bot closed this Jul 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

close:duplicate Closed as duplicate dedupe:child Duplicate issue/PR child in dedupe cluster duplicate This issue or pull request already exists extensions: thread-ownership merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: S 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.

3 participants