Skip to content

Fix dev seeding failures and surface seed errors#993

Open
adrmac wants to merge 1 commit intomainfrom
adrian/fix-seeding
Open

Fix dev seeding failures and surface seed errors#993
adrmac wants to merge 1 commit intomainfrom
adrian/fix-seeding

Conversation

@adrmac
Copy link
Copy Markdown
Member

@adrmac adrmac commented Feb 18, 2026

Summary

This fixes two seed data issues:

  1. no seed populating even though using /seed in the UI appeared successful ('Data seeded' message)
  2. actual backend error:
    NoSuchInput / Required field :maintainer_emails during Orcasite.Radio.Seed.feeds

Root cause

Feed seeding failing due to input mismatches (Codex diagnosis and fix):

  • maintainer_emails was present in seed payloads but not accepted by Feed.create.
  • Some prod feeds return maintainerEmails: null, which conflicted with local non-null constraints.
  • seed_all/startup flows could proceed after feed-seed failure and produce misleading success/empty results.

Changes

feed.ex

  • Allow :maintainer_emails in create :create.
  • Include :maintainer_emails in upsert_fields.

utils.ex

  • Skip incoming nil values for attributes with allow_nil?: false during seed payload conversion.

seed.ex

  • Make time_range and latest fail early if feed seeding fails or yields zero feeds.

seeds.exs

  • Use bang variants (time_range!, latest!) so setup seeding fails loudly instead of silently continuing.

seed.tsx

  • Improve mutation error handling so backend seed failures are shown.
  • Avoid misleading “Seeded …” message when zero records are seeded.
  • Make /seed route available in local dev by fallback detection when explicit seed flag is unset.

Validation

  • mix compile (server) passes.
  • npm run build:dev (ui) passes.
  • Direct seed invocation now succeeds:
    • Orcasite.Radio.Seed.time_range(...) returns {:ok, ...} with seeded records.

Notes

  • Dev setup still requires both processes running:
    • Phoenix on (line 4000)
    • Next.js on (line 3000) (otherwise /seed via (line 4000) returns proxy 502 econnrefused).

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 18, 2026

📝 Walkthrough

Walkthrough

Adds a maintainer_emails field to the Feed resource, refactors the seeding flow with a helper function to ensure feeds exist before processing, introduces attribute validation logic to enforce nil-checking, switches seed helpers to bang variants for stricter error handling, and enhances the UI seed page with centralized mutation error handling and environment-aware visibility controls.

Changes

Cohort / File(s) Summary
Feed Schema & Core Seeding Infrastructure
server/lib/orcasite/radio/feed.ex, server/lib/orcasite/radio/seed.ex, server/lib/orcasite/radio/seed/utils.ex
Adds maintainer_emails field to Feed; refactors seeding flow to introduce seed_and_load_feeds helper with guard pattern ensuring feeds exist; adds include_attribute_input? function for attribute validation with nil-checking enforcement.
Seed Script Updates
server/priv/repo/seeds.exs
Switches seed helpers from non-bang to bang variants (time_range!/1, latest!/0), changing error handling from tuples to exceptions.
UI Seed Page Enhancements
ui/src/pages/seed.tsx
Introduces centralized mutation error handler, adds result count reporting for seedAllMutation, implements environment-aware seed page visibility via conditional enableSeedFromProd logic.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Suggested reviewers

  • paulcretu
  • dthaler

Poem

🐰 Whiskers twitch with seeded glee,
Emails stored, guards now decree,
Attributes nil when they should be,
Bang! Bang! Errors raised, you'll see,
Seeds and feeds now dance with care! 📧✨

🚥 Pre-merge checks | ✅ 2 | ❌ 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 (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely summarizes the main changes: fixing seed data population failures and improving error visibility in the UI.

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

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch adrian/fix-seeding

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


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.

@paulcretu paulcretu temporarily deployed to orcasite-pr-993 February 18, 2026 17:32 Inactive
Copy link
Copy Markdown
Contributor

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ui/src/pages/seed.tsx (1)

121-121: ⚠️ Potential issue | 🟡 Minor

Remove console.log debug artifact.

This log fires on every resource count during seedAll responses and will appear in production browser consoles whenever seeding is enabled.

🔧 Proposed fix
-          console.log(resource, count);
-          return `${count} ${lowerCaseResource(resource)}${count === 1 ? "" : "s"}`;
+          return `${count} ${lowerCaseResource(resource)}${count === 1 ? "" : "s"}`;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ui/src/pages/seed.tsx` at line 121, Remove the debug console.log so it
doesn't spam production: find the console.log(resource, count) call in the
seedAll flow in ui/src/pages/seed.tsx (the line that logs resource and count
during seeding) and delete it (or replace it with a debug-only or
environment-gated logger if you need retained visibility), ensuring no other
logic depends on that expression.
🧹 Nitpick comments (2)
server/lib/orcasite/radio/seed/utils.ex (1)

14-16: Optional: consolidate the two Ash.Resource.Info.attribute lookups into one.

writable_attr? and include_attribute_input? each independently call Ash.Resource.Info.attribute(resource, key). Combining them into a single lookup per key avoids the redundancy.

♻️ Proposed refactor

Replace the two helpers at the call site with a single guard clause:

-        writable_attr?(resource, attr) and include_attribute_input?(resource, attr, val) ->
+        match?(%{writable?: true}, Ash.Resource.Info.attribute(resource, attr)) and
+          (match?(%{allow_nil?: true}, Ash.Resource.Info.attribute(resource, attr)) or
+             not is_nil(val)) ->

Or, more readably, add a combined helper:

def writable_and_includable?(resource, key, value) do
  case Ash.Resource.Info.attribute(resource, key) do
    %{writable?: true, allow_nil?: false} when is_nil(value) -> false
    %{writable?: true} -> true
    _ -> false
  end
end

and call it as:

-        writable_attr?(resource, attr) and include_attribute_input?(resource, attr, val) ->
+        writable_and_includable?(resource, attr, val) ->
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/lib/orcasite/radio/seed/utils.ex` around lines 14 - 16, Consolidate
the duplicate Ash.Resource.Info.attribute(resource, key) lookups by introducing
a combined predicate (e.g., writable_and_includable?/3) that does a single
attribute fetch and returns true only when the attribute exists, is writable,
and passes the include/allow_nil checks currently performed by writable_attr?
and include_attribute_input?; then replace the cond clause that calls both
writable_attr?(resource, attr) and include_attribute_input?(resource, attr, val)
with a single call to writable_and_includable?(resource, attr, val) and remove
the redundant per-call attribute lookups in
writable_attr?/include_attribute_input? where appropriate (or forward them to
the new helper).
server/lib/orcasite/radio/seed.ex (1)

64-81: resource! exceptions escape the with block — consider error-tolerant accumulation per feed.

with only pattern-matches return values; it does not rescue exceptions. If __MODULE__.resource!/1 raises for a single {feed, resource} pair, the exception propagates through Stream.map |> Enum.to_list(), discarding all previously accumulated results and returning an opaque runtime error to the GraphQL caller instead of a structured {:error, ...} tuple.

For seeds.exs this is acceptable (fail loud). For the seedAll GraphQL mutation, a single failing feed's resource aborts the entire operation without indicating which feed/resource failed or returning partial results.

♻️ Proposed refactor — error-tolerant accumulation
       seed_params
-      |> Stream.map(fn {feed, resource} ->
-        __MODULE__.resource!(%{
-          resource: resource,
-          start_time: start_time,
-          end_time: end_time,
-          feed_id: feed.id
-        })
-      end)
-      |> Enum.to_list()
-      |> then(&{:ok, &1})
+      |> Enum.flat_map(fn {feed, resource} ->
+        case __MODULE__.resource(%{
+               resource: resource,
+               start_time: start_time,
+               end_time: end_time,
+               feed_id: feed.id
+             }) do
+          {:ok, results} ->
+            results
+
+          {:error, error} ->
+            require Logger
+            Logger.warning("Failed to seed #{resource} for feed #{feed.id}: #{inspect(error)}")
+            []
+        end
+      end)
+      |> then(&{:ok, &1})

The same pattern applies to latest (lines 91–107) with latest_resource.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/lib/orcasite/radio/seed.ex` around lines 64 - 81, The current
implementation calls __MODULE__.resource!/1 inside Stream.map/Enum.to_list which
lets exceptions escape the with block; wrap calls to resource!/1 (and similarly
latest_resource) in a safe wrapper that rescues exceptions and returns a tagged
result (e.g. {:ok, result} or {:error, {feed, resource, reason}}) so a single
failure does not crash the whole operation, then partition or reduce the
collected results into a final {:ok, results} with partial successes and a
structured list of errors (or {:error, errors} if you prefer) before returning
from the with; reference the seed_and_load_feeds call and the mapping that
currently invokes __MODULE__.resource!/1 (and the latest -> latest_resource
invocation) to locate where to add the try/rescue wrapper and aggregation logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@ui/src/pages/seed.tsx`:
- Line 121: Remove the debug console.log so it doesn't spam production: find the
console.log(resource, count) call in the seedAll flow in ui/src/pages/seed.tsx
(the line that logs resource and count during seeding) and delete it (or replace
it with a debug-only or environment-gated logger if you need retained
visibility), ensuring no other logic depends on that expression.

---

Nitpick comments:
In `@server/lib/orcasite/radio/seed.ex`:
- Around line 64-81: The current implementation calls __MODULE__.resource!/1
inside Stream.map/Enum.to_list which lets exceptions escape the with block; wrap
calls to resource!/1 (and similarly latest_resource) in a safe wrapper that
rescues exceptions and returns a tagged result (e.g. {:ok, result} or {:error,
{feed, resource, reason}}) so a single failure does not crash the whole
operation, then partition or reduce the collected results into a final {:ok,
results} with partial successes and a structured list of errors (or {:error,
errors} if you prefer) before returning from the with; reference the
seed_and_load_feeds call and the mapping that currently invokes
__MODULE__.resource!/1 (and the latest -> latest_resource invocation) to locate
where to add the try/rescue wrapper and aggregation logic.

In `@server/lib/orcasite/radio/seed/utils.ex`:
- Around line 14-16: Consolidate the duplicate
Ash.Resource.Info.attribute(resource, key) lookups by introducing a combined
predicate (e.g., writable_and_includable?/3) that does a single attribute fetch
and returns true only when the attribute exists, is writable, and passes the
include/allow_nil checks currently performed by writable_attr? and
include_attribute_input?; then replace the cond clause that calls both
writable_attr?(resource, attr) and include_attribute_input?(resource, attr, val)
with a single call to writable_and_includable?(resource, attr, val) and remove
the redundant per-call attribute lookups in
writable_attr?/include_attribute_input? where appropriate (or forward them to
the new helper).

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