Skip to content

Comments

ralph: #25 — Design Generated Case Templates — define 5 LLM generation template types#54

Open
jharris1679 wants to merge 1 commit intomainfrom
ralph/issue-25
Open

ralph: #25 — Design Generated Case Templates — define 5 LLM generation template types#54
jharris1679 wants to merge 1 commit intomainfrom
ralph/issue-25

Conversation

@jharris1679
Copy link
Contributor

@jharris1679 jharris1679 commented Feb 16, 2026

Issue

Closes #25

Status: ✓ verified

Build, tests, and lint all pass locally.

Summary

Automated implementation by Ralph (rlmkit + MiniMax M2.5).
Review the changes carefully — this was generated by a local model.

Summary by CodeRabbit

Release Notes

  • New Features
    • Introduced a comprehensive template system for case generation with five predefined templates: style-conformance, missing-coverage, duplication, type-safety, and dependency-updates.
    • Added built-in validation capabilities to ensure generated cases conform to defined schemas.
    • Templates are now available in the public API.

@coderabbitai
Copy link

coderabbitai bot commented Feb 16, 2026

Walkthrough

Added a new templates module to the cases package, defining five template types (style-conformance, missing-coverage, duplication, type-safety, dependency-updates) with associated metadata, configurations, validation rules, and utility functions for template management and case validation.

Changes

Cohort / File(s) Summary
Index re-export
src/cases/index.ts
Added public re-export of the new templates module to expose template types and utilities via the cases package API.
Templates module
src/cases/templates.ts
New comprehensive module introducing TemplateType enum, TemplateMetadata and TemplateConfig interfaces, TEMPLATES and TEMPLATE_CONFIGS constants with predefined template definitions, utility functions (getTemplate, getAllTemplateTypes, getTemplateConfig, isTemplateAvailable) for template queries, and validation functions (validateGeneratedCase, validateRule) with supporting validation rule and criteria interfaces.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

  • Implement Generated Case Runner #28: The new templates module provides the template schema and validation infrastructure that the Generated Case Runner feature depends on for case validation and template configuration lookup.

Poem

🐰 Five templates hop, structured and clear,
Style, coverage, duplication appear,
Type-safety guards, dependencies too,
Validation rules—a robust debut!
Templates organized, from whisker to toe! 🎨

🚥 Pre-merge checks | ✅ 6
✅ Passed checks (6 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: defining 5 LLM generation template types, which directly matches the primary objective of the PR.
Linked Issues check ✅ Passed The PR implements all 5 required template types with proper schema definition, validation rules, and utility functions as required by issue #25.
Out of Scope Changes check ✅ Passed All changes are scoped to template definition and validation. No unrelated modifications or out-of-scope features are introduced.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

✏️ 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 ralph/issue-25

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

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

Copy link

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

🤖 Fix all issues with AI agents
In `@src/cases/templates.ts`:
- Around line 221-276: Extract the duplicated required_field rules into a single
shared constant (e.g., baseValidationRules) containing the eight common rule
objects for id, title, prompt, files, source, language, difficulty, and
category; then in each template's validationRules replace the duplicated array
with a spread composition like [...baseValidationRules,
...templateSpecificRules] where templateSpecificRules contains only the
differing final pattern rule (the prompt pattern). Update all occurrences that
define validationRules (the arrays shown in the validationRules blocks) to use
the shared base constant and remove the duplicated objects from those
template-specific arrays.
- Around line 876-883: The code constructs a RegExp from untrusted input
(rule.criteria.pattern) which can cause ReDoS; modify the pattern-check block
where RegExp is created (the "Check pattern" handling referencing
rule.criteria.pattern) to validate and safely compile the regex: wrap new
RegExp(...) in a try/catch to handle invalid patterns, enforce limits (e.g. max
pattern length and disallow high-risk constructs) or check against a static
allowlist or a safe-regex utility before compiling, and on failure return a
clear error (instead of throwing) so malformed or malicious patterns cannot
cause catastrophic backtracking or runtime crashes.
- Around line 884-888: The enum validation uses
"rule.criteria.enum.includes(value as string)" unsafely; update the check in the
enum branch (referencing rule.criteria.enum) to first verify the value is a
string (e.g., typeof value === "string") and if not return a clear type error
(e.g., `${rule.field} must be one of: ...` or a message indicating it must be a
string), otherwise perform the includes check on the string; ensure you do not
use unchecked type assertions like "as string".
- Around line 866-870: The current required check only tests `value ===
undefined`, letting `null` and empty strings pass; update the validation in the
block that checks `rule.criteria.required` (where `value` and `rule.field` are
used) to treat null and empty-string as missing too — e.g., consider `value ==
null || value === ''` (or equivalent) as missing and return the same `{ error:
`${rule.field} is required` }` when that condition is met so `null` and `""`
from LLM-parsed `caseData` are rejected.
🧹 Nitpick comments (3)
src/cases/templates.ts (3)

15-20: Trailing semicolon in union type member.

Line 20 has a stray ; after the comment, which is harmless but inconsistent with the other members that use no trailing punctuation.

-  | 'dependency-updates'  // Find deprecated or outdated API usage;
+  | 'dependency-updates'; // Find deprecated or outdated API usage

914-916: getTemplate and getTemplateConfig can never return undefined given a TemplateType key.

Since the parameter is typed as TemplateType and the records are Record<TemplateType, ...>, a lookup will always succeed. The | undefined return type is misleading to callers who then have to do unnecessary null checks. If you want to keep undefined for future extensibility (e.g., dynamic template registration), accept string instead and use isTemplateAvailable as a type guard first.

Also applies to: 928-930


104-106: custom validator function won't survive serialization.

ValidationCriteria.custom holds a function reference, which means templates with custom validators can't be serialized to JSON/YAML and rehydrated—something to be aware of if templates are ever stored or transmitted as data. Consider documenting this limitation or using a named-validator registry pattern instead.

Comment on lines +221 to +276
validationRules: [
{
type: 'required_field',
field: 'id',
criteria: { required: true, pattern: '^[a-z0-9-]+$' },
errorMessage: 'Case ID must contain only lowercase letters, numbers, and hyphens',
},
{
type: 'required_field',
field: 'title',
criteria: { required: true },
errorMessage: 'Case title is required',
},
{
type: 'required_field',
field: 'prompt',
criteria: { required: true },
errorMessage: 'Case prompt is required',
},
{
type: 'required_field',
field: 'files',
criteria: { required: true },
errorMessage: 'Case files are required',
},
{
type: 'required_field',
field: 'source',
criteria: { required: true, enum: ['generated'] },
errorMessage: 'Case source must be "generated"',
},
{
type: 'required_field',
field: 'language',
criteria: { required: true },
errorMessage: 'Case language is required',
},
{
type: 'required_field',
field: 'difficulty',
criteria: { required: true, enum: ['easy', 'medium', 'hard'] },
errorMessage: 'Case difficulty must be easy, medium, or hard',
},
{
type: 'required_field',
field: 'category',
criteria: { required: true },
errorMessage: 'Case category is required',
},
{
type: 'pattern',
field: 'prompt',
criteria: { pattern: 'style|convention|naming|formatting' },
errorMessage: 'Prompt should mention style or conventions',
},
],
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Validation rules are copy-pasted across all five template configs.

The eight required_field rules (id, title, prompt, files, source, language, difficulty, category) are identical in every config. Only the final pattern rule differs. Extract a shared base array and spread template-specific rules on top.

♻️ Sketch
+const BASE_VALIDATION_RULES: TemplateValidationRule[] = [
+  {
+    type: 'required_field',
+    field: 'id',
+    criteria: { required: true, pattern: '^[a-z0-9-]+$' },
+    errorMessage: 'Case ID must contain only lowercase letters, numbers, and hyphens',
+  },
+  // ... remaining 7 shared rules ...
+];
+
 // Then in each config:
-    validationRules: [ /* 9 identical + 1 unique */ ],
+    validationRules: [
+      ...BASE_VALIDATION_RULES,
+      {
+        type: 'pattern',
+        field: 'prompt',
+        criteria: { pattern: 'style|convention|naming|formatting' },
+        errorMessage: 'Prompt should mention style or conventions',
+      },
+    ],

Also applies to: 358-413, 509-564, 631-686, 750-805

🤖 Prompt for AI Agents
In `@src/cases/templates.ts` around lines 221 - 276, Extract the duplicated
required_field rules into a single shared constant (e.g., baseValidationRules)
containing the eight common rule objects for id, title, prompt, files, source,
language, difficulty, and category; then in each template's validationRules
replace the duplicated array with a spread composition like
[...baseValidationRules, ...templateSpecificRules] where templateSpecificRules
contains only the differing final pattern rule (the prompt pattern). Update all
occurrences that define validationRules (the arrays shown in the validationRules
blocks) to use the shared base constant and remove the duplicated objects from
those template-specific arrays.

Comment on lines +866 to +870

// Check required
if (rule.criteria.required && value === undefined) {
return { error: `${rule.field} is required` };
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

required check only catches undefined, not null or empty string.

value === undefined lets null and "" slip through as valid for required fields. Since caseData comes from LLM output (parsed JSON/YAML), null values are common.

🐛 Proposed fix
   // Check required
-  if (rule.criteria.required && value === undefined) {
+  if (rule.criteria.required && (value === undefined || value === null)) {
     return { error: `${rule.field} is required` };
   }
 
   // Skip validation if value is not present and not required
-  if (value === undefined) {
+  if (value === undefined || value === null) {
     return {};
   }
🤖 Prompt for AI Agents
In `@src/cases/templates.ts` around lines 866 - 870, The current required check
only tests `value === undefined`, letting `null` and empty strings pass; update
the validation in the block that checks `rule.criteria.required` (where `value`
and `rule.field` are used) to treat null and empty-string as missing too — e.g.,
consider `value == null || value === ''` (or equivalent) as missing and return
the same `{ error: `${rule.field} is required` }` when that condition is met so
`null` and `""` from LLM-parsed `caseData` are rejected.

Comment on lines +876 to +883

// Check pattern
if (rule.criteria.pattern && typeof value === 'string') {
const regex = new RegExp(rule.criteria.pattern);
if (!regex.test(value)) {
return { error: `${rule.field} does not match required pattern` };
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

ReDoS risk: regex constructed from variable input.

rule.criteria.pattern is used directly in new RegExp(...). While current patterns are hardcoded, the TemplateConfig interface is public and extensible—custom templates could introduce pathological patterns. Wrap the construction in a try/catch at minimum, and consider a static allowlist or a safe-regex check.

🛡️ Proposed minimal hardening
   // Check pattern
   if (rule.criteria.pattern && typeof value === 'string') {
-    const regex = new RegExp(rule.criteria.pattern);
-    if (!regex.test(value)) {
-      return { error: `${rule.field} does not match required pattern` };
+    try {
+      const regex = new RegExp(rule.criteria.pattern);
+      if (!regex.test(value)) {
+        return { error: `${rule.field} does not match required pattern` };
+      }
+    } catch {
+      return { error: `${rule.field} has an invalid validation pattern` };
     }
   }
🧰 Tools
🪛 ast-grep (0.40.5)

[warning] 878-878: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(rule.criteria.pattern)
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html

(regexp-from-variable)

🤖 Prompt for AI Agents
In `@src/cases/templates.ts` around lines 876 - 883, The code constructs a RegExp
from untrusted input (rule.criteria.pattern) which can cause ReDoS; modify the
pattern-check block where RegExp is created (the "Check pattern" handling
referencing rule.criteria.pattern) to validate and safely compile the regex:
wrap new RegExp(...) in a try/catch to handle invalid patterns, enforce limits
(e.g. max pattern length and disallow high-risk constructs) or check against a
static allowlist or a safe-regex utility before compiling, and on failure return
a clear error (instead of throwing) so malformed or malicious patterns cannot
cause catastrophic backtracking or runtime crashes.

Comment on lines +884 to +888

// Check enum
if (rule.criteria.enum && !rule.criteria.enum.includes(value as string)) {
return { error: `${rule.field} must be one of: ${rule.criteria.enum.join(', ')}` };
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Unsafe cast in enum check.

value as string is applied without confirming the value is actually a string. If an LLM returns a number or boolean for a field with an enum constraint, Array.includes will silently pass/fail without a type error, producing a confusing validation message.

Proposed fix
   // Check enum
-  if (rule.criteria.enum && !rule.criteria.enum.includes(value as string)) {
+  if (rule.criteria.enum && (typeof value !== 'string' || !rule.criteria.enum.includes(value))) {
     return { error: `${rule.field} must be one of: ${rule.criteria.enum.join(', ')}` };
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Check enum
if (rule.criteria.enum && !rule.criteria.enum.includes(value as string)) {
return { error: `${rule.field} must be one of: ${rule.criteria.enum.join(', ')}` };
}
// Check enum
if (rule.criteria.enum && (typeof value !== 'string' || !rule.criteria.enum.includes(value))) {
return { error: `${rule.field} must be one of: ${rule.criteria.enum.join(', ')}` };
}
🤖 Prompt for AI Agents
In `@src/cases/templates.ts` around lines 884 - 888, The enum validation uses
"rule.criteria.enum.includes(value as string)" unsafely; update the check in the
enum branch (referencing rule.criteria.enum) to first verify the value is a
string (e.g., typeof value === "string") and if not return a clear type error
(e.g., `${rule.field} must be one of: ...` or a message indicating it must be a
string), otherwise perform the includes check on the string; ensure you do not
use unchecked type assertions like "as string".

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.

Design Generated Case Templates

1 participant