Skip to content

feat(logic-grid-ai)!: structured validation errors + model option#23

Merged
antonstefer merged 2 commits into
mainfrom
feat/structured-validation-errors-and-model-option
Apr 28, 2026
Merged

feat(logic-grid-ai)!: structured validation errors + model option#23
antonstefer merged 2 commits into
mainfrom
feat/structured-validation-errors-and-model-option

Conversation

@antonstefer
Copy link
Copy Markdown
Owner

Summary

Three small AI-package improvements bundled into one major bump.

1. Structured validation errors

validateThemeResult now returns ThemeValidationError[] (each with a stable code, human-readable message, and optional category field). validateRewrittenClues returns RewriteCluesValidationError[] with code, message, optional 1-indexed clueIndex. Codes are exported as union types so callers can write exhaustive switches.

generateTheme now throws ThemeGenerationError carrying the structured errors; rewriteClues throws RewriteCluesError. Callers can do:

try {
  await generateTheme({ theme: "...", size: 4, categories: 4 });
} catch (err) {
  if (err instanceof ThemeGenerationError) {
    if (err.errors.some((e) => e.code === "no_ordered_category")) {
      // surface a specific hint to the user
    }
  }
  throw err;
}

2. Model option on createAnthropicClient

createAnthropicClient(undefined, { model: "claude-haiku-4-5" });

Defaults to the existing claude-sonnet-4-6. Backward-compatible — old single-arg call sites still work. Useful for swapping to Haiku for cheaper/faster generation without writing a whole custom AIClient.

3. Documents Anthropic SDK retry behavior

Code comment + README note: transport-level retries (429s, 5xx, network errors) are already handled inside the Anthropic SDK with exponential backoff. Our MAX_RETRIES = 3 only covers semantic validation failures (the AI returned malformed output and we re-prompt with the errors). The two layers don't compound.

Coverage

logic-grid-ai stays at 100% statements / branches / functions / lines (75 tests).

Breaking changes

  • validateThemeResult and validateRewrittenClues return structured objects instead of strings.
    • Migration: read e.message for the same human-readable text, or switch to e.code for stable identifiers.
  • generateTheme and rewriteClues now throw ThemeGenerationError / RewriteCluesError subclasses instead of plain Error. instanceof Error checks still match — only === against Error itself would change behavior.

Release impact

feat!: triggers a major bump → release-please will propose logic-grid-ai 2.0.0. Worth merging together with the in-flight logic-grid 3.0.0 Release PR (#22) since logic-grid-ai's peerDep on logic-grid is also moving up.

Three small AI-package improvements bundled into one major bump.

1. Validation returns structured errors instead of plain strings.
   - validateThemeResult now returns ThemeValidationError[] (each with a
     stable code, human-readable message, and optional category field).
   - validateRewrittenClues now returns RewriteCluesValidationError[]
     (with code, message, optional 1-indexed clueIndex).
   - Codes are exported as union types so callers can do exhaustive
     switches.
   - generateTheme now throws ThemeGenerationError carrying the
     structured errors; rewriteClues throws RewriteCluesError likewise.
     Callers can branch on err.errors[i].code to surface specific UI
     hints (e.g. "no_ordered_category" → guide the user to add one).

2. createAnthropicClient(apiKey?, options?) accepts an optional model
   override. Defaults to the existing claude-sonnet-4-6. Useful for
   swapping to claude-haiku-4-5 for cheaper/faster generation without
   writing a whole custom AIClient.

3. Documents that transport-level retries (429s, 5xx, network) are
   already handled inside the Anthropic SDK with exponential backoff.
   Our retry loop only covers semantic validation failures.

Tests updated to assert on stable error codes rather than message
substrings; coverage stays at 100% across all metrics.

BREAKING CHANGE: validateThemeResult and validateRewrittenClues now
return structured ValidationError objects instead of strings. Migration:
read e.message for the human-readable text (same content as before), or
switch to e.code for stable, machine-readable identifiers. generateTheme
and rewriteClues now throw ThemeGenerationError / RewriteCluesError
subclasses instead of plain Error; existing instanceof Error checks
still match.
@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented Apr 28, 2026

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
logic-grid 89eae4f Commit Preview URL

Branch Preview URL
Apr 28 2026, 01:18 PM

- Lift duplicated hasCode helper into src/test-utils.ts (typed generically
  so passing a foreign code still fails type-check at the call site).
- Document on ThemeValidationError that the category field echoes the
  asserted name even when the name itself is what's invalid (e.g. for
  long_category_name) — preserves grouping by category in callers.
- Skip the duplicate-name check when the asserted name is empty, so two
  categories with empty names report two empty_category_name errors
  rather than empty + duplicate. The empty name is the problem; calling
  it a duplicate of another empty name is noise. Added a covering test.
@antonstefer antonstefer merged commit 2d10193 into main Apr 28, 2026
4 checks passed
@antonstefer antonstefer deleted the feat/structured-validation-errors-and-model-option branch April 28, 2026 13:20
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.

1 participant