Skip to content

fix: validate effective_at against new invalid_at when both updated#13

Open
Washio20 wants to merge 1 commit intostayforge:mainfrom
Washio20:fix/bug-6
Open

fix: validate effective_at against new invalid_at when both updated#13
Washio20 wants to merge 1 commit intostayforge:mainfrom
Washio20:fix/bug-6

Conversation

@Washio20
Copy link

@Washio20 Washio20 commented Feb 23, 2026

Summary

  • Updated effective_at and invalid_at field descriptions in CardProperties schema to clarify that effective_at must be earlier than invalid_at
  • Added documentation that when both fields are updated in a single PATCH request, they are validated against each other (the new values from the request body), not against the currently stored values
  • Updated the PATCH 422 error description to explicitly describe this time validation behavior
  • Applied changes to both openapi.yaml and openapi.json

Closes #6

Test plan

  • Verify openapi.yaml is valid YAML
  • Verify openapi.json is valid JSON
  • Confirm effective_at description now mentions validation against invalid_at
  • Confirm invalid_at description now mentions validation against effective_at
  • Confirm PATCH 422 error description clarifies the validation uses new values when both are provided

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Documentation
    • Improved card API documentation with enhanced descriptions of time field validation requirements and constraints.
    • Updated error messages for card creation and modification endpoints to better explain validation failures.
    • Added clarity on validation behavior when updating multiple time-related fields in a single request.

…loses stayforge#6)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings February 23, 2026 08:08
@coderabbitai
Copy link

coderabbitai bot commented Feb 23, 2026

📝 Walkthrough

Walkthrough

OpenAPI documentation updated to clarify cross-field time validation constraints between effective_at and invalid_at fields in card schemas. Descriptions now specify that effective_at must precede invalid_at, and PATCH operations validate both fields against their new values when updated together.

Changes

Cohort / File(s) Summary
OpenAPI Documentation
openapi.json, openapi.yaml
Updated CardProperties field descriptions and 422 error responses for POST and PATCH card endpoints to document cross-field time validation: effective_at must be earlier than invalid_at, with validation occurring against new values in PATCH operations.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 The times they align in docs so bright,
Effective before invalid, set just right!
When patches come through with both fields new,
They validate together—the constraint is true!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: validate effective_at against new invalid_at when both updated' directly describes the core change—documenting the validation behavior when both time fields are updated together in a PATCH request.
Linked Issues check ✅ Passed The PR documents the undocumented cross-field validation rule (effective_at must be earlier than invalid_at) and clarifies that validation uses new values when both fields are updated, directly addressing the issue's request to document the restriction.
Out of Scope Changes check ✅ Passed All changes are limited to documentation updates in openapi.yaml and openapi.json to clarify the effective_at and invalid_at validation behavior, which is directly scoped to the linked issue.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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

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 addresses issue #6 by adding documentation to clarify the validation behavior when both effective_at and invalid_at are updated together. The key clarification is that when both fields are provided in the same request, they are validated against each other's new values (from the request body) rather than against the currently stored values in the database.

Changes:

  • Updated field descriptions in CardProperties schema to document the cross-field validation between effective_at and invalid_at
  • Enhanced the PATCH endpoint's 422 error description to explain time validation behavior
  • Applied consistent changes to both openapi.yaml and openapi.json

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 6 comments.

File Description
openapi.yaml Added documentation for time validation in CardProperties schema and PATCH 422 error response
openapi.json Mirrored the documentation changes from openapi.yaml in JSON format

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

Comment on lines +5563 to +5565
When updating both `effective_at` and `invalid_at` in a single PATCH request,
`invalid_at` is validated against the new `effective_at` value provided in
the request body (not the currently stored `effective_at`).
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

The description mentions "When updating both effective_at and invalid_at in a single PATCH request", but since CardProperties is also used by CardInput for POST requests, this wording might be confusing. Consider either:

  1. Using more generic wording like "When both fields are provided in the same request" (similar to the 422 error description), or
  2. Explicitly mentioning both POST and PATCH operations if the validation applies to both.
    This would make the documentation clearer for API consumers using the POST endpoint.

Copilot uses AI. Check for mistakes.
},
"422": {
"description": "Unprocessable Entity - Request is well-formed but contains semantic errors.\nError codes: `unprocessable_entity`\n",
"description": "Unprocessable Entity - Request is well-formed but contains semantic errors.\nFor time validation: `effective_at` must be earlier than `invalid_at`. When both fields are provided in the same request, they are validated against each other (the new values), not against the currently stored values.\nError codes: `unprocessable_entity`\n",
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

The time validation documentation was added only to the PATCH endpoint's 422 error description, but the CardProperties schema is also used by the POST endpoint (via CardInput). If the time validation logic applies to POST requests as well (when both effective_at and invalid_at are provided), consider adding similar documentation to the POST endpoint's 422 error description (line 318 in openapi.json). This would ensure consistency and clarity for API consumers using either endpoint.

Copilot uses AI. Check for mistakes.
"format": "date-time",
"nullable": true,
"description": "Effective time (when the card becomes active).\nMust be the current time or a future time.\n**⚠️Default: `UTC`**, recommended to use the format `2025-02-16T12:00:00+01:00` to ensure the correct time zone.\nAbout ISO 8601: https://en.wikipedia.org/wiki/ISO_8601\n"
"description": "Effective time (when the card becomes active).\nMust be the current time or a future time, and must be earlier than `invalid_at`.\nWhen updating both `effective_at` and `invalid_at` in a single PATCH request, `effective_at` is validated against the new `invalid_at` value provided in the request body (not the currently stored `invalid_at`).\n**⚠️Default: `UTC`**, recommended to use the format `2025-02-16T12:00:00+01:00` to ensure the correct time zone.\nAbout ISO 8601: https://en.wikipedia.org/wiki/ISO_8601\n"
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

The description mentions "When updating both effective_at and invalid_at in a single PATCH request", but since CardProperties is also used by CardInput for POST requests, this wording might be confusing. Consider either:

  1. Using more generic wording like "When both fields are provided in the same request" (similar to the 422 error description), or
  2. Explicitly mentioning both POST and PATCH operations if the validation applies to both.
    This would make the documentation clearer for API consumers using the POST endpoint.

Copilot uses AI. Check for mistakes.
"format": "date-time",
"nullable": true,
"description": "Invalidation time (when the card becomes invalid/expires).\nMust be the current time or a future time.\n**⚠️Default: `UTC`**, recommended to use the format `2025-02-16T12:00:00+01:00` to ensure the correct time zone.\nAbout ISO 8601: https://en.wikipedia.org/wiki/ISO_8601\n"
"description": "Invalidation time (when the card becomes invalid/expires).\nMust be the current time or a future time, and must be later than `effective_at`.\nWhen updating both `effective_at` and `invalid_at` in a single PATCH request, `invalid_at` is validated against the new `effective_at` value provided in the request body (not the currently stored `effective_at`).\n**⚠️Default: `UTC`**, recommended to use the format `2025-02-16T12:00:00+01:00` to ensure the correct time zone.\nAbout ISO 8601: https://en.wikipedia.org/wiki/ISO_8601\n"
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

The description mentions "When updating both effective_at and invalid_at in a single PATCH request", but since CardProperties is also used by CardInput for POST requests, this wording might be confusing. Consider either:

  1. Using more generic wording like "When both fields are provided in the same request" (similar to the 422 error description), or
  2. Explicitly mentioning both POST and PATCH operations if the validation applies to both.
    This would make the documentation clearer for API consumers using the POST endpoint.

Copilot uses AI. Check for mistakes.
Comment on lines +505 to +507
For time validation: `effective_at` must be earlier than `invalid_at`.
When both fields are provided in the same request, they are validated
against each other (the new values), not against the currently stored values.
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

The time validation documentation was added only to the PATCH endpoint's 422 error description, but the CardProperties schema is also used by the POST endpoint (via CardInput). If the time validation logic applies to POST requests as well (when both effective_at and invalid_at are provided), consider adding similar documentation to the POST endpoint's 422 error description (lines 236-242 in openapi.yaml). This would ensure consistency and clarity for API consumers using either endpoint.

Copilot uses AI. Check for mistakes.
Comment on lines +5545 to +5547
When updating both `effective_at` and `invalid_at` in a single PATCH request,
`effective_at` is validated against the new `invalid_at` value provided in
the request body (not the currently stored `invalid_at`).
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

The description mentions "When updating both effective_at and invalid_at in a single PATCH request", but since CardProperties is also used by CardInput for POST requests, this wording might be confusing. Consider either:

  1. Using more generic wording like "When both fields are provided in the same request" (similar to the 422 error description), or
  2. Explicitly mentioning both POST and PATCH operations if the validation applies to both.
    This would make the documentation clearer for API consumers using the POST endpoint.

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

Caution

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

⚠️ Outside diff range comments (2)
openapi.json (1)

660-671: ⚠️ Potential issue | 🟡 Minor

Clarify the 422 example message to avoid “Device” confusion.

This is a card endpoint, but the example message still begins with “Device validation failed,” which can mislead API consumers. Consider wording that explicitly refers to card validation or is neutral.

📝 Suggested wording
- "message": "Device validation failed or invalid effective_at/invalid_at"
+ "message": "Validation failed: invalid effective_at/invalid_at or device association"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@openapi.json` around lines 660 - 671, Update the 422 example value under the
"unprocessable_entity" example (the JSON example object referencing
components/schemas/Error) so the error message no longer says "Device validation
failed"; change it to mention "card validation failed" or a neutral phrasing
like "Validation failed or invalid effective_at/invalid_at" to match the card
endpoint and avoid confusion. Ensure the updated message stays under the same
example key "unprocessable_entity" and keeps the same error code
"unprocessable_entity".
openapi.yaml (1)

236-251: ⚠️ Potential issue | 🟡 Minor

POST 422 description not updated — inconsistency with openapi.json

According to the AI summary, openapi.json had its POST /v1/cards/{organization_id} 422 response expanded to include the cross-field time validation constraint and an updated example error message. The equivalent change is missing here in openapi.yaml, leaving the two spec files out of sync.

📄 Suggested update to align with `openapi.json`
       '422':
-        description: 'Unprocessable Entity - Request is well-formed but contains
-          semantic errors.
-
-          Error codes: `unprocessable_entity`
-
-          '
+        description: 'Unprocessable Entity - Request is well-formed but contains
+          semantic errors.
+
+          For time validation: `effective_at` must be earlier than `invalid_at`.
+          When both fields are provided in the same request, they are validated
+          against each other (the new values), not against the currently stored values.
+
+          Error codes: `unprocessable_entity`
+
+          '
         content:
           application/json:
             schema:
               $ref: '#/components/schemas/Error'
             examples:
               unprocessable_entity:
                 value:
                   code: unprocessable_entity
-                  message: Device validation failed
+                  message: Device validation failed or invalid effective_at/invalid_at
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@openapi.yaml` around lines 236 - 251, Update the POST
/v1/cards/{organization_id} 422 response in openapi.yaml to match openapi.json:
expand the description to include the cross-field time validation constraint
text, update the example under
content->application/json->examples->unprocessable_entity to the new error
message, and ensure the response still references the Error schema; locate the
POST path entry for /v1/cards/{organization_id} and modify the '422' response
block (schema $ref and examples key unprocessable_entity) to reflect the same
wording and example as openapi.json.
🧹 Nitpick comments (1)
openapi.yaml (1)

5543-5547: PATCH-specific wording in shared CardProperties may confuse POST consumers

CardProperties is inherited by both CardInput (used by POST /v1/cards) and CardUpdate (used by PATCH /v1/cards/{organization_id}/{card_number}). The phrase "When updating both effective_at and invalid_at in a single PATCH request" is scoped to PATCH, but developers reading the field description via CardInput see PATCH-specific semantics that don't apply to card creation (where there are no stored values to contrast against).

Consider generalising the wording to be operation-agnostic:

✏️ Suggested wording (applies naturally to both POST and PATCH)
-            When updating both `effective_at` and `invalid_at` in a single PATCH request,
-            `effective_at` is validated against the new `invalid_at` value provided in
-            the request body (not the currently stored `invalid_at`).
+            When both `effective_at` and `invalid_at` are provided in the same request,
+            they are validated against each other (the supplied values), not against
+            any previously stored value.

Apply the equivalent change to the invalid_at description (lines 5563-5565).

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

In `@openapi.yaml` around lines 5543 - 5547, The shared CardProperties field
descriptions include PATCH-specific language that can confuse POST consumers;
update the effective_at description (and similarly invalid_at) to
operation-agnostic wording such as: "Must be the current time or a future time
and earlier than invalid_at. If both effective_at and invalid_at are provided in
the same request, validation is performed against the values supplied in that
request (not stored values)." Ensure you change the descriptions in
CardProperties so CardInput (POST /v1/cards) and CardUpdate (PATCH
/v1/cards/{organization_id}/{card_number}) inherit the clarified, request-scoped
semantics for effective_at and invalid_at.
ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a61a3a4 and 0a64b87.

📒 Files selected for processing (2)
  • openapi.json
  • openapi.yaml
🤖 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 `@openapi.json`:
- Around line 660-671: Update the 422 example value under the
"unprocessable_entity" example (the JSON example object referencing
components/schemas/Error) so the error message no longer says "Device validation
failed"; change it to mention "card validation failed" or a neutral phrasing
like "Validation failed or invalid effective_at/invalid_at" to match the card
endpoint and avoid confusion. Ensure the updated message stays under the same
example key "unprocessable_entity" and keeps the same error code
"unprocessable_entity".

In `@openapi.yaml`:
- Around line 236-251: Update the POST /v1/cards/{organization_id} 422 response
in openapi.yaml to match openapi.json: expand the description to include the
cross-field time validation constraint text, update the example under
content->application/json->examples->unprocessable_entity to the new error
message, and ensure the response still references the Error schema; locate the
POST path entry for /v1/cards/{organization_id} and modify the '422' response
block (schema $ref and examples key unprocessable_entity) to reflect the same
wording and example as openapi.json.

---

Nitpick comments:
In `@openapi.yaml`:
- Around line 5543-5547: The shared CardProperties field descriptions include
PATCH-specific language that can confuse POST consumers; update the effective_at
description (and similarly invalid_at) to operation-agnostic wording such as:
"Must be the current time or a future time and earlier than invalid_at. If both
effective_at and invalid_at are provided in the same request, validation is
performed against the values supplied in that request (not stored values)."
Ensure you change the descriptions in CardProperties so CardInput (POST
/v1/cards) and CardUpdate (PATCH /v1/cards/{organization_id}/{card_number})
inherit the clarified, request-scoped semantics for effective_at and invalid_at.

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.

[Bug]effective_at Time Restriction Issue When Using PATCH Update a card API

2 participants