feat: publish Relayfile ingest identity contracts - #254
Conversation
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
|
Warning Review limit reached
Next review available in: 36 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
📝 WalkthroughWalkthroughThis PR adds a shared inbound capability contract, provider declarations, catalog generation and validation commands, deterministic logical event key computation, golden vectors, and Gmail canonical identity migration support. ChangesInbound capability platform
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant Adapter
participant Catalog
participant KeyResolver
Adapter->>Catalog: publish inboundCapabilities
Catalog->>Catalog: normalize and validate declarations
Catalog-->>KeyResolver: provide catalog and catalogVersion
KeyResolver->>KeyResolver: resolve capability and compute logicalEventKey
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c2ed055d8e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/gmail/src/path-mapper.ts (1)
54-65: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
parseRelayfilePathdoesn't recognize the legacy/google-mailroot.
RELAYFILE_ROOT(line 61 check) only reflects the canonicalGMAIL_PATH_ROOT, so paths under the legacy root (/google-mail/...) fall through toresource: 'unknown'instead of'object'. This contradicts the migration policy declared inidentity.ts(legacyReads: 'supported') and is inconsistent withdigest.ts, which was just updated to match againstGMAIL_PATH_ROOTS(canonical + legacy) for the same migration.🐛 Proposed fix
-import { GMAIL_PATH_ROOT, GMAIL_PROVIDER_ID } from "./identity.js"; +import { GMAIL_PATH_ROOTS, GMAIL_PROVIDER_ID } from "./identity.js"; -export const RELAYFILE_ROOT = GMAIL_PATH_ROOT; +export const RELAYFILE_ROOT = GMAIL_PATH_ROOTS[0]; @@ - if (segments[0] === RELAYFILE_ROOT.slice(1)) { + if (GMAIL_PATH_ROOTS.some((root) => segments[0] === root.slice(1))) { return { resource: 'object', id: segments.at(-1) ?? null, segments }; }🤖 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 `@packages/gmail/src/path-mapper.ts` around lines 54 - 65, Update parseRelayfilePath to recognize both canonical and legacy object roots by matching the first segment against the existing GMAIL_PATH_ROOTS collection, rather than only RELAYFILE_ROOT. Preserve the current lifecycle matching and unknown-path behavior, and return resource: 'object' with the existing ID and segments for either supported root.
🧹 Nitpick comments (3)
packages/gmail/src/path-mapper.ts (3)
4-5: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse
RELAYFILE_ROOTinstead of re-hardcoding"/gmail".
RELAYFILE_ROOTwas just introduced fromGMAIL_PATH_ROOTon line 3 specifically to centralize the root, butOBJECT_RESOURCE_PATH/LIFECYCLE_RESOURCE_PATHstill hardcode the literal"/gmail". If the canonical root ever changes, these constants will silently drift out of sync.♻️ Proposed fix
export const RELAYFILE_ROOT = GMAIL_PATH_ROOT; -export const OBJECT_RESOURCE_PATH = "/gmail/{account}/threads"; -export const LIFECYCLE_RESOURCE_PATH = "/gmail/watches"; +export const OBJECT_RESOURCE_PATH = `${RELAYFILE_ROOT}/{account}/threads`; +export const LIFECYCLE_RESOURCE_PATH = `${RELAYFILE_ROOT}/watches`;🤖 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 `@packages/gmail/src/path-mapper.ts` around lines 4 - 5, Update OBJECT_RESOURCE_PATH and LIFECYCLE_RESOURCE_PATH to build their paths from the existing RELAYFILE_ROOT constant instead of hardcoding "/gmail", while preserving the current account and watches suffixes.
41-41: 🗄️ Data Integrity & Integration | 🔵 Trivial | 🏗️ Heavy liftCanonical thread filename omits the required slug segment.
Per the repo's canonical record contract, flat records must be named
<slug>__<id>.json, but this builds the thread path as justencodePathSegment(input.threadId ?? id) + '.json'— no slug component. Please confirm whether Gmail threads are intentionally excepted from the slug requirement, or whether this needs aslugifyAlias-derived prefix.As per coding guidelines, "Canonical record names must use
<slug>__<id>: flat records are<slug>__<id>.json... Slugs must be ASCII, lowercase, hyphen-separated, truncated to 80 characters at a word boundary, and produced throughslugifyAlias".🤖 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 `@packages/gmail/src/path-mapper.ts` at line 41, Update the Gmail case in the path-mapping logic to construct the thread filename as the canonical `<slug>__<id>.json` form, deriving the slug through `slugifyAlias` and applying its standard ASCII, lowercase, hyphenated, truncated behavior. Preserve the existing account path and thread ID selection while ensuring the slug prefix is included before the encoded ID.Source: Coding guidelines
32-48: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDead switch branches for unrelated providers, all hardcoding
"/gmail".
PROVIDER_SLUGis derived fromGMAIL_PROVIDER_IDand is always"gmail"in this package, yet the switch carries cases forgoogle-drive,gcs,sharepoint,onedrive,azure-blob,dropbox,s3,box,postgres, andredis— none reachable, and each one still hardcodes the"/gmail"prefix regardless of its own case label. BecausePROVIDER_SLUGis typed as plainstring(line 6) rather than the literal type ofGMAIL_PROVIDER_ID, TypeScript can't flag these as unreachable. This looks like leftover boilerplate from a shared template; collapsing it to the single relevant case would remove confusing dead code.🤖 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 `@packages/gmail/src/path-mapper.ts` around lines 32 - 48, The toObjectRelayfilePath switch contains unreachable provider branches and hardcodes the Gmail prefix for unrelated providers. Since PROVIDER_SLUG is always Gmail, collapse the switch to the single Gmail path construction, preserving its current account, threadId, identifier fallbacks, encoding, and “.json” suffix.
🤖 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 `@packages/core/src/inbound/catalog-generator.ts`:
- Around line 74-79: Extend validateCatalog to enforce a one-to-one relationship
between providerId and pathRoot across all capability declarations: capabilities
sharing a providerId must use the same pathRoot, and distinct providerIds must
not reuse one. Ensure validation runs before catalog generation and reports
conflicting declarations. Update generateInboundCapabilityCatalog to use the
validated consistent providerId rather than assuming
declarations[0]!.providerId.
---
Outside diff comments:
In `@packages/gmail/src/path-mapper.ts`:
- Around line 54-65: Update parseRelayfilePath to recognize both canonical and
legacy object roots by matching the first segment against the existing
GMAIL_PATH_ROOTS collection, rather than only RELAYFILE_ROOT. Preserve the
current lifecycle matching and unknown-path behavior, and return resource:
'object' with the existing ID and segments for either supported root.
---
Nitpick comments:
In `@packages/gmail/src/path-mapper.ts`:
- Around line 4-5: Update OBJECT_RESOURCE_PATH and LIFECYCLE_RESOURCE_PATH to
build their paths from the existing RELAYFILE_ROOT constant instead of
hardcoding "/gmail", while preserving the current account and watches suffixes.
- Line 41: Update the Gmail case in the path-mapping logic to construct the
thread filename as the canonical `<slug>__<id>.json` form, deriving the slug
through `slugifyAlias` and applying its standard ASCII, lowercase, hyphenated,
truncated behavior. Preserve the existing account path and thread ID selection
while ensuring the slug prefix is included before the encoded ID.
- Around line 32-48: The toObjectRelayfilePath switch contains unreachable
provider branches and hardcodes the Gmail prefix for unrelated providers. Since
PROVIDER_SLUG is always Gmail, collapse the switch to the single Gmail path
construction, preserving its current account, threadId, identifier fallbacks,
encoding, and “.json” suffix.
🪄 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: 4cd4c106-3bd4-4d55-83c1-f327673d737d
⛔ Files ignored due to path filters (2)
packages/core/src/inbound/catalog.generated.jsonis excluded by!**/*.generated.*packages/core/src/inbound/catalog.generated.tsis excluded by!**/*.generated.*
📒 Files selected for processing (41)
AGENTS.mdCHANGELOG.mddocs/inbound-capability-contract.mdpackages/core/package.jsonpackages/core/src/cli.tspackages/core/src/inbound/catalog-generator.tspackages/core/src/inbound/golden-vectors.tspackages/core/src/inbound/index.tspackages/core/src/inbound/logical-event-key.test.tspackages/core/src/inbound/logical-event-key.tspackages/core/src/inbound/types.tspackages/core/src/index.tspackages/core/tests/inbound/catalog-generator.test.tspackages/core/tsconfig.jsonpackages/github/package.jsonpackages/github/src/inbound.tspackages/github/src/index.tspackages/gitlab/package.jsonpackages/gitlab/src/inbound.tspackages/gitlab/src/index.tspackages/gmail/package.jsonpackages/gmail/src/config.tspackages/gmail/src/digest.test.tspackages/gmail/src/digest.tspackages/gmail/src/identity.test.tspackages/gmail/src/identity.tspackages/gmail/src/inbound.tspackages/gmail/src/index.tspackages/gmail/src/path-mapper.tspackages/hubspot/package.jsonpackages/hubspot/src/inbound.tspackages/hubspot/src/index.tspackages/linear/package.jsonpackages/linear/src/inbound.tspackages/linear/src/index.tspackages/notion/package.jsonpackages/notion/src/inbound.tspackages/notion/src/index.tspackages/slack/package.jsonpackages/slack/src/inbound.tspackages/slack/src/index.ts
|
CodeRabbit outside-diff/nit triage for head
Targeted exact-worktree validation before push: core build + 181/181 core tests + inbound catalog check; Gmail build/typecheck + 16/16 tests. |
|
Follow-up proof on exact head |
Outcome
Publishes the two adapter-owned contracts blocking the Relayfile ingest cut:
logicalEventKey, including GitLab Hookdeck, with cross-runtime golden vectors.No Cloud or relayfile-cloud code is changed. Consumers must wait for the adapter release and import these exports directly.
Gmail identity
gmail/gmailgmail,google-mail,google-mail-relaygoogle-mail,/google-mail/google-mailonly after zero-reference reconciliation and an explicit cutover.Inbound catalog and logical key
src/inbound.ts; adapter-core generates a normalized, version-hashed catalog rather than maintaining a static package map.INBOUND_CAPABILITY_CATALOG,INBOUND_CAPABILITY_CATALOG_VERSION,resolveInboundCapability,logicalEventKey, and exact golden vectors.eventIdfields are not implicitly promoted to transport identity.x-gitlab-event-uuid, thenx-hookdeck-eventid.RED-first evidence
/google-maildigest events were rejected.eventIdwas incorrectly selected as delivery identity before the header-only fix.Validation
npx turbo build typecheck test— 147/147 tasks successful.@relayfile/adapter-core— 178/178 tests.@relayfile/adapter-github— 377/377 tests.npm run catalog:check --workspace @relayfile/adapter-core— 8 capabilities, catalog versionsha256:edcb9170384faeebebe1a4c535552d6c6e2e96c69df68373d588322080fd96b0.npm pack --dry-run— adapter-core, Gmail, and GitLab package surfaces verified.git diff --check— clean.Release and downstream gates
Package versions are intentionally unchanged in this feature PR.
After approval and merge,
@lead/ khaliq must gate:core,github,gitlab,gmail,hubspot,linear,notion, andslack.Do not merge, publish, deploy, or update downstream pins from this PR without that gate.
Explicitly deferred P0s