Skip to content

Canonicalize Slack webhook paths in core - #257

Merged
khaliqgant merged 6 commits into
mainfrom
fix/core-slack-envelope-canonicalization
Jun 7, 2026
Merged

khaliqgant merged 6 commits into
mainfrom
fix/core-slack-envelope-canonicalization

Conversation

@khaliqgant

Copy link
Copy Markdown
Member

Summary

  • port the Slack webhook path canonicalization behavior into @relayfile/core
  • canonicalize Slack provider-relative paths such as /channels/C123/... to /slack/channels/C123/...
  • ignore out-of-provider Slack paths instead of materializing them
  • resolve raw Slack channel IDs to existing same-channel channelId__name aliases before file writes/events
  • use canonical paths for webhook coalescing keys
  • bump @relayfile/core to 0.8.17 for publish

Validation

  • npm run test --workspace=packages/core
  • npm run build --workspace=packages/core
  • npm pack --workspace=packages/core --dry-run
  • git diff --check

Publish note

npm whoami is khaliqgant, and npm access list collaborators @relayfile/core --json reports khaliqgant: read-write, so I should be able to publish @relayfile/core@0.8.17 after merge.

@codeant-ai

codeant-ai Bot commented Jun 7, 2026

Copy link
Copy Markdown

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

@coderabbitai

coderabbitai Bot commented Jun 7, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

@khaliqgant, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 19 minutes and 23 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: 01c11521-3bf0-430f-afae-50aefff6b6db

📥 Commits

Reviewing files that changed from the base of the PR and between 9927ddd and c5a3f28.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (10)
  • .trajectories/active/traj_y5jru5dh9ku6/trajectory.json
  • .trajectories/completed/2026-06/traj_hk2sfepahlu0.json
  • .trajectories/completed/2026-06/traj_hk2sfepahlu0.md
  • .trajectories/index.json
  • packages/core/CHANGELOG.md
  • packages/core/package.json
  • packages/core/src/webhooks.test.ts
  • packages/core/src/webhooks.ts
  • packages/sdk/typescript/package.json
  • packages/sdk/typescript/src/client.test.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/core-slack-envelope-canonicalization

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.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request implements Slack webhook envelope path canonicalization, ensuring provider-relative channel paths and /slack/... paths are treated equivalently, raw channel IDs are resolved to existing aliases, and out-of-provider paths are ignored. It also adds a comprehensive test suite for these changes. Feedback on the changes highlights a performance bottleneck in the Slack channel alias resolution logic, where calling storage.listFiles() and mapping/splitting every file path in large workspaces can cause significant CPU overhead; a more efficient prefix-filtering approach is suggested to resolve this.

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 +701 to +711
const candidates = files
.map((file) => normalizePath(file.path).slice(1).split("/"))
.filter(
(fileParts) =>
fileParts.length >= 3 &&
fileParts[0] === "slack" &&
fileParts[1] === "channels" &&
fileParts[2]?.startsWith(`${channelSegment}__`),
)
.map((fileParts) => fileParts[2] as string)
.sort();

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

Performance Bottleneck in Channel Alias Resolution

Calling storage.listFiles() returns all files in the workspace. In large workspaces, this array can contain thousands of files.

The current implementation maps, slices, and splits the path of every single file in the workspace before filtering. This creates significant CPU overhead and garbage collection pressure on every webhook event application.

By filtering the normalized paths using startsWith first, we can avoid splitting and slicing the paths of unrelated files.

  const prefix = `/slack/channels/${channelSegment}__`;
  const candidates = files
    .map((file) => normalizePath(file.path))
    .filter((p) => p.startsWith(prefix))
    .map((p) => p.slice(1).split("/")[2] as string)
    .sort();

@github-actions

github-actions Bot commented Jun 7, 2026 •

Copy link
Copy Markdown

Relayfile Eval Review

Run: .relayfile/evals/runs/2026-06-07T21-00-24-124Z-HEAD-provider
Mode: provider
Git SHA: db0e6c3

Passed: 4 | Needs human: 0 | Reviewable: 0 | Missing output: 0 | Failed: 0 | Skipped: 0

Human Review Cases

No reviewable human-review cases captured Relayfile output.

@cubic-dev-ai cubic-dev-ai 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.

3 issues found across 5 files

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

Re-trigger cubic

Comment thread packages/core/src/webhooks.ts
Comment thread packages/core/src/webhooks.ts
Comment thread packages/core/src/webhooks.ts Outdated
@codeant-ai

codeant-ai Bot commented Jun 7, 2026

Copy link
Copy Markdown

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 7f15ed4 to this PR. The notes below describe what changed.

Fixed two issues in packages/core/src/webhooks.ts:

  • ingestWebhook now passes the normalized provider into normalizeEnvelopePath, so Slack provider-relative paths like /channels/... queue correctly instead of being rejected.
  • Addressed Gemini’s review by filtering Slack alias candidates by prefix before splitting path segments.

Local validation passed:

  • npm test --workspace packages/core -- webhooks.test.ts
  • npm test --workspace packages/core
  • npm run build --workspace packages/core
  • scripts/check-contract-surface.sh
  • npm pack --workspace=packages/core --dry-run

I did not print READY because the public GitHub check-run API still showed cubic · AI code reviewer as in_progress, with the PR mergeable state reported as unstable at the time I checked.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Devin Review found 1 potential issue.

View 3 additional findings in Devin Review.

Open in Devin Review

if (normalizeProvider(provider) !== "slack") {
return path;
}
return canonicalizeSlackChannelAliasPath(storage.listFiles(), path);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🚩 storage.listFiles() called on every Slack envelope application

canonicalizeExistingProviderAliasPath at packages/core/src/webhooks.ts:687 calls storage.listFiles() to scan ALL files in the workspace every time applyWebhookEnvelope processes a Slack envelope. For large workspaces with thousands of files, this is O(n) per webhook. Then canonicalizeSlackChannelAliasPath at line 701-711 further splits and filters every file path. This is correct but potentially expensive. Consider adding a narrower query method to StorageAdapter (e.g., listFilesByPrefix(prefix)) or caching the channel alias map rather than scanning all files on every webhook.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@cubic-dev-ai cubic-dev-ai 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.

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

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

Re-trigger cubic

Comment thread packages/core/src/webhooks.ts
@codeant-ai

codeant-ai Bot commented Jun 7, 2026

Copy link
Copy Markdown

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

@khaliqgant

Copy link
Copy Markdown
Member Author

Addressed the remaining PR-review storage-scan concern in commit 1aa330c. canonicalizeExistingProviderAliasPath now proves a Slack path is a raw /slack/channels/<channelId>/... path before calling storage.listFiles(), so Slack DMs, non-channel paths, and already-aliased channelId__name paths do not scan storage. Added regression coverage that raw channel alias resolution scans once, while already-aliased channel and DM paths scan zero times.

Also checked the SDK failure reported in src/client.test.ts: the focused digest test passes, and the full TypeScript SDK suite passes after building the SDK package first so @relayfile/sdk package exports resolve.

Validation run locally:

  • npm run test --workspace=packages/core -- webhooks.test.ts
  • npm run test --workspace=packages/core
  • npm run build --workspace=packages/core
  • npm pack --workspace=packages/core --dry-run
  • scripts/check-contract-surface.sh
  • npm run build --workspace=packages/sdk/typescript
  • npm run typecheck --workspace=packages/sdk/typescript
  • npm run test --workspace=packages/sdk/typescript

@codeant-ai

codeant-ai Bot commented Jun 7, 2026

Copy link
Copy Markdown

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

@khaliqgant

Copy link
Copy Markdown
Member Author

Follow-up for the failing src/client.test.ts CI annotation: pushed 5db0ef0 to stabilize waitForExpectation. The failing digest test was waiting for async WebSocket materialization with only 20 immediate timer turns; on CI that could expire before readFile + digest computation completed. It now uses a real deadline with a short poll interval.

Validation after the change:

  • npm run test --workspace=packages/sdk/typescript -- src/client.test.ts -t "computes fallback digests without exposing file content"
  • npm run build --workspace=packages/sdk/typescript
  • npm run typecheck --workspace=packages/sdk/typescript
  • npm run test --workspace=packages/sdk/typescript
  • git diff --check

@agent-relay-code

Copy link
Copy Markdown
Contributor

⚠️ pr-reviewer push failed (exit 1) — fixes were not applied to the PR. The notes below are advisory and were not pushed.

Implemented two additional fixes for PR #257:

  • Added an early guard in webhooks.ts so Slack alias resolution only calls storage.listFiles() for raw /slack/channels/<id>/... paths that can actually need alias lookup.
  • Added a regression test in webhooks.test.ts proving non-channel Slack paths do not scan files.
  • Aligned @relayfile/sdk’s dependency on @relayfile/core to 0.8.17 in package.json and regenerated package-lock.json.

Validation passed locally:

  • npm ci
  • npm run test --workspace=packages/core
  • npm run build --workspace=packages/core
  • npm run test --workspace=packages/sdk/typescript
  • npm run typecheck --workspace=packages/sdk/typescript
  • npm run build --workspace=packages/sdk/typescript
  • npm run test --workspace=packages/local-mount
  • npm run build --workspace=packages/local-mount
  • npm run test --workspace=@relayfile/file-observer
  • scripts/check-contract-surface.sh
  • npm pack --workspace=packages/core --dry-run

I could not run local Go commands or the root npm run build end-to-end because go is not installed in this sandbox. I also did not print READY because the PR’s remote checks need to rerun after these local edits are applied.

@cubic-dev-ai cubic-dev-ai 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.

2 issues found across 3 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread packages/sdk/typescript/src/client.test.ts Outdated
Comment thread packages/core/src/webhooks.ts Outdated
@codeant-ai

codeant-ai Bot commented Jun 7, 2026

Copy link
Copy Markdown

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

@khaliqgant

Copy link
Copy Markdown
Member Author

Addressed the follow-up dependency alignment note in e52dfc0: @relayfile/sdk now depends on exact @relayfile/core@0.8.17, and the root lockfile no longer carries the stale nested SDK copy of @relayfile/core@0.8.16.

Validation after the dependency alignment:

  • npm run build --workspace=packages/sdk/typescript
  • npm run typecheck --workspace=packages/sdk/typescript
  • npm run test --workspace=packages/sdk/typescript
  • npm run test --workspace=packages/core
  • npm run build --workspace=packages/core
  • npm pack --workspace=packages/core --dry-run
  • scripts/check-contract-surface.sh
  • git diff --check

@codeant-ai

codeant-ai Bot commented Jun 7, 2026

Copy link
Copy Markdown

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

@khaliqgant

Copy link
Copy Markdown
Member Author

Addressed the two latest issues identified by cubic in c5a3f28:

  • waitForExpectation no longer depends on Date.now(), so tests that mock Date.now() cannot make the helper non-terminating.
  • The raw Slack channel alias path check is now centralized in parseRawSlackChannelAliasPath, avoiding duplicated path-structure validation between the early storage-scan guard and the alias canonicalizer.

Validation after this follow-up:

  • npm run test --workspace=packages/core -- webhooks.test.ts
  • npm run test --workspace=packages/sdk/typescript -- src/client.test.ts -t "computes fallback digests without exposing file content"
  • npm run test --workspace=packages/core
  • npm run build --workspace=packages/core
  • npm run test --workspace=packages/sdk/typescript
  • npm run typecheck --workspace=packages/sdk/typescript
  • npm run build --workspace=packages/sdk/typescript
  • npm pack --workspace=packages/core --dry-run
  • scripts/check-contract-surface.sh
  • git diff --check

@khaliqgant
khaliqgant merged commit bbc4d1b into main Jun 7, 2026
9 checks passed
@khaliqgant
khaliqgant deleted the fix/core-slack-envelope-canonicalization branch June 7, 2026 21:02
@agent-relay-code

Copy link
Copy Markdown
Contributor

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

Fixed the PR issue I found: packages/sdk/typescript/package.json now depends on @relayfile/core@0.8.17, matching the bumped core workspace version, and package-lock.json now resolves the SDK to the local workspace core instead of a nested registry copy.

Verified locally:

  • npm run test --workspace=packages/core
  • npm run test --workspace=packages/sdk/typescript
  • npm run build --workspace=packages/core
  • npm run typecheck --workspace=packages/sdk/typescript
  • scripts/check-contract-surface.sh
  • PATH=/tmp/go-toolchain/go/bin:$PATH npm test
  • PATH=/tmp/go-toolchain/go/bin:$PATH npm run build

I installed Go 1.22.12 temporarily under /tmp/go-toolchain because the sandbox had no go binary. I’m not printing READY because I cannot verify GitHub’s current required-check state or mergeability from this sandbox without gh/remote PR access.

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