Skip to content

Add Reddit Relayfile adapter package#132

Merged
khaliqgant merged 3 commits into
mainfrom
feat/reddit-relay-adapter
May 29, 2026
Merged

Add Reddit Relayfile adapter package#132
khaliqgant merged 3 commits into
mainfrom
feat/reddit-relay-adapter

Conversation

@miyaontherelay
Copy link
Copy Markdown
Contributor

Summary\n- add new package\n- implement layout prompt, resource manifest, path mapping, auxiliary emission, and digest handler\n- add digest tests for canonical/terminal-state and alias filtering\n\n## Validation\n-

@relayfile/adapter-core@0.3.24 build
rm -rf dist/tests/round-trip && tsc -p tsconfig.json\n-
@relayfile/adapter-reddit@0.1.0 typecheck
tsc --noEmit -p tsconfig.json\n-
@relayfile/adapter-reddit@0.1.0 test
node --import tsx --test 'src/**/*.test.ts'

✔ reddit digest summarizes canonical events and terminal states (1.404625ms)
✔ reddit digest ignores aliases and non-canonical helper files (0.08425ms)
ℹ tests 2
ℹ suites 0
ℹ pass 2
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 301.31225\n-

@relayfile/adapter-reddit@0.1.0 build
tsc\n-
relayfile-adapters@0.1.0 test:digest-contracts
node --test scripts/digest-layout-contracts.test.mjs && node scripts/digest-layout-contracts.mjs

✔ digest contract coverage rejects keyword-only comments without a live assertion (0.873375ms)
✔ digest contract coverage ignores skipped tests even when they contain assertions (0.050458ms)
✔ digest contract coverage accepts a live assertion test (0.077292ms)
✔ digest contract coverage ignores closing parens inside comments when slicing test blocks (0.069667ms)
✔ executable regression contracts require all evidence in one live assertion test (0.098958ms)
✔ digest contract coverage slices parenthesized test calls from the test token (0.066291ms)
ℹ tests 6
ℹ suites 0
ℹ pass 6
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 66.479
Verified adapter metadata/layout contracts do not require provider digest handlers.
Verified 11 category resource contracts.
Verified 5 activity-summary fallback contracts.
Verified 11 executable regression contracts.\n-

relayfile-adapters@0.1.0 test:writeback-discovery
node --test scripts/writeback-discovery-normalizer.test.mjs && node scripts/verify-writeback-discovery.mjs

✔ loads GitHub writeback operations from a local OpenAPI contract (1156.747834ms)
✔ loads OpenAPI YAML request schemas with refs, JSON media types, and examples (1.826875ms)
✔ loads JSON Schema contracts with descriptions, enum values, required fields, and examples (0.396208ms)
✔ normalizes endpoints with schemas loaded from integration contracts (5.519833ms)
✔ normalizes existing writeback discovery adapter endpoints without changing generated paths (0.200083ms)
✔ normalizes GitLab slugged nested writeback paths to runtime matchers (0.085125ms)
✔ attaches optional layoutManifest-style writeback metadata by static path segments (0.311875ms)
✔ does not match layout writeback resources with only a trailing dynamic segment in common (0.080166ms)
✔ does not match layout writeback resources with static segments in different positions (0.081542ms)
✔ normalizes adapter collections with layout manifests supplied as a provider map (0.478833ms)
✔ normalizes layout manifest paths to leading-slash paths (0.058292ms)
✔ fullRecordSchema marks provider-managed fields read-only (0.089083ms)
✔ escapeMarkdownTableCell escapes literal pipes inside regex cells (0.0415ms)
ℹ tests 13
ℹ suites 0
ℹ pass 13
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 1256.109375
Verified 82 writeback discovery endpoints.

@gemini-code-assist
Copy link
Copy Markdown

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 29, 2026

Review Change Stack

Warning

Review limit reached

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

More reviews will be available in 4 minutes and 58 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: ea645ee3-c207-4bca-a823-f255e2f00385

📥 Commits

Reviewing files that changed from the base of the PR and between 8ca81e1 and 93e3185.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (9)
  • packages/core/src/triggers/adapters-without-known-triggers.generated.json
  • packages/core/src/triggers/catalog.generated.ts
  • packages/reddit/src/emit-auxiliary-files.test.ts
  • packages/reddit/src/emit-auxiliary-files.ts
  • packages/reddit/src/index-emitter.test.ts
  • packages/reddit/src/index-emitter.ts
  • packages/reddit/src/layout-prompt.test.ts
  • packages/reddit/src/path-mapper.test.ts
  • packages/reddit/src/path-mapper.ts
📝 Walkthrough

Walkthrough

This PR adds a complete Reddit adapter (@relayfile/adapter-reddit) implementing record ingestion, change summarization, and index/auxiliary file emission. The package includes typed data models, path construction utilities, a digest change handler, index file builders, and a main auxiliary-file orchestrator that processes Reddit subreddit and post records into canonical and alias paths with deletion support.

Changes

Reddit Adapter Implementation

Layer / File(s) Summary
Type definitions and path contracts
packages/reddit/src/types.ts, packages/reddit/src/path-mapper.ts
RedditSubreddit and RedditPost interfaces with optional metadata; RedditSubredditIndexRow and RedditPostIndexRow for index entries. Path-mapper exports REDDIT_PATH_ROOT constant and RedditPathObjectType union for building Reddit document paths.
Path mapping and normalization
packages/reddit/src/path-mapper.ts
Functions to build layout, index, subreddit/post canonical paths, ID-based and status-based alias paths. Includes subreddit normalization, URL-safe title slug generation, scoped post ID parsing, and path computation from object type and ID.
Resource metadata and routing
packages/reddit/src/resources.ts
AdapterResourceConfig interface and resources array defining subreddit and post resource metadata (paths, patterns, schemas, examples). findResourceByPath() helper matches incoming paths to resource types.
Digest handler and change events
packages/reddit/src/digest.ts, packages/reddit/src/digest.test.ts
Reddit-specific digest handler via createDigestHandler configured with provider, canonical path matchers, identifier derivation from URL segments, action verb→past-tense rules. Tests verify canonical events are summarized correctly and non-canonical paths are filtered.
Index file generation
packages/reddit/src/index-emitter.ts
Builders for root, subreddit, post, and per-subreddit index JSON files. Record-to-row mappers compute index timestamps from source data, sort rows by updated date and ID, and conditionally include optional fields.
Auxiliary record emission orchestration
packages/reddit/src/emit-auxiliary-files.ts
Main emitRedditAuxiliaryFiles handler classifies records, writes static files, manages index reconcilers, and orchestrates batched emit planning. Handles subreddit and post upserts/deletes, generates stale deletes for status alias paths on post deletion, and accumulates write/error/delete results.
Package assembly and build configuration
packages/reddit/src/layout-prompt.ts, packages/reddit/src/index.ts, packages/reddit/package.json, packages/reddit/tsconfig.json
Layout prompt markdown defining expected mount structure. Barrel export aggregates all implementation modules and types. Package.json declares exports for root, ./layout-prompt, ./path-mapper, ./types subpaths, build/test scripts, and dependency relationships. TypeScript config specifies strict options, NodeNext module resolution, and dist output.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • AgentWorkforce/relayfile-adapters#93: Both PRs add new src/digest.ts implementations and barrel re-exports for different adapter providers using the same digest-handler factory pattern.
  • AgentWorkforce/relayfile-adapters#109: This PR's Reddit digest.ts builds handlers via createDigestHandler from adapter-core, matching the same digest-factory refactoring applied across other adapters.
  • AgentWorkforce/relayfile-adapters#78: This PR's emit-auxiliary-files.ts orchestrates shared runEmitBatch and IndexFileReconciler flows that were introduced for unified auxiliary-file emission across adapters.

Poem

🐰 A rabbit hops through Reddit's lands,
Building paths with nimble hands,
Digests change with clever sighs,
While posts and subreddits softly rise—
New adapter blooms, so neat and grand! 🌟

🚥 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 'Add Reddit Relayfile adapter package' clearly and accurately summarizes the main change—adding a complete new Reddit adapter package with multiple implementations.
Description check ✅ Passed The description is relevant to the changeset, covering the new package addition, core implementations (layout prompt, resource manifest, path mapping, auxiliary emission, digest handler), tests, and comprehensive validation results.
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 feat/reddit-relay-adapter

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

@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: 7

🧹 Nitpick comments (1)
packages/reddit/src/emit-auxiliary-files.ts (1)

167-192: ⚡ Quick win

Normalize subreddit consistently and move scoped-id parsing into the delete branch.

Two smaller issues:

  • parseRedditPostScopedId(record.id) runs for every record and throws if id isn't in subreddit/post_id form, yet the create branch doesn't use scoped. Move the call inside the isDeleted branch so non-scoped ids on the write path don't fail the batch.
  • The per-subreddit index map is keyed by record.subreddit (raw) on create but scoped.subreddit (normalized) on delete. Since both resolve to the same redditSubredditPostsIndexPath, mismatched casing creates two reconcilers writing the same path, so one flush overwrites the other's rows. Key the map by a normalized subreddit.
🤖 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/reddit/src/emit-auxiliary-files.ts` around lines 167 - 192, In
planPostRecord: stop calling parseRedditPostScopedId at the top — move
parseRedditPostScopedId(record.id) into the isDeleted branch so it only runs for
deletes; and ensure the subredditIndex map is keyed by a normalized subreddit in
both branches (replace subredditIndex(record.subreddit) with
subredditIndex(normalizedSubreddit)) — obtain normalizedSubreddit either from
scoped.subreddit inside the delete branch or by normalizing record.subreddit
(e.g., via the same normalization used by parseRedditPostScopedId) for the
create/upsert branch so both delete and upsert use the same normalized key.
🤖 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/reddit/src/digest.test.ts`:
- Around line 6-69: Add three unit tests under packages/reddit/src: (1) a
path-mapper round-trip that composes and then parses paths to assert equality
using computeRedditPath* helpers and parseRedditPostScopedId (e.g., build a
post/subreddit path with computeRedditPathPost/computeRedditPathSubreddit then
parse it back and assert ids match), (2) an alias-subtree collision test that
verifies events in both /reddit/posts/by-id/... and /reddit/posts/by-status/...
(and similarly /reddit/subreddits/by-id/... if applicable) are treated as
aliases and do not produce duplicate canonical bullets (simulate changeEvents
with colliding alias paths and assert digest output ignores duplicates), and (3)
a redditLayoutPromptFile emitter test that calls redditLayoutPromptFile() (or
the function that generates LAYOUT.md) and asserts the returned string is
non-empty, exceeds a minimal length, and contains a known substring from
REDDIT_LAYOUT_PROMPT; reference computeRedditPath*, parseRedditPostScopedId,
redditLayoutPromptFile, and REDDIT_LAYOUT_PROMPT when locating code to test.

In `@packages/reddit/src/emit-auxiliary-files.ts`:
- Around line 131-165: planSubredditRecord currently mixes two identifiers
(record.id and record.name) causing deletes to miss created rows; normalize the
subreddit slug once from record.name using normalizeSubreddit and use that slug
everywhere: compute const slug = normalizeSubreddit(record.name) at the top of
planSubredditRecord, call index.remove(slug) on deletes and use
redditSubredditPath(slug) / redditSubredditByIdAliasPath(slug) for staleDeletes;
for creates ensure the index row is keyed by that same slug (adjust
redditSubredditIndexRow call or replace its id with slug) and build
canonicalPath/aliases with slug so upsert and mirrorWrite use the identical
normalized identifier.
- Around line 174-188: The delete branch currently calls
redditPostPath(scoped.subreddit, scoped.postId) which doesn't match the created
canonical file that includes the title slug; fix by deleting the canonical file
by id-prefix instead: add a delete entry for the canonical pattern (e.g.
redditPostPath(scoped.subreddit, `*__${scoped.postId}`) or otherwise construct a
prefix/glob matching `<slug>__${scoped.postId}.json`) to the staleDeletes array
so the slugged canonical file is removed; if staleDeletes doesn't support
patterns, extend it to accept a prefix/glob or alternatively carry the title
through the RedditDeletedRecord so redditPostTitle(record) can be used when
calling redditPostPath. Ensure changes reference the isDeleted branch,
redditPostPath, redditPostByIdAliasPath, staleDeletes and RedditDeletedRecord.

In `@packages/reddit/src/index-emitter.ts`:
- Around line 57-64: The subreddit index uses a non-deterministic timestamp;
update redditSubredditIndexRow to set updated from record.created_utc when
available (convert the Unix/UTC seconds to an ISO string) and only fall back to
new Date().toISOString() if created_utc is absent, preserving the deterministic
behavior used for post rows; reference the redditSubredditIndexRow function and
the RedditSubreddit/RedditSubredditIndexRow types when making the change.
- Around line 22-31: Replace the string-concatenated root index path in
buildRedditRootIndexFile with the centralized path-mapper helper: add a
redditRootIndexPath() export to path-mapper.ts (returning
`${REDDIT_PATH_ROOT}/_index.json`) and then import and call
redditRootIndexPath() inside buildRedditRootIndexFile instead of using
`${'/reddit'}/_index.json`; ensure REDDIT_PATH_ROOT is used from the mapper so
all canonical Reddit paths flow through the mapper.

In `@packages/reddit/src/layout-prompt.ts`:
- Around line 12-15: Replace flat subreddit record paths with directory-record
style everywhere: change `/reddit/subreddits/<subreddit>.json` and
`/reddit/subreddits/by-id/<subreddit>.json` to
`/reddit/subreddits/<id>__<slug>/meta.json` and
`/reddit/subreddits/by-id/<id>__<slug>/meta.json` respectively, and update the
subpaths that reference the subreddit directory—e.g. change
`/reddit/subreddits/<subreddit>/posts/_index.json` to
`/reddit/subreddits/<id>__<slug>/posts/_index.json` and
`/reddit/subreddits/<subreddit>/posts/<title>__<postId>.json` to use the
subreddit directory id__slug prefix like
`/reddit/subreddits/<id>__<slug>/posts/<postId>__<slug>.json` so the layout
follows the directory-record rule (entities with sub-artifacts use
`<id>__<slug>/meta.json`).

In `@packages/reddit/src/path-mapper.ts`:
- Around line 26-36: Replace the local slugifier with the shared core helper: in
path-mapper, change the implementation of function slugify to call the
re-exported slugifyAlias (imported from core) instead of the hand-rolled logic,
then preserve existing consumers by mapping core’s empty-slug sentinel back to
the old sentinel: if slugifyAlias(...) returns 'untitled' return 'post'
(otherwise return slugifyAlias result). Update any places using slugify (e.g.,
redditPostPath) to keep using the same slugify symbol and keep
aliasCollisionSuffix usage intact so filename generation and collision handling
remain unchanged while adopting core’s truncation/normalization.

---

Nitpick comments:
In `@packages/reddit/src/emit-auxiliary-files.ts`:
- Around line 167-192: In planPostRecord: stop calling parseRedditPostScopedId
at the top — move parseRedditPostScopedId(record.id) into the isDeleted branch
so it only runs for deletes; and ensure the subredditIndex map is keyed by a
normalized subreddit in both branches (replace subredditIndex(record.subreddit)
with subredditIndex(normalizedSubreddit)) — obtain normalizedSubreddit either
from scoped.subreddit inside the delete branch or by normalizing
record.subreddit (e.g., via the same normalization used by
parseRedditPostScopedId) for the create/upsert branch so both delete and upsert
use the same normalized key.
🪄 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: 36d8e806-fcc9-4128-bdd0-42c74cff4170

📥 Commits

Reviewing files that changed from the base of the PR and between 52b0a11 and 8ca81e1.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (11)
  • packages/reddit/package.json
  • packages/reddit/src/digest.test.ts
  • packages/reddit/src/digest.ts
  • packages/reddit/src/emit-auxiliary-files.ts
  • packages/reddit/src/index-emitter.ts
  • packages/reddit/src/index.ts
  • packages/reddit/src/layout-prompt.ts
  • packages/reddit/src/path-mapper.ts
  • packages/reddit/src/resources.ts
  • packages/reddit/src/types.ts
  • packages/reddit/tsconfig.json

Comment on lines +6 to +69
test('reddit digest summarizes canonical events and terminal states', async () => {
const ctx: DigestContext = {
provider: 'reddit',
window: { from: '2026-05-29T00:00:00.000Z', to: '2026-05-30T00:00:00.000Z' },
async changeEvents(filter) {
assert.deepEqual(filter, { providers: ['reddit'] });
return [
{
id: 'evt-1',
timestamp: '2026-05-29T08:00:00.000Z',
action: 'created',
canonicalPath: '/reddit/subreddits/agentrelay.json',
},
{
id: 'evt-2',
timestamp: '2026-05-29T08:30:00.000Z',
action: 'archived',
canonicalPath: '/reddit/subreddits/agentrelay/posts/launch-week-recap__abc123.json',
},
];
},
};

const result = await digest(ctx);
assert.deepEqual(result, {
provider: 'reddit',
bullets: [
{
text: 'subreddit r/agentrelay was created',
canonicalPath: 'reddit/subreddits/agentrelay.json',
},
{
text: 'post r/agentrelay/launch-week-recap__abc123 was archived',
canonicalPath: 'reddit/subreddits/agentrelay/posts/launch-week-recap__abc123.json',
},
],
});
});

test('reddit digest ignores aliases and non-canonical helper files', async () => {
const ctx: DigestContext = {
provider: 'reddit',
window: { from: '2026-05-29T00:00:00.000Z', to: '2026-05-30T00:00:00.000Z' },
async changeEvents() {
return [
{ id: 'evt-1', timestamp: '2026-05-29T08:00:00.000Z', action: 'updated', canonicalPath: '/reddit/LAYOUT.md' },
{
id: 'evt-2',
timestamp: '2026-05-29T08:00:01.000Z',
action: 'updated',
canonicalPath: '/reddit/posts/by-id/agentrelay__abc123.json',
},
{
id: 'evt-3',
timestamp: '2026-05-29T08:00:02.000Z',
action: 'updated',
canonicalPath: '/reddit/posts/by-status/archived/agentrelay__abc123.json',
},
];
},
};

assert.equal(await digest(ctx), null);
});
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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Confirm whether path-mapper / layout-prompt / collision tests exist in the package.
fd -t f -e ts . packages/reddit/src | rg -n 'test'
rg -nP --type=ts 'aliasCollisionSuffix|collision|round.?trip|LAYOUT' packages/reddit 2>/dev/null

Repository: AgentWorkforce/relayfile-adapters

Length of output: 655


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# List all test files under packages/reddit
echo "== test files ==" 
find packages/reddit -type f \( -name "*.test.ts" -o -name "*.test.tsx" \) | sort

# Search for round-trip/collision/layout-prompt assertions inside reddit
echo "== keyword hits (roundtrip/collision/LAYOUT) ==" 
rg -n --hidden -S --type=ts '(round.?trip|aliasCollisionSuffix|collision|LAYOUT\.md|REDDIT_LAYOUT_PROMPT)' packages/reddit || true

# Search for path-mapper tests specifically
echo "== path-mapper hits ==" 
rg -n --hidden -S '(path-mapper|compose|parse|canonicalPath|by-id|by-status)' packages/reddit/src || true

Repository: AgentWorkforce/relayfile-adapters

Length of output: 4662


🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n --hidden -S 'LAYOUT\.md|REDDIT_LAYOUT_PROMPT|layout prompt' packages/reddit/src

Repository: AgentWorkforce/relayfile-adapters

Length of output: 618


🏁 Script executed:

#!/bin/bash
set -euo pipefail
# Show relevant sections of path-mapper.ts around compose/parse helpers and any LAYOUT path helper
sed -n '1,220p' packages/reddit/src/path-mapper.ts

echo "----"
# Show where LAYOUT.md content is assembled/emitted
rg -n --hidden -S 'LAYOUT\.md|REDDIT_LAYOUT_PROMPT|layoutPrompt|layout-prompt|REDDIT_LAYOUT_PROMPT' packages/reddit/src
echo "----"
# Inspect emit logic around REDDIT_LAYOUT_PROMPT usage
rg -n --hidden -S 'LAYOUT\.md' packages/reddit/src/emit-auxiliary-files.ts packages/reddit/src/index-emitter.ts packages/reddit/src/index.ts packages/reddit/src/*.ts || true

Repository: AgentWorkforce/relayfile-adapters

Length of output: 5116


🏁 Script executed:

#!/bin/bash
set -euo pipefail
# Show relevant sections of path-mapper.ts around compose/parse helpers and any LAYOUT path helper
sed -n '1,220p' packages/reddit/src/path-mapper.ts

echo "----"
# Locate where LAYOUT.md content is assembled/emitted
rg -n --hidden -S 'LAYOUT\.md|REDDIT_LAYOUT_PROMPT|layout-prompt' packages/reddit/src

echo "----"
# Inspect emitter(s) around LAYOUT.md emission
rg -n --hidden -S 'LAYOUT\.md' packages/reddit/src/emit-auxiliary-files.ts packages/reddit/src/index-emitter.ts packages/reddit/src/*.ts

Repository: AgentWorkforce/relayfile-adapters

Length of output: 5116


🏁 Script executed:

#!/bin/bash
set -euo pipefail
sed -n '1,140p' packages/reddit/src/layout-prompt.ts
rg -n --hidden -S 'redditLayoutPromptFile|LAYOUT\.md|REDDIT_LAYOUT_PROMPT' packages/reddit/src/emit-auxiliary-files.ts
sed -n '1,120p' packages/reddit/src/emit-auxiliary-files.ts

Repository: AgentWorkforce/relayfile-adapters

Length of output: 5479


🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n --hidden -S 'export function parse|function parse|parseReddit|parse.*Path|parse.*Alias' packages/reddit/src

Repository: AgentWorkforce/relayfile-adapters

Length of output: 502


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== aliasCollisionSuffix usage in reddit =="
rg -n --hidden -S 'aliasCollisionSuffix|collision suffix|collision' packages/reddit/src || true

echo "== other compose/parse helpers (beyond path-mapper parseScopedPostId) =="
rg -n --hidden -S 'computeRedditPathFromModel|computeRedditPath\(|parseReddit|parse.*Path|scopedId|subreddit\/|post_id' packages/reddit/src || true

Repository: AgentWorkforce/relayfile-adapters

Length of output: 466


Add missing required test categories for reddit adapter helpers

packages/reddit/src/digest.test.ts covers digest behavior, but packages/reddit/src contains no other tests (so the mandated coverage is missing):

  • Add path-mapper round-trip tests (compose → parse → equality) targeting computeRedditPath* / parseRedditPostScopedId.
  • Add an alias-subtree collision test for both /reddit/posts/by-id/... and /reddit/posts/by-status/... (and /reddit/subreddits/by-id/... if treated as an alias subtree).
  • Add a non-empty LAYOUT.md emitter test for redditLayoutPromptFile() (length + key substring assertions from REDDIT_LAYOUT_PROMPT).
🤖 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/reddit/src/digest.test.ts` around lines 6 - 69, Add three unit tests
under packages/reddit/src: (1) a path-mapper round-trip that composes and then
parses paths to assert equality using computeRedditPath* helpers and
parseRedditPostScopedId (e.g., build a post/subreddit path with
computeRedditPathPost/computeRedditPathSubreddit then parse it back and assert
ids match), (2) an alias-subtree collision test that verifies events in both
/reddit/posts/by-id/... and /reddit/posts/by-status/... (and similarly
/reddit/subreddits/by-id/... if applicable) are treated as aliases and do not
produce duplicate canonical bullets (simulate changeEvents with colliding alias
paths and assert digest output ignores duplicates), and (3) a
redditLayoutPromptFile emitter test that calls redditLayoutPromptFile() (or the
function that generates LAYOUT.md) and asserts the returned string is non-empty,
exceeds a minimal length, and contains a known substring from
REDDIT_LAYOUT_PROMPT; reference computeRedditPath*, parseRedditPostScopedId,
redditLayoutPromptFile, and REDDIT_LAYOUT_PROMPT when locating code to test.

Comment thread packages/reddit/src/emit-auxiliary-files.ts
Comment thread packages/reddit/src/emit-auxiliary-files.ts
Comment thread packages/reddit/src/index-emitter.ts
Comment thread packages/reddit/src/index-emitter.ts
Comment on lines +12 to +15
- \`/reddit/subreddits/<subreddit>.json\`
- \`/reddit/subreddits/by-id/<subreddit>.json\`
- \`/reddit/subreddits/<subreddit>/posts/_index.json\`
- \`/reddit/subreddits/<subreddit>/posts/<title>__<postId>.json\`
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

Canonical subreddit path shape is inconsistent with directory-record rules.

Line 12 documents a flat record (<subreddit>.json) while Line 14 shows the same entity as a parent directory for sub-artifacts. For entities with sub-artifacts, the canonical form should be directory-record style (<id>__<slug>/meta.json) in the layout contract to avoid downstream path drift.

As per coding guidelines, "Directory records (entities WITH sub-artifacts) must use <id>__<slug>/meta.json."

🤖 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/reddit/src/layout-prompt.ts` around lines 12 - 15, Replace flat
subreddit record paths with directory-record style everywhere: change
`/reddit/subreddits/<subreddit>.json` and
`/reddit/subreddits/by-id/<subreddit>.json` to
`/reddit/subreddits/<id>__<slug>/meta.json` and
`/reddit/subreddits/by-id/<id>__<slug>/meta.json` respectively, and update the
subpaths that reference the subreddit directory—e.g. change
`/reddit/subreddits/<subreddit>/posts/_index.json` to
`/reddit/subreddits/<id>__<slug>/posts/_index.json` and
`/reddit/subreddits/<subreddit>/posts/<title>__<postId>.json` to use the
subreddit directory id__slug prefix like
`/reddit/subreddits/<id>__<slug>/posts/<postId>__<slug>.json` so the layout
follows the directory-record rule (entities with sub-artifacts use
`<id>__<slug>/meta.json`).

Comment on lines +26 to +36
function slugify(value: string): string {
const ascii = value
.normalize('NFKD')
.replace(/[\u0300-\u036f]/g, '')
.replace(/[^\x00-\x7F]+/g, '');
const slug = ascii
.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-+|-+$/g, '');
return slug || 'post';
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Confirm the shared slug helpers exist and how they're exported for adapters.
rg -nP --type=ts '\b(slugifyAlias|aliasCollisionSuffix)\b' -C2
fd -t f 'alias-slug.ts'
# Check whether adapter-core re-exports them
fd -t f 'index.ts' packages/core/src | xargs rg -nP 'alias-slug|slugifyAlias' 2>/dev/null

Repository: AgentWorkforce/relayfile-adapters

Length of output: 47266


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the reddit path-mapper around the reported lines
if [ -f "packages/reddit/src/path-mapper.ts" ]; then
  nl -ba packages/reddit/src/path-mapper.ts | sed -n '1,120p'
  echo "---- tail around 20-60 ----"
  nl -ba packages/reddit/src/path-mapper.ts | sed -n '20,60p'
else
  echo "MISSING: packages/reddit/src/path-mapper.ts"
  exit 1
fi

# Check whether reddit has a shared alias-slug wrapper and how it's exported
echo "---- reddit alias-slug.ts ----"
if [ -f "packages/reddit/src/alias-slug.ts" ]; then
  nl -ba packages/reddit/src/alias-slug.ts | sed -n '1,160p'
else
  echo "MISSING: packages/reddit/src/alias-slug.ts"
fi

# Check core exports for the helpers
echo "---- core/src/alias-slug.ts exports ----"
nl -ba packages/core/src/alias-slug.ts | sed -n '1,120p'
echo "---- core/src/index.ts re-exports ----"
nl -ba packages/core/src/index.ts | sed -n '1,80p'

# Find any local slugify/alias slug logic inside reddit path-mapper
echo "---- search for slugify functions in reddit ----"
rg -nP "function\s+slugify\s*\(|slugifyAlias|aliasCollisionSuffix" packages/reddit/src -S

Repository: AgentWorkforce/relayfile-adapters

Length of output: 120


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect reddit path-mapper around the reported lines
if [ -f "packages/reddit/src/path-mapper.ts" ]; then
  echo "---- reddit/src/path-mapper.ts (lines 1-140) ----"
  cat -n packages/reddit/src/path-mapper.ts | sed -n '1,140p'
else
  echo "MISSING: packages/reddit/src/path-mapper.ts"
  exit 1
fi

# Check whether reddit has an alias-slug wrapper and how it's exported
echo "---- reddit/src/alias-slug.ts ----"
if [ -f "packages/reddit/src/alias-slug.ts" ]; then
  cat -n packages/reddit/src/alias-slug.ts | sed -n '1,200p'
else
  echo "MISSING: packages/reddit/src/alias-slug.ts"
fi

# Check core exports for the helpers
echo "---- core/src/alias-slug.ts ----"
cat -n packages/core/src/alias-slug.ts | sed -n '1,120p'

echo "---- core/src/index.ts (exports) ----"
cat -n packages/core/src/index.ts | sed -n '1,80p'

# Find any local slugify functions inside reddit
echo "---- search for slugify usage in reddit/src ----"
rg -nP "function\s+slugify\s*\(" packages/reddit/src || true
echo "---- search for slugifyAlias/aliasCollisionSuffix imports/usage in reddit/src ----"
rg -nP "(slugifyAlias|aliasCollisionSuffix)" packages/reddit/src || true

Repository: AgentWorkforce/relayfile-adapters

Length of output: 7659


Replace the hand-rolled slugify in packages/reddit/src/path-mapper.ts with shared slugifyAlias (and preserve back-compat).

packages/reddit/src/path-mapper.ts defines its own function slugify(...) (26-36) and uses it in redditPostPath to build the {slug}__{postId} filename segment. Core already provides the shared slugifyAlias/aliasCollisionSuffix helpers (via packages/core/src/alias-slug.ts, re-exported from packages/core/src/index.ts), and the adapter should use slugifyAlias instead of rolling a local slugifier. Switching will change output behavior (including the empty-slug sentinel: 'post''untitled') and apply core’s truncation; add additive/deprecated helper output or reader-side back-compat so existing consumers don’t 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 `@packages/reddit/src/path-mapper.ts` around lines 26 - 36, Replace the local
slugifier with the shared core helper: in path-mapper, change the implementation
of function slugify to call the re-exported slugifyAlias (imported from core)
instead of the hand-rolled logic, then preserve existing consumers by mapping
core’s empty-slug sentinel back to the old sentinel: if slugifyAlias(...)
returns 'untitled' return 'post' (otherwise return slugifyAlias result). Update
any places using slugify (e.g., redditPostPath) to keep using the same slugify
symbol and keep aliasCollisionSuffix usage intact so filename generation and
collision handling remain unchanged while adopting core’s
truncation/normalization.

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.

3 issues found across 12 files

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

Re-trigger cubic

Comment thread packages/reddit/src/path-mapper.ts Outdated
Comment thread packages/reddit/src/index-emitter.ts Outdated
Comment thread packages/reddit/src/emit-auxiliary-files.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.

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

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

Re-trigger cubic

Comment thread packages/reddit/src/emit-auxiliary-files.ts Outdated
Comment thread packages/reddit/src/index-emitter.ts Outdated
@khaliqgant khaliqgant merged commit c5f6e75 into main May 29, 2026
3 checks passed
@khaliqgant khaliqgant deleted the feat/reddit-relay-adapter branch May 29, 2026 11:37
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