Skip to content

Fix required fields validation and normalize template titles#4

Merged
yannelli merged 1 commit intomainfrom
claude/fix-snake-case-conversion-D8dd8
Mar 19, 2026
Merged

Fix required fields validation and normalize template titles#4
yannelli merged 1 commit intomainfrom
claude/fix-snake-case-conversion-D8dd8

Conversation

@yannelli
Copy link
Copy Markdown
Owner

@yannelli yannelli commented Mar 19, 2026

Summary

This PR fixes the JSON schema generation to correctly include all fields in the required array, regardless of their required status, and normalizes template titles to snake_case format for consistency.

Key Changes

  • Required Fields Validation: Modified EphemeralSection and Section classes to include all fields in the required array instead of only those explicitly marked as required. This ensures the schema accurately reflects all fields that must be present.

  • Template Title Normalization: Updated EphemeralTemplate and Template classes to convert template names to snake_case format using Str::snake() when generating JSON schema documents. This provides consistent naming conventions in schema output.

  • Schema Structure Simplification: Removed the conditional check that omitted the required key when the array was empty. The required key is now always included in the schema output.

Implementation Details

  • The changes affect both the Ephemeral and Model implementations consistently, maintaining parity between the two code paths.
  • Test expectations have been updated to reflect the new behavior where all fields are marked as required in the schema.
  • The Illuminate\Support\Str utility is now imported in both Template classes to support the snake_case conversion.

The schema title was using the raw template name (e.g. "Document") instead
of snake_case (e.g. "document"), causing errors with OpenAI/Anthropic APIs.
Additionally, all fields are now always included in the required array, as
strict mode requires every property to be listed as required.

https://claude.ai/code/session_01VMGZKwtTLfYK7r3pL2514T
Copilot AI review requested due to automatic review settings March 19, 2026 21:08
@yannelli yannelli self-assigned this Mar 19, 2026
@yannelli yannelli merged commit 67fe7ba into main Mar 19, 2026
6 checks passed
@yannelli yannelli deleted the claude/fix-snake-case-conversion-D8dd8 branch March 19, 2026 21:09
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates JSON Schema generation for templates/sections and adjusts feature tests accordingly, including normalizing schema document titles and changing how required is emitted.

Changes:

  • Normalize schema document title for Template/EphemeralTemplate using Str::snake($name).
  • Change Section/EphemeralSection schema generation to always emit required and currently include all field names in it.
  • Update feature test expectations for the new schema output.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/Feature/TemplateTest.php Updates expected schema document title casing/format.
tests/Feature/SectionTest.php Updates expectations around section schema required fields.
tests/Feature/SchematicServiceTest.php Updates expected schema document title returned by service.
tests/Feature/EphemeralTemplateTest.php Updates expected schema document title casing/format.
tests/Feature/EphemeralSectionTest.php Updates expectations around ephemeral section schema required fields and presence.
src/Models/Template.php Normalizes schema document title with Str::snake().
src/Models/Section.php Alters section JSON Schema required generation (now includes all fields, always emits key).
src/Ephemeral/EphemeralTemplate.php Normalizes schema document title with Str::snake().
src/Ephemeral/EphemeralSection.php Alters ephemeral section JSON Schema required generation (now includes all fields, always emits key).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 150 to 156
public function toJsonSchemaDocument(): array
{
return [
'$schema' => config('schematic.schema.draft'),
'title' => $this->name,
'title' => Str::snake($this->name),
...$this->toJsonSchema(),
];
Copy link

Copilot AI Mar 19, 2026

Choose a reason for hiding this comment

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

PR description mentions that the schema output now always includes the required key (even when empty), but Template::toJsonSchema() still conditionally omits required when there are no enabled sections (if ($required !== [])). If the goal is parity with the updated Section schemas, consider always emitting 'required' => $required here as well, or adjust the PR description to clarify this only applies to section schemas.

Copilot uses AI. Check for mistakes.
Comment on lines 158 to 165
public function toJsonSchemaDocument(): array
{
return [
'$schema' => config('schematic.schema.draft'),
'title' => $this->name,
'title' => Str::snake($this->name),
...$this->toJsonSchema(),
];
}
Copy link

Copilot AI Mar 19, 2026

Choose a reason for hiding this comment

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

PR description says the required key is now always included in schema output, but EphemeralTemplate::toJsonSchema() still omits required when there are no enabled sections (if ($required !== [])). Either align this with the updated EphemeralSection schema behavior (always include required, possibly empty) or clarify in the PR description that the change is limited to section schemas.

Copilot uses AI. Check for mistakes.
Comment on lines 65 to 74
foreach ($this->field_definitions as $field) {
$properties[$field->name] = $field->toJsonSchemaProperty();

if ($field->required) {
$required[] = $field->name;
}
$required[] = $field->name;
}

$schema = [
'type' => 'object',
'properties' => $properties,
'required' => $required,
];
Copy link

Copilot AI Mar 19, 2026

Choose a reason for hiding this comment

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

This change makes every field required in the generated JSON Schema ($required[] = $field->name;), which contradicts the documented behavior that required: false makes a field optional (typically paired with nullable: true). It also makes FieldDefinition::$required (and the addField(..., bool $required)) ineffective for schema generation. Consider restoring the conditional so only $field->required fields go into required (while still always emitting the required key, possibly as an empty array), so the schema matches both docs and the FieldDefinition API.

Copilot uses AI. Check for mistakes.
Comment on lines 60 to 69
foreach ($this->fieldDefinitions() as $field) {
$properties[$field->name] = $field->toJsonSchemaProperty();

if ($field->required) {
$required[] = $field->name;
}
$required[] = $field->name;
}

$schema = [
'type' => 'object',
'properties' => $properties,
'required' => $required,
];
Copy link

Copilot AI Mar 19, 2026

Choose a reason for hiding this comment

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

This change makes every field required in the generated JSON Schema ($required[] = $field->name;), which contradicts the documented behavior that required: false makes a field optional (typically paired with nullable: true). It also makes FieldDefinition::$required (and the addField(..., bool $required)) ineffective for schema generation. Consider restoring the conditional so only $field->required fields are listed in required (while still always emitting the required key, possibly empty), so the schema matches both docs and the FieldDefinition API.

Copilot uses AI. Check for mistakes.
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.

3 participants