Skip to content

fix: validate checkpoint SubType constraints - #851

Closed
OKAN-SOFTWARE wants to merge 4 commits into
aws:mainfrom
OKAN-SOFTWARE:fix/testing-subtype-validation-836
Closed

OKAN-SOFTWARE wants to merge 4 commits into
aws:mainfrom
OKAN-SOFTWARE:fix/testing-subtype-validation-836

Conversation

@OKAN-SOFTWARE

@OKAN-SOFTWARE OKAN-SOFTWARE commented Oct 27, 2026 •

Copy link
Copy Markdown

Issue

Fixes #836.

Description of changes

This PR brings the Python local checkpoint server's OperationUpdate.SubType validation into alignment with the AWS service model.

Previously, the local runner could accept subtype values that the AWS service rejects. Consequently, an execution could pass locally but fail when deployed.

Changes implemented:

  • Validate every non-null OperationUpdate.SubType before applying checkpoint updates.
  • Enforce the service's 1–32-character length constraint and [a-zA-Z0-9-_]+ pattern.
  • Return an HTTP 400 ValidationException with the invalid value, its 1-based update position, and the violated constraint.
  • Report multiple validation failures in update order, with a maximum of ten errors.
  • Reject the entire checkpoint request before changing execution state or advancing its checkpoint token.
  • Translate local service-model validation failures into non-retryable checkpoint errors so invalid requests terminate durable executions as FAILED.

Root cause and design

The checkpoint validator previously checked operation-state consistency without enforcing the service-model constraints on SubType.

The fix adds validation at the shared checkpoint entry point, protecting requests regardless of how they were constructed.

The in-memory service client also needed to handle the new validation exception consistently with the production client. Without this handling, the local runner retried invalid checkpoint requests until execution timeout instead of treating them as unrecoverable failures.

Scope and design decisions:

The design follows the service constraints described in #836. Maintainer feedback on the approach is welcome; prior design approval was not obtained.

Regression coverage

Tests cover:

  • Valid subtype values at the minimum and maximum permitted lengths.
  • Empty, oversized, whitespace-containing, and non-ASCII values.
  • Multiple invalid updates and error ordering.
  • The maximum of ten reported validation errors.
  • Rejection without modifying execution state.
  • Translation of local validation exceptions into non-retryable checkpoint errors.
  • End-to-end verification that invalid subtype values cause durable executions to fail.

Validation results

  • Python testing-package suite — 1,762 passed.
  • Focused client, validator, and end-to-end regression tests — 19 passed.
  • Python type checking — no issues found in 137 source files.
  • Ruff linting and formatting checks — passed.
  • git diff --check — passed.
  • Complete monorepo test suite — not executed.
  • JavaScript SDK example compatibility tests — execution blocked during setup by an environment permission error while creating a local IPC socket.
  • Live AWS service comparison — not performed.

The Python testing-package run produced two deprecation warnings but no test failures.

CI status

The upstream Python package, JavaScript examples, and cloud test workflows currently report action_required. Their results are pending; these statuses should not be interpreted as passing tests.

Review status

This PR remains a draft pending outstanding CI and cross-language verification and maintainer design feedback.

Contribution checklist

  • The change addresses the behavior reported in [Testing]: Local checkpoint server accepts a SubType the service rejects #836.
  • Regression tests cover valid and invalid inputs.
  • Invalid checkpoint requests are verified to terminate local executions.
  • The implementation remains focused on SubType validation.
  • No unrelated core SDK public API changes are introduced.
  • Remaining upstream checks must complete successfully.

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@OKAN-SOFTWARE
OKAN-SOFTWARE marked this pull request as ready for review October 28, 2026 18:36
@OKAN-SOFTWARE
OKAN-SOFTWARE deployed to ai-pr-review-runtime October 28, 2026 18:36 — with GitHub Actions Active
@hln33

hln33 commented Oct 28, 2026

Copy link
Copy Markdown
Contributor

Thanks for the first contribution @OKAN-SOFTWARE!

I am reviewing the PR as we speak, but as a first pass I'll run an AI reviewer to also see if there are any immediate issues. The reviewer will leave comments with a severity rating. Please also be sure to address them should any appear.

Comment on lines +100 to +101
if sub_type is None:
continue

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Codex AI review · Finding arf_v1_o774exfzpnxilygdtusnmrpaik

[P2] Validate empty wire subtypes before normalization

The HTTP handler parses updates through OperationUpdate.from_dict(), whose data.get("SubType") or None converts an explicit "SubType": "" into None. This branch then skips validation, so an otherwise valid checkpoint succeeds and advances its token instead of returning 400. The new empty-string test constructs OperationUpdate directly and misses this path. Validate the supplied wire value before normalization, while preserving support for an omitted subtype, and cover rejection through the HTTP request path.

To suppress repeats, reply /ai verdict deferred, /ai verdict false-positive, or /ai verdict out-of-scope on the first nonblank line. Add rationale on later lines. A new /ai verdict accepted allows future repeats again.

if errors:
reported = errors[:_MAX_VALIDATION_ERRORS]
count = len(reported)
noun = "error" if count == 1 else "errors"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Codex AI review · Finding arf_v1_dayjsbcswrpdsvjjr4hna22gl2

[P3] Revisit the untested singular-error branch

Rule 4, “Every branch has a test that fails without it,” is unmet. The single-error tests check only startswith("1 validation error"), which also accepts "1 validation errors". Always choosing the plural therefore satisfies every added assertion, leaving the singular branch without an observable regression test. Please return to the design phase under rule 8, step 6, and decide whether this formatting distinction belongs in the required behavior and how the agreed test plan will establish it.

To suppress repeats, reply /ai verdict deferred, /ai verdict false-positive, or /ai verdict out-of-scope on the first nonblank line. Add rationale on later lines. A new /ai verdict accepted allows future repeats again.

@github-actions

Copy link
Copy Markdown
Contributor

Codex AI review

Found an HTTP validation gap and two approach findings:

  • packages/aws-durable-execution-sdk-python-testing/src/aws_durable_execution_sdk_python_testing/checkpoint/validators/checkpoint.py:100
  • packages/aws-durable-execution-sdk-python-testing/src/aws_durable_execution_sdk_python_testing/exceptions.py:156
  • packages/aws-durable-execution-sdk-python-testing/src/aws_durable_execution_sdk_python_testing/checkpoint/validators/checkpoint.py:122

Static review only; tests were not executed.

Reviewed commit a9725c0792f1a2befc8d564cf997a5661e0f1e49. Workflow run

with pytest.raises(AwsApiException) as exc_info:
CheckpointValidator.validate_input([_update(sub_type)], _execution())
message = str(exc_info.value)
assert message.startswith(f"{len(constraints)} validation error")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

These assertions check a prefix and substrings. #836 asks for the exact service message. So a wrong separator, a wrong singular/plural form, or a reordered constraint would still pass here. Could you assert the full string for the one-error case, and for the two-error case in test_multiple_invalid_updates_report_in_input_order (lines 114–117) with the ; join?

Example for order charge:

assert message == (
    "1 validation error detected: Value 'order charge' at "
    "'updates.1.member.subType' failed to satisfy constraint: "
    "Member must satisfy regular expression pattern: [a-zA-Z0-9-_]+"
)

client.checkpoint("execution-arn", "token", [], None)

assert not exc_info.value.is_retryable()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: also assert the error category and cause of the exception

assert exc_info.value.error_category is DurableApiErrorCategory.EXECUTION
assert isinstance(exc_info.value.__cause__, ValidationException)

@OKAN-SOFTWARE

Copy link
Copy Markdown
Author

Thanks for the detailed review.

I've pushed commit 1587af7 addressing the feedback:

  • Preserved explicit empty SubType values during deserialization and added HTTP-level regression coverage for empty and omitted values.
  • Strengthened validation tests to assert complete error messages, including ordering and separators.
  • Added assertions for the checkpoint error category and underlying exception cause.

Validation:

  • Testing SDK: 1,764 tests passed.
  • Core SDK: 2,116 tests and 13 subtests passed.
  • Type checking: 137 source files passed.
  • Git whitespace checks passed.

The upstream CI workflows are still awaiting authorization.

The changes are ready for another review. Thank you!

@hln33

hln33 commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Thank you very much. We just had a discussion internally amongst the team. Although we can put individual validations in the processor, what we will do instead is a broader redesign where we will implement a consolidated validation layer, so we don't end up playing whack a mole with individual fixes. Please see #466

We will close this PR as this work will happen under #466.

Sorry for not communicating this sooner. We have introduced new issue labels "needs-decision" and "not-ready" to communicate whether issues are ready to be implemented in the future.

@hln33 hln33 closed this Oct 28, 2026
@OKAN-SOFTWARE

Copy link
Copy Markdown
Author

Thanks for the update and for taking the time to review my contribution. A consolidated validation layer makes sense, especially for maintaining consistency with the service model.

I'll follow #466 and would be happy to contribute once the design is finalized. Appreciate the guidance!

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.

[Testing]: Local checkpoint server accepts a SubType the service rejects

2 participants