Add Renure Support for 2026 Norms and Fertilizer Planning - #712
Conversation
…e as 4th norm and provide value and filling functions. For 2025 do not return Renure norm and count as manure for filling.
…BAAT fertilizer catalogue: Ammoniumsulfaat, Ammoniumnitraat, Mineralenconcentraat and Ammoniumstruviet. Also two non-Renure variants of Ammoniumstruviet and Kaliumstruviet are added. For mestcode 134 no default product has been added to the catalogue as it is a generic "other" category.
…run on app startup) now automatically acquires a newly introduced fertilizer catalogue product for every existing farm that already has that catalogue source enabled, mirroring the bulk-acquisition that happens when a new farm is created
|
Warning Review limit reached
Next review available in: 51 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: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughRenure support is added across fertilizer catalogues, 2025/2026 norm calculations, fertilizer planning, Gerrit agent contracts, synchronization, and application displays. RVO codes 130–134 are propagated through data flows, with 2026-specific norms and ChangesRenure calculation and catalogue support
Planning and application integration
Estimated code review effort: 5 (Critical) | ~120 minutes Possibly related PRs
Suggested labels: Suggested reviewers: 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 |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (2)
fdm-app/app/components/blocks/timeline/timeline-colors.ts (1)
13-24: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAlign the helper parameter with
FertilizerKind.
FertilizerKindand the runtime fallback both support"other", butgetFertilizerKindColorrejects it at compile time. AcceptFertilizerKind | null | undefined(or remove"other"from the exported union) to avoid caller-side casts.🤖 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 `@fdm-app/app/components/blocks/timeline/timeline-colors.ts` around lines 13 - 24, Update the getFertilizerKindColor parameter type to use FertilizerKind | null | undefined, ensuring it accepts the existing "other" value while preserving the current null/undefined fallback behavior and FERTILIZER_KIND_COLOR mapping.fdm-app/app/lib/gerrit.server.ts (1)
183-185: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winKeep the Renure filling call type-safe.
Line 184 uses
as any, so TypeScript cannot verify that the 2026 factory exposes this method or that it returnsNormFilling; a contract drift would become a runtime failure. Expose the 2026 method through a typed factory branch instead.🤖 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 `@fdm-app/app/lib/gerrit.server.ts` around lines 183 - 185, Replace the `(fillingFuncs as any)` access in the 2026 branch with a typed factory branch that explicitly exposes `calculateFertilizerApplicationFillingForRenure` and returns `NormFilling`. Ensure the factory’s type contract verifies both method availability and return type, while preserving `Promise.resolve(undefined)` for non-2026 years.
🤖 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 `@fdm-agents/src/tools/fertilizer-planner/index.ts`:
- Around line 750-763: The fertilizer planner must enforce the independent 2026
Renure ceiling regardless of includeRenure. In
fdm-agents/src/tools/fertilizer-planner/index.ts lines 750-763, calculate and
aggregate Renure norm/filling from 2026 onward, expose them through farmTotals,
and add compliance validation for exceeding 80 kg N/ha while retaining
includeRenure only for product eligibility. In
fdm-agents/src/tools/fertilizer-planner/index.test.ts lines 846-852, verify
enabling Renure suppresses only the strategy opt-out issue and add coverage for
a plan exceeding the Renure ceiling.
In `@fdm-app/app/components/blocks/gerrit/strategy-form.tsx`:
- Around line 99-120: Update the effect around includeRenure to return without
changing selections when showRenure is false. When showRenure is enabled, do not
automatically append Renure product IDs for includeRenure true or undefined;
preserve the user’s existing selectedFertilizerIds, while retaining filtering of
Renure products when includeRenure is explicitly false.
In `@fdm-app/app/components/blocks/timeline/mobile-view.tsx`:
- Line 79: Update eventColor, used by EventTypeIcon for the mobile event tile
styling, to detect Renure using event.p_type_rvo in addition to event.p_type.
Ensure Renure events use the same color classification as FertilizerIcon instead
of relying solely on the primary type.
In `@fdm-app/app/routes/farm`.$b_id_farm.$calendar.norms.$b_id.tsx:
- Around line 340-345: Update the showRenure rendering block to conditionally
render both ItemSeparator and renderApplicationContributionForNorm only when
applicationFilling.renure exists; keep the current behavior unchanged when a
Renure contribution is present.
In `@fdm-core/src/catalogues.ts`:
- Around line 646-670: Update the public catalogue-product creation flow around
the farm backfill loop to require authorization before creating farm-owned
fertilizer, acquiring, and picking records. Pass an acting principal_id and
validate that principal’s permission for each farm, or enforce an explicitly
privileged scheduler-only actor; do not perform the inserts for unauthorized
farms.
In `@fdm-data/src/fertilizers/catalogues/baat.json`:
- Around line 2941-3192: Add a new BAAT catalogue entry for Renure “ander
ammoniumzout” with p_type_rvo set to 134, matching the existing Renure catalogue
conventions and required nutrient/application fields. Keep the existing
Ammoniumstruviet and Kaliumstruviet entries BAAT076 and BAAT077 unchanged at
p_type_rvo 115.
---
Nitpick comments:
In `@fdm-app/app/components/blocks/timeline/timeline-colors.ts`:
- Around line 13-24: Update the getFertilizerKindColor parameter type to use
FertilizerKind | null | undefined, ensuring it accepts the existing "other"
value while preserving the current null/undefined fallback behavior and
FERTILIZER_KIND_COLOR mapping.
In `@fdm-app/app/lib/gerrit.server.ts`:
- Around line 183-185: Replace the `(fillingFuncs as any)` access in the 2026
branch with a typed factory branch that explicitly exposes
`calculateFertilizerApplicationFillingForRenure` and returns `NormFilling`.
Ensure the factory’s type contract verifies both method availability and return
type, while preserving `Promise.resolve(undefined)` for non-2026 years.
🪄 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: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: b9b3fd0c-f457-4959-8edf-24117f60c618
📒 Files selected for processing (65)
.changeset/gentle-donkeys-smile.md.changeset/gentle-herons-relax.md.changeset/khaki-corners-cheer.md.changeset/quiet-jokes-relax.md.changeset/six-games-sit.md.changeset/yummy-wasps-happen.mdfdm-agents/src/agents/gerrit/agent.tsfdm-agents/src/agents/gerrit/schema.tsfdm-agents/src/index.test.tsfdm-agents/src/index.tsfdm-agents/src/tools/fertilizer-planner/index.test.tsfdm-agents/src/tools/fertilizer-planner/index.tsfdm-app/app/components/blocks/farms/columns.tsxfdm-app/app/components/blocks/fertilizer-applications/list.tsxfdm-app/app/components/blocks/fertilizer-applications/metrics.tsxfdm-app/app/components/blocks/fertilizer/columns.tsxfdm-app/app/components/blocks/fertilizer/form.tsxfdm-app/app/components/blocks/fertilizer/utils.tsfdm-app/app/components/blocks/fields/columns.tsxfdm-app/app/components/blocks/gerrit/plan-table.tsxfdm-app/app/components/blocks/gerrit/schema.tsfdm-app/app/components/blocks/gerrit/strategy-form.tsxfdm-app/app/components/blocks/gerrit/summary-cards.tsxfdm-app/app/components/blocks/gerrit/types.tsfdm-app/app/components/blocks/norms/farm-norms.tsxfdm-app/app/components/blocks/norms/field-norms.tsxfdm-app/app/components/blocks/rotation/columns.tsxfdm-app/app/components/blocks/rotation/fertilizer-display.tsxfdm-app/app/components/blocks/timeline/gantt-view.tsxfdm-app/app/components/blocks/timeline/mobile-view.tsxfdm-app/app/components/blocks/timeline/timeline-colors.tsfdm-app/app/components/blocks/timeline/timeline-events.tsfdm-app/app/components/custom/fertilizer-icon.tsxfdm-app/app/integrations/calculator.tsfdm-app/app/lib/gerrit.server.tsfdm-app/app/routes/api.gerrit.stream.tsfdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id._index.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.gerrit.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.norms.$b_id.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.norms._index.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.rotation.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.timeline.tsxfdm-app/app/routes/organization.$slug.$calendar.farms._index.tsxfdm-calculator/src/norms/farm.test.tsfdm-calculator/src/norms/farm.tsfdm-calculator/src/norms/index.tsfdm-calculator/src/norms/nl/2025/filling/dierlijke-mest-gebruiksnorm.test.tsfdm-calculator/src/norms/nl/2025/filling/table-11-mestcodes.tsfdm-calculator/src/norms/nl/2025/filling/table-9.tsfdm-calculator/src/norms/nl/2026/filling/dierlijke-mest-gebruiksnorm.test.tsfdm-calculator/src/norms/nl/2026/filling/renure-gebruiksnorm.test.tsfdm-calculator/src/norms/nl/2026/filling/renure-gebruiksnorm.tsfdm-calculator/src/norms/nl/2026/filling/table-11-mestcodes.tsfdm-calculator/src/norms/nl/2026/filling/table-9.tsfdm-calculator/src/norms/nl/2026/filling/types.d.tsfdm-calculator/src/norms/nl/2026/value/renure-gebruiksnorm.test.tsfdm-calculator/src/norms/nl/2026/value/renure-gebruiksnorm.tsfdm-core/src/catalogues.test.tsfdm-core/src/catalogues.tsfdm-core/src/db/migrations/0032_overjoyed_beast.sqlfdm-core/src/db/migrations/meta/0032_snapshot.jsonfdm-core/src/db/migrations/meta/_journal.jsonfdm-core/src/db/schema.tsfdm-core/src/fertilizer.tsfdm-data/src/fertilizers/catalogues/baat.json
BoraIneviNMI
left a comment
There was a problem hiding this comment.
In the farm.$b_id_farm.fertilizers.new._index route you need to include the purple color for renures too.
| ? "bg-blue-600 text-white hover:bg-blue-700" | ||
| : "bg-gray-600 text-white hover:bg-gray-700" | ||
| isRenure | ||
| ? "bg-purple-600 text-white hover:bg-purple-700" |
There was a problem hiding this comment.
its correct that this structure differs? so RENURE is not a p_type but a boolean p_type_rvo? is this because a RENURE is basically another type of mineral product?
| .filter((name) => { | ||
| if (name === "isDerogation") return showDerogation | ||
| if (name === "includeRenure") return showRenure | ||
| return true |
There was a problem hiding this comment.
both TRUE can never occur?
There was a problem hiding this comment.
Yes Renure is available from 2026 and degoration up to 2025
| phosphate: GebruiksnormResult | ||
| nitrogen: GebruiksnormResult | ||
| renure?: GebruiksnormResult | ||
| } |
There was a problem hiding this comment.
question mark makes it optional?
| export function getFertilizerKindColor( | ||
| p_type: "manure" | "mineral" | "compost" | null | undefined, | ||
| p_type: FertilizerKind | null | undefined, | ||
| ): string { |
There was a problem hiding this comment.
this change is not only adding renure but switching all p_types to the export const. is that preferred above just adding "renure"?
There was a problem hiding this comment.
Yes, the type for fertilizer is now defined at a single place
| "p_ef_nh3": 0.113, | ||
| "p_name_nl": "Ammoniumsulfaat (Renure)", | ||
| "p_dm": 999, | ||
| "p_density": 1, |
There was a problem hiding this comment.
is this actually a granule or a liquid? might discuss Romke.
https://wiki.groenkennisnet.nl/space/mestverwaarding/330170384/RENURE
Most RENURE products are aqueous mineral concentrates, liquid digestate fractions, or purified ammonium salt solutions created via reverse osmosis, evaporation, or stripping-scrubbing technologies
https://nutriman.net/sites/default/files/2020-07/520-INFO_SHEET_PRODUCT-Mineral_concentrate.pdf
| "p_zn_rt": null, | ||
| "p_type_rvo": 130, | ||
| "p_app_method_options": "broadcasting||pocket placement||incorporation", | ||
| "p_app_amount_unit": "kg/ha", |
There was a problem hiding this comment.
application depends on form, if liquid then injection?
gerardhros
left a comment
There was a problem hiding this comment.
Nice update, looks great.
see few questions. Most import one is the composition of RENURE, being granular or liquid. To be discussed.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
fdm-app/app/components/blocks/gerrit/strategy-form.tsx (1)
99-112: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse the shared Renure classifier.
The local code list duplicates
RENURE_RVO_CODES; useisRenureRvoCode(fert?.p_type_rvo)so filtering stays aligned with catalogue metadata.🤖 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 `@fdm-app/app/components/blocks/gerrit/strategy-form.tsx` around lines 99 - 112, Update the filtering logic in the useEffect around selectedFertilizerIds to remove the local renureCodes list and use the shared isRenureRvoCode classifier with fert?.p_type_rvo. Preserve the existing behavior for non-renure fertilizers and the current form update flow.
🤖 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 `@fdm-app/app/components/blocks/fertilizer/utils.ts`:
- Around line 11-22: Update getFertilizerCategoryFromRvoCode in
fdm-app/app/components/blocks/fertilizer/utils.ts to expose a shared resolver
accepting p_type and p_type_rvo, preferring every recognized RVO category
including Renure and falling back to p_type. In
fdm-app/app/components/blocks/fertilizer-applications/list.tsx:60-63, use this
resolver for FertilizerIcon; in
fdm-app/app/components/blocks/fields/columns.tsx:160-162 and
fdm-app/app/components/blocks/rotation/fertilizer-display.tsx:36-43, preserve
fertilizer.p_type as the fallback; and in
fdm-app/app/components/blocks/timeline/mobile-view.tsx:60-82, derive one
resolved kind and reuse it for both tile color and icon.
---
Nitpick comments:
In `@fdm-app/app/components/blocks/gerrit/strategy-form.tsx`:
- Around line 99-112: Update the filtering logic in the useEffect around
selectedFertilizerIds to remove the local renureCodes list and use the shared
isRenureRvoCode classifier with fert?.p_type_rvo. Preserve the existing behavior
for non-renure fertilizers and the current form update flow.
🪄 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: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 581a6785-9f30-4b17-9095-2e6dfde6414f
📒 Files selected for processing (22)
.changeset/gentle-herons-relax.mdfdm-agents/src/tools/fertilizer-planner/index.test.tsfdm-agents/src/tools/fertilizer-planner/index.tsfdm-app/app/components/blocks/fertilizer-applications/list.tsxfdm-app/app/components/blocks/fertilizer/columns.tsxfdm-app/app/components/blocks/fertilizer/utils.tsfdm-app/app/components/blocks/fields/columns.tsxfdm-app/app/components/blocks/gerrit/plan-table.tsxfdm-app/app/components/blocks/gerrit/strategy-form.tsxfdm-app/app/components/blocks/gerrit/types.tsfdm-app/app/components/blocks/rotation/fertilizer-display.tsxfdm-app/app/components/blocks/timeline/gantt-view.tsxfdm-app/app/components/blocks/timeline/mobile-view.tsxfdm-app/app/components/blocks/timeline/timeline-colors.tsfdm-app/app/components/custom/fertilizer-badge.tsxfdm-app/app/components/custom/fertilizer-icon.tsxfdm-app/app/lib/gerrit.server.tsfdm-app/app/routes/farm.$b_id_farm.$calendar.norms.$b_id.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.rotation.tsxfdm-calculator/src/norms/nl/2026/filling/renure-gebruiksnorm.test.tsfdm-core/src/db/schema.tsfdm-data/src/fertilizers/catalogues/baat.json
🚧 Files skipped from review as they are similar to previous changes (9)
- .changeset/gentle-herons-relax.md
- fdm-app/app/routes/farm.$b_id_farm.$calendar.rotation.tsx
- fdm-core/src/db/schema.ts
- fdm-agents/src/tools/fertilizer-planner/index.test.ts
- fdm-app/app/components/blocks/fertilizer/columns.tsx
- fdm-app/app/components/custom/fertilizer-icon.tsx
- fdm-app/app/routes/farm.$b_id_farm.$calendar.norms.$b_id.tsx
- fdm-app/app/lib/gerrit.server.ts
- fdm-app/app/components/blocks/timeline/gantt-view.tsx
| export function getFertilizerCategoryFromRvoCode( | ||
| p_type_rvo?: string | null, | ||
| ): FertilizerKind { | ||
| if (p_type_rvo) { | ||
| if (RENURE_RVO_CODES.includes(p_type_rvo)) return "renure" | ||
| if (MINERAL_RVO_CODES.includes(p_type_rvo)) return "mineral" | ||
| if (COMPOST_RVO_CODES.includes(p_type_rvo)) return "compost" | ||
| if (MANURE_RVO_CODES.includes(p_type_rvo)) return "manure" | ||
| if (OTHER_RVO_CODES.includes(p_type_rvo)) return "other" | ||
| } | ||
| return "other" | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Resolve fertilizer kind from both metadata fields consistently.
RVO-only callers turn products without p_type_rvo into other, while the applications list prioritizes potentially stale p_type; mobile timeline color and icon can therefore disagree. Add one resolver that uses a recognized RVO category (including Renure) and otherwise falls back to p_type, then use it everywhere.
fdm-app/app/components/blocks/fertilizer/utils.ts#L11-L22: expose a resolver accepting bothp_typeandp_type_rvo.fdm-app/app/components/blocks/fertilizer-applications/list.tsx#L60-L63: use the shared resolver instead of passing competing values toFertilizerIcon.fdm-app/app/components/blocks/fields/columns.tsx#L160-L162: retainfertilizer.p_typeas fallback when RVO metadata is missing.fdm-app/app/components/blocks/rotation/fertilizer-display.tsx#L36-L43: retainfertilizer.p_typeas fallback when RVO metadata is missing.fdm-app/app/components/blocks/timeline/mobile-view.tsx#L60-L82: derive one kind and use it for both tile color and icon.
📍 Affects 5 files
fdm-app/app/components/blocks/fertilizer/utils.ts#L11-L22(this comment)fdm-app/app/components/blocks/fertilizer-applications/list.tsx#L60-L63fdm-app/app/components/blocks/fields/columns.tsx#L160-L162fdm-app/app/components/blocks/rotation/fertilizer-display.tsx#L36-L43fdm-app/app/components/blocks/timeline/mobile-view.tsx#L60-L82
🤖 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 `@fdm-app/app/components/blocks/fertilizer/utils.ts` around lines 11 - 22,
Update getFertilizerCategoryFromRvoCode in
fdm-app/app/components/blocks/fertilizer/utils.ts to expose a shared resolver
accepting p_type and p_type_rvo, preferring every recognized RVO category
including Renure and falling back to p_type. In
fdm-app/app/components/blocks/fertilizer-applications/list.tsx:60-63, use this
resolver for FertilizerIcon; in
fdm-app/app/components/blocks/fields/columns.tsx:160-162 and
fdm-app/app/components/blocks/rotation/fertilizer-display.tsx:36-43, preserve
fertilizer.p_type as the fallback; and in
fdm-app/app/components/blocks/timeline/mobile-view.tsx:60-82, derive one
resolved kind and reuse it for both tile color and icon.
There was a problem hiding this comment.
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 `@fdm-app/app/routes/farm`.$b_id_farm.fertilizers.new._index.tsx:
- Around line 216-223: Update the fertilizer badge rendering around
FertilizerBadge so it is shown when either fertilizer.p_type_rvo or
fertilizer.p_type is available. Use the RVO value when present and
fertilizer.p_type as the category fallback for custom fertilizers, while
preserving the existing hidden behavior when neither value exists.
🪄 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: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: b9db7c6c-a9e2-4547-b4ad-31e088a457b7
📒 Files selected for processing (2)
fdm-app/app/components/blocks/fertilizer/form.tsxfdm-app/app/routes/farm.$b_id_farm.fertilizers.new._index.tsx
Summary by CodeRabbit
Closes #675