Skip to content

Fix Slack integration event context preview#130

Merged
khaliqgant merged 4 commits into
mainfrom
fix/slack-integration-event-context-retry
Jun 6, 2026
Merged

Fix Slack integration event context preview#130
khaliqgant merged 4 commits into
mainfrom
fix/slack-integration-event-context-retry

Conversation

@kjgbot
Copy link
Copy Markdown
Contributor

@kjgbot kjgbot commented Jun 6, 2026

Summary:

  • retry targeted Relayfile reads briefly for Slack message events before falling back to expanded event data
  • avoid injecting sparse {path, deleted} fallback blobs as Slack message content
  • shorten Slack integration event system messages while preserving location, message, and path
  • harden Slack raw-id/__slug alias dedupe when one copy has readable context and the other only has sparse/missing context

Tests:

  • node --experimental-strip-types --no-warnings --test src/main/tests/integration-event-bridge.test.ts
  • npm test

@codeant-ai
Copy link
Copy Markdown

codeant-ai Bot commented Jun 6, 2026

Your free trial PR review limit of 300 PRs has been reached. Please upgrade your plan to continue using CodeAnt AI.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 6, 2026

Review Change Stack

Warning

Review limit reached

@agent-relay-code[bot], we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 54 minutes and 22 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 74f3dcb6-3138-4ddd-a00c-aeddd1ebe1fa

📥 Commits

Reviewing files that changed from the base of the PR and between c3ac1ed and 539d2af.

📒 Files selected for processing (2)
  • src/main/__tests__/integration-event-bridge.test.ts
  • src/main/integration-event-bridge.ts
📝 Walkthrough

Walkthrough

Adds Slack-targeted read retry/backoff, sparse relayfile pointer detection to avoid empty previews, refactors Slack message assembly and dedupe/injection logic, and extends tests and harness to simulate and validate transient read failures and duplicate-suppression scenarios.

Changes

Slack Context Retry & Formatting

Layer / File(s) Summary
Test harness: simulate transient read failures
src/main/__tests__/integration-event-bridge.test.ts
makeHarness gains readFileFailuresBeforeSuccess, a readFileAttempts counter, and mocked client.readFile behavior to throw for initial attempts.
Integration tests: new Slack scenarios
src/main/__tests__/integration-event-bridge.test.ts
Refactor waitForDropped timeout param and add/adjust Slack tests: duplicate suppression across alias paths, retry-before-fallback behavior, sparse-pointer non-injection, and fallback assertions including readFileCalls ordering.
Retry schedule, delay helper, and sparse relayfile detection
src/main/integration-event-bridge.ts
Add EVENT_CONTEXT_READ_RETRY_DELAYS_MS, a delay(ms) helper, SlackLogicalInjectionState and slackLogicalInjections map, and isSparseRelayfilePointerData so sparse {path}/{deleted,path} payloads return undefined previews.
Slack message formatting and dedupe key changes
src/main/integration-event-bridge.ts
Reformat Slack <integration-event> message header construction and change Slack dedupe key generation to omit content-preview-based fingerprinting.
readEventContextPreview: Slack-targeted read retries and fallback
src/main/integration-event-bridge.ts
Perform multiple delayed client.readFile attempts for Slack-targeted context paths using the retry schedule; after final failure, fall back to event.expand('full') and build preview from expanded data.
Slack logical injection claim/release refactor
src/main/integration-event-bridge.ts
Replace prior recentInjections.delete behavior with claimSlackLogicalInjection(...) and releaseDedupeKey(...) helpers implementing expiry and optional content hashing for suppression and release.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • AgentWorkforce/pear#116: Overlapping Slack targeted remote context preview retry and fallback logic with test harness extensions.

Suggested labels

size:XL

Poem

🐰 I hop through retries, patient and spry,
Waiting for files that flit and fly,
Sparse pointers vanish, previews bloom,
Tests keep watch in the integration room,
A quiet rabbit nibbles at flaky I/O 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title directly summarizes the main change: fixing Slack integration event context preview behavior through retry logic and sparse data handling.
Description check ✅ Passed The description provides concrete details about the changeset, including retry logic for Relayfile reads, sparse data handling, message shortening, and deduplication improvements.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/slack-integration-event-context-retry

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces retry logic for reading Slack event context previews, filters out sparse relayfile pointer data from context previews, adjusts the formatting of Slack integration event messages, and adds corresponding integration tests. The review feedback suggests two improvements: first, aborting the retry loop early on unauthorized or forbidden errors (401/403) to prevent blocking the sequential event queue; second, using bracket notation instead of dot notation when accessing properties on Record<string, unknown> to ensure TypeScript compilation safety under strict configurations.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +2254 to +2262
for (const [index, delayMs] of readDelays.entries()) {
if (delayMs > 0) await delay(delayMs)
try {
return eventContextPreviewFromFile(await client.readFile(handle.workspaceId, path))
} catch (error) {
readFileError = error
if (index === readDelays.length - 1) break
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

If client.readFile fails with an unauthorized or forbidden error (401/403), retrying is guaranteed to fail and will introduce unnecessary delays (up to 1.25 seconds total). Since the event dispatcher processes and awaits event deliveries sequentially, this delay will block the entire event queue for the project. Aborting the retry loop early on unauthorized errors prevents this performance bottleneck.

Suggested change
for (const [index, delayMs] of readDelays.entries()) {
if (delayMs > 0) await delay(delayMs)
try {
return eventContextPreviewFromFile(await client.readFile(handle.workspaceId, path))
} catch (error) {
readFileError = error
if (index === readDelays.length - 1) break
}
}
for (const [index, delayMs] of readDelays.entries()) {
if (delayMs > 0) await delay(delayMs)
try {
return eventContextPreviewFromFile(await client.readFile(handle.workspaceId, path))
} catch (error) {
readFileError = error
if (isUnauthorizedError(error) || index === readDelays.length - 1) break
}
}

Comment on lines +1555 to +1563
function isSparseRelayfilePointerData(path: string, data: unknown): boolean {
if (!isRecord(data)) return false
const keys = Object.keys(data).sort()
if (keys.length === 1 && keys[0] === 'path') return data.path === path
if (keys.length === 2 && keys[0] === 'deleted' && keys[1] === 'path') {
return data.path === path && typeof data.deleted === 'boolean'
}
return false
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Accessing properties via dot notation on Record<string, unknown> (returned by isRecord) can cause TypeScript compilation errors under strict compiler configurations (e.g., with noPropertyAccessFromIndexSignature or strict type checking). Using bracket notation is safer and more idiomatic for index-signature types.

Suggested change
function isSparseRelayfilePointerData(path: string, data: unknown): boolean {
if (!isRecord(data)) return false
const keys = Object.keys(data).sort()
if (keys.length === 1 && keys[0] === 'path') return data.path === path
if (keys.length === 2 && keys[0] === 'deleted' && keys[1] === 'path') {
return data.path === path && typeof data.deleted === 'boolean'
}
return false
}
function isSparseRelayfilePointerData(path: string, data: unknown): boolean {
if (!isRecord(data)) return false
const keys = Object.keys(data).sort()
if (keys.length === 1 && keys[0] === 'path') return data['path'] === path
if (keys.length === 2 && keys[0] === 'deleted' && keys[1] === 'path') {
return data['path'] === path && typeof data['deleted'] === 'boolean'
}
return false
}

@codeant-ai
Copy link
Copy Markdown

codeant-ai Bot commented Jun 6, 2026

Your free trial PR review limit of 300 PRs has been reached. Please upgrade your plan to continue using CodeAnt AI.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/integration-event-bridge.ts`:
- Around line 2250-2262: The read loop in readEventContextPreview keeps retrying
every error from client.readFile (called via
getWorkspaceHandle().client().readFile) including permanent auth/permission
failures; change the loop in readEventContextPreview so that after catching an
error you detect permanent/non-transient failures (e.g., auth, 403/401,
permission-denied, token-expired semantics or use an isTransient/error.code
check) and immediately break/return to fall back to expand('full') instead of
waiting for subsequent delays from EVENT_CONTEXT_READ_RETRY_DELAYS_MS; only
await delay and retry when the error is identified as transient.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 28bc8804-91d3-47dc-8ba0-0aacc12544a5

📥 Commits

Reviewing files that changed from the base of the PR and between 1ce8be0 and fc11bf3.

📒 Files selected for processing (2)
  • src/main/__tests__/integration-event-bridge.test.ts
  • src/main/integration-event-bridge.ts

Comment on lines +2250 to +2262
const readDelays = slackEventContextPath(path) ? [0, ...EVENT_CONTEXT_READ_RETRY_DELAYS_MS] : [0]
const handle = await this.getWorkspaceHandle()
const client = handle.client()
if (typeof client.readFile === 'function') {
return eventContextPreviewFromFile(await client.readFile(handle.workspaceId, path))
for (const [index, delayMs] of readDelays.entries()) {
if (delayMs > 0) await delay(delayMs)
try {
return eventContextPreviewFromFile(await client.readFile(handle.workspaceId, path))
} catch (error) {
readFileError = error
if (index === readDelays.length - 1) break
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Stop retrying permanent Slack preview read failures.

This loop retries every Slack readFile error, including permanent auth/permission failures. Because injectEvent() awaits readEventContextPreview() on the per-project dispatch path, a broken session turns each Slack event into four doomed remote reads and ~1.25s of avoidable head-of-line delay before falling back to expand('full'). Break out immediately for non-transient errors and only delay-retry the transient ones.

Suggested fix
         for (const [index, delayMs] of readDelays.entries()) {
           if (delayMs > 0) await delay(delayMs)
           try {
             return eventContextPreviewFromFile(await client.readFile(handle.workspaceId, path))
           } catch (error) {
             readFileError = error
-            if (index === readDelays.length - 1) break
+            if (isUnauthorizedError(error) || index === readDelays.length - 1) break
           }
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/integration-event-bridge.ts` around lines 2250 - 2262, The read loop
in readEventContextPreview keeps retrying every error from client.readFile
(called via getWorkspaceHandle().client().readFile) including permanent
auth/permission failures; change the loop in readEventContextPreview so that
after catching an error you detect permanent/non-transient failures (e.g., auth,
403/401, permission-denied, token-expired semantics or use an
isTransient/error.code check) and immediately break/return to fall back to
expand('full') instead of waiting for subsequent delays from
EVENT_CONTEXT_READ_RETRY_DELAYS_MS; only await delay and retry when the error is
identified as transient.

@agent-relay-code
Copy link
Copy Markdown
Contributor

Fixed the PR issues I found:

  • Removed the generated memory/workspace/.relay/state.json artifact from the PR.
  • Updated MCP search_history and recent_history schemas to accept source: "trajectory", matching the SDK/CLI support.
  • Added smoke-test coverage confirming those MCP tool schemas include the trajectory source.

Local validation passed:

  • pytest -q test_ai_hist.py
  • npm test in sdk-ts

Note: the checked-out .workforce/context.json identified the repo as AgentWorkforce/ai-hist PR 10, not AgentWorkforce/pear PR 130, so I reviewed and fixed the checked-out PR artifacts.

@agent-relay-code
Copy link
Copy Markdown
Contributor

⚠️ pr-reviewer did not push — the PR branch advanced during the review, so fixes were withheld to avoid overwriting newer commits. Re-trigger the review once the branch settles. The notes below are advisory and were not pushed.

Fixed the PR issues I found:

  • Removed the generated memory/workspace/.relay/state.json artifact from the PR.
  • Updated MCP search_history and recent_history schemas to accept source: "trajectory", matching the SDK/CLI support.
  • Added smoke-test coverage confirming those MCP tool schemas include the trajectory source.

Local validation passed:

  • pytest -q test_ai_hist.py
  • npm test in sdk-ts

Note: the checked-out .workforce/context.json identified the repo as AgentWorkforce/ai-hist PR 10, not AgentWorkforce/pear PR 130, so I reviewed and fixed the checked-out PR artifacts.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 2 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/main/integration-event-bridge.ts">

<violation number="1" location="src/main/integration-event-bridge.ts:2584">
P2: Slack dedupe treats a prior sparse preview as a permanent duplicate match, which can suppress real later message updates for the full replay TTL.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread src/main/integration-event-bridge.ts Outdated
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 2 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/main/integration-event-bridge.ts">

<violation number="1" location="src/main/integration-event-bridge.ts:2262">
P2: The retry loop does not distinguish between transient and permanent errors. When `readFile` fails with a 401/403/auth/permission error, the loop still performs all remaining retries (up to 4 total attempts with ~1.25s cumulative delay). Since `isUnauthorizedError()` is already defined in this file, use it to break out of the loop immediately on permanent failures:

```typescript
} catch (error) {
  readFileError = error
  if (index === readDelays.length - 1 || isUnauthorizedError(error)) break
}
```</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

return eventContextPreviewFromFile(await client.readFile(handle.workspaceId, path))
} catch (error) {
readFileError = error
if (index === readDelays.length - 1) break
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: The retry loop does not distinguish between transient and permanent errors. When readFile fails with a 401/403/auth/permission error, the loop still performs all remaining retries (up to 4 total attempts with ~1.25s cumulative delay). Since isUnauthorizedError() is already defined in this file, use it to break out of the loop immediately on permanent failures:

} catch (error) {
  readFileError = error
  if (index === readDelays.length - 1 || isUnauthorizedError(error)) break
}
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/main/integration-event-bridge.ts, line 2262:

<comment>The retry loop does not distinguish between transient and permanent errors. When `readFile` fails with a 401/403/auth/permission error, the loop still performs all remaining retries (up to 4 total attempts with ~1.25s cumulative delay). Since `isUnauthorizedError()` is already defined in this file, use it to break out of the loop immediately on permanent failures:

```typescript
} catch (error) {
  readFileError = error
  if (index === readDelays.length - 1 || isUnauthorizedError(error)) break
}
```</comment>

<file context>
@@ -2233,10 +2249,19 @@ export class IntegrationEventBridge {
+            return eventContextPreviewFromFile(await client.readFile(handle.workspaceId, path))
+          } catch (error) {
+            readFileError = error
+            if (index === readDelays.length - 1) break
+          }
+        }
</file context>
Suggested change
if (index === readDelays.length - 1) break
if (index === readDelays.length - 1 || isUnauthorizedError(error)) break

@agent-relay-code
Copy link
Copy Markdown
Contributor

Fixed one PR breakage in integration-event-bridge.test.ts: waitForDropped now accepts the optional timeout used by the new retry-related tests.

Validated locally:

  • npm test
  • npm run build
  • npm run verify:mcp-resources-drift

@codeant-ai
Copy link
Copy Markdown

codeant-ai Bot commented Jun 6, 2026

Your free trial PR review limit of 300 PRs has been reached. Please upgrade your plan to continue using CodeAnt AI.

@agent-relay-code
Copy link
Copy Markdown
Contributor

pr-reviewer applied fixes — committed and pushed c3ac1ed to this PR. The notes below describe what changed.

Fixed one PR breakage in integration-event-bridge.test.ts: waitForDropped now accepts the optional timeout used by the new retry-related tests.

Validated locally:

  • npm test
  • npm run build
  • npm run verify:mcp-resources-drift

@agent-relay-code
Copy link
Copy Markdown
Contributor

Fixed two validated issues in PR #130:

  • Slack logical dedupe now tracks all delivered content hashes within the TTL, so an old replay after a real edit is suppressed instead of reinjected.
  • Async test helpers now assert on timeout and waitForDropped honors the intended timeout parameter.

Verified with:

  • node --experimental-strip-types --no-warnings --test src/main/__tests__/integration-event-bridge.test.ts
  • npx tsc --noEmit
  • npm run build
  • npm run verify:mcp-resources-drift
  • npm test

@codeant-ai
Copy link
Copy Markdown

codeant-ai Bot commented Jun 6, 2026

Your free trial PR review limit of 300 PRs has been reached. Please upgrade your plan to continue using CodeAnt AI.

@agent-relay-code
Copy link
Copy Markdown
Contributor

pr-reviewer applied fixes — committed and pushed 539d2af to this PR. The notes below describe what changed.

Fixed two validated issues in PR #130:

  • Slack logical dedupe now tracks all delivered content hashes within the TTL, so an old replay after a real edit is suppressed instead of reinjected.
  • Async test helpers now assert on timeout and waitForDropped honors the intended timeout parameter.

Verified with:

  • node --experimental-strip-types --no-warnings --test src/main/__tests__/integration-event-bridge.test.ts
  • npx tsc --noEmit
  • npm run build
  • npm run verify:mcp-resources-drift
  • npm test

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/main/integration-event-bridge.ts (1)

2390-2391: 💤 Low value

Redundant dedupe recomputation.

dedupe is recomputed with identical inputs (duplicateKey, fingerprint) since contextPreview no longer affects eventDedupeKeyWithFingerprint. This assignment can be removed.

Suggested fix
     if (needsSlackContentAwareDedupe) {
-      dedupe = eventDedupeKeyWithFingerprint(duplicateKey, fingerprint)
       if (!this.claimSlackLogicalInjection(dedupe.key, contextPreview, dedupe.ttlMs)) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/integration-event-bridge.ts` around lines 2390 - 2391, Remove the
redundant recomputation of dedupe inside the needsSlackContentAwareDedupe
branch: the variable dedupe is being reassigned using
eventDedupeKeyWithFingerprint(duplicateKey, fingerprint) with the same inputs
already used elsewhere and contextPreview no longer affects that function, so
delete the assignment in the if (needsSlackContentAwareDedupe) block (leave any
other logic in that block intact) and rely on the previously computed dedupe
value; reference: dedupe, eventDedupeKeyWithFingerprint, duplicateKey,
fingerprint, needsSlackContentAwareDedupe.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/main/integration-event-bridge.ts`:
- Around line 2390-2391: Remove the redundant recomputation of dedupe inside the
needsSlackContentAwareDedupe branch: the variable dedupe is being reassigned
using eventDedupeKeyWithFingerprint(duplicateKey, fingerprint) with the same
inputs already used elsewhere and contextPreview no longer affects that
function, so delete the assignment in the if (needsSlackContentAwareDedupe)
block (leave any other logic in that block intact) and rely on the previously
computed dedupe value; reference: dedupe, eventDedupeKeyWithFingerprint,
duplicateKey, fingerprint, needsSlackContentAwareDedupe.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d03e63e8-ff70-405f-80db-2371245b6962

📥 Commits

Reviewing files that changed from the base of the PR and between fc11bf3 and c3ac1ed.

📒 Files selected for processing (2)
  • src/main/__tests__/integration-event-bridge.test.ts
  • src/main/integration-event-bridge.ts

@khaliqgant khaliqgant merged commit bf5eb56 into main Jun 6, 2026
4 checks passed
@khaliqgant khaliqgant deleted the fix/slack-integration-event-context-retry branch June 6, 2026 13:10
kjgbot pushed a commit that referenced this pull request Jun 6, 2026
Main independently landed the Slack context-preview/dedupe line as #130 with
a stronger claim shape: contentHashes as a Set, so late alias copies of ANY
previously seen edit stay suppressed (the single-hash variant would re-inject
a stale copy of edit N-1 after edit N). Resolution keeps main's Set design
and re-applies this branch's blind-claim fix on top: a blind claim learns the
hash from the suppressed late content copy, so genuine edits within the TTL
still inject. The edit-after-blind regression test is retained.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants