Skip to content

refactor(checks): replace Scenario sequence with step-based structure#2297

Merged
mattbit merged 8 commits intomainfrom
2290-data-structure-of-scenario-object-proposal
Mar 11, 2026
Merged

refactor(checks): replace Scenario sequence with step-based structure#2297
mattbit merged 8 commits intomainfrom
2290-data-structure-of-scenario-object-proposal

Conversation

@kevinmessiaen
Copy link
Copy Markdown
Member

@kevinmessiaen kevinmessiaen commented Mar 10, 2026

Description

  • Add Step model grouping interacts and checks per TestCase
  • Replace sequence field with steps in Scenario
  • Add Scenario.from_sequence() for flat component input
  • Update runner with _build_steps for target binding
  • Fix Equals examples to use expected_value parameter

Related Issue

Type of Change

  • 📚 Examples / docs / tutorials / dependencies update
  • 🔧 Bug fix (non-breaking change which fixes an issue)
  • 🥂 Improvement (non-breaking change which improves an existing feature)
  • 🚀 New feature (non-breaking change which adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to change)
  • 🔐 Security fix

Checklist

  • I've read the CODE_OF_CONDUCT.md document.
  • I've read the CONTRIBUTING.md guide.
  • I've written tests for all new methods and classes that I created.
  • I've written the docstring in Google format for all the methods and classes that I used.
  • I've updated the pdm.lock running pdm update-lock (only applicable when pyproject.toml has been
    modified)

kevinmessiaen and others added 5 commits March 9, 2026 10:30
- Remove ScenarioBuilder and scenario() to eliminate variable shadowing
- Add fluent methods (interact, check, etc.) directly to Scenario
- Update Suite to accept only Scenario
- Use scenario/scenario1/scenario2 as variable names in examples

BREAKING CHANGE: scenario() and ScenarioBuilder are removed. Use
Scenario("name").interact(...).check(...) instead.

Closes #2287

Made-with: Cursor
- Add Step model grouping interacts and checks per TestCase
- Replace sequence field with steps in Scenario
- Add Scenario.from_sequence() for flat component input
- Update runner with _build_steps for target binding
- Fix Equals examples to use expected_value parameter

Refs: 2290
Made-with: Cursor
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly refactors the Scenario class within the giskard-checks library by transitioning from a flat sequence of components to a more structured, step-based approach. This change introduces a dedicated Step model to logically group interactions and checks, thereby improving the clarity and maintainability of scenario definitions. The update also includes a convenience constructor, from_sequence, to ease migration for existing scenarios and adapts the underlying scenario runner to correctly execute the new step-oriented structure.

Highlights

  • New Step Model: Introduced a new Step model to group interactions and checks within a scenario, enhancing structural organization.
  • Scenario Refactoring: Replaced the sequence field in the Scenario class with a steps field, aligning with the new step-based structure.
  • Backward Compatibility: Added Scenario.from_sequence() to allow creation of scenarios from a flat list of components, maintaining compatibility with previous usage patterns.
  • Runner Update: Updated the scenario runner logic to process the new step-based structure, including a new _build_steps function for target binding.
  • Equals Check Parameter Fix: Corrected Equals check examples to use the expected_value parameter instead of expected.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • libs/giskard-checks/README.md
    • Updated Scenario instantiation examples to use from_sequence and corrected Equals parameter name.
  • libs/giskard-checks/src/giskard/checks/init.py
    • Exported the new Step model.
  • libs/giskard-checks/src/giskard/checks/core/init.py
    • Exported the new Step model.
  • libs/giskard-checks/src/giskard/checks/core/scenario.py
    • Introduced the Step model for grouping interactions and checks.
    • Replaced the sequence field with steps in the Scenario class.
    • Added Scenario.from_sequence() class method for creating scenarios from a flat list of components.
    • Updated interact, check, checks, add_interaction, add_interactions, append, and extend methods to operate on the new steps structure.
    • Revised docstrings for Scenario and its methods to reflect the step-based design.
  • libs/giskard-checks/src/giskard/checks/scenarios/runner.py
    • Removed the internal _ScenarioStep and _ScenarioStepsBuilder classes.
    • Added the _build_steps function to handle target binding for Interact outputs within steps.
    • Refactored the ScenarioRunner to process the Scenario.steps instead of the previous sequence.
    • Updated docstrings to reflect the new step-based execution flow.
  • libs/giskard-checks/tests/core/test_scenario.py
    • Imported the new Step model for testing.
    • Updated test_scenario_annotations_propagated_to_trace to use the steps field.
    • Added a new test class TestScenarioFromSequenceAndSerialization to verify from_sequence equivalence, scenarios with only checks, serialization roundtrip, and explicit Step constructor usage.
  • libs/giskard-checks/tests/integration/test_stateless.py
    • Migrated the test_single_message integration test to utilize the new Scenario.from_sequence() constructor.
Activity
  • The author introduced a new Step model to structure scenario components.
  • The Scenario class was refactored to use this new step-based approach, replacing the flat sequence.
  • A from_sequence constructor was added to Scenario for easier migration and flexibility.
  • The scenario runner was updated to correctly process the new step-based scenarios.
  • Examples for the Equals check were corrected to use the expected_value parameter.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a significant and well-executed refactoring of the Scenario class, replacing the flat sequence of components with a more structured steps approach. The new Step model, which groups interactions and checks, improves clarity and makes the scenario's structure more explicit. The introduction of Scenario.from_sequence() is a thoughtful addition that maintains ease of use for simpler cases. The runner has been simplified, and the changes are consistently applied across the codebase, including documentation and tests. Overall, this is a great improvement to the library's core logic. I have one minor suggestion for improving code clarity in the runner.

Comment on lines +47 to +49
interact = type(interact).model_validate(
interact.model_copy(update={"outputs": target})
)
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.

medium

The current way of creating a new Interact instance with an updated outputs field is a bit convoluted and potentially inefficient. It creates an intermediate model instance with model_copy, which is then passed to model_validate (which internally converts it back to a dictionary before validation). A more direct and clearer approach would be to dump the model to a dictionary, update the dictionary, and then validate it to create the new instance. This was the approach used before this refactoring.

This is more explicit about the "dump, update, validate" process and avoids creating an unnecessary intermediate model object.

Suggested change
interact = type(interact).model_validate(
interact.model_copy(update={"outputs": target})
)
interact_data = interact.model_dump()
interact_data["outputs"] = target
interact = type(interact).model_validate(interact_data)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@gemini-code-assist

Using model_dump would prevent potentially excluded field to be passed to newly created model.

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.

You are absolutely right, @kevinmessiaen. My apologies for overlooking that crucial detail. Using model_dump() could indeed lead to issues if the Interact model has fields that are excluded from serialization by default (e.g., with exclude=True in their Field definition) but are still necessary for model_validate() to reconstruct a complete and correct instance.

model_copy(update=...) is a much safer and more robust approach in this scenario, as it preserves all existing fields of the model and only modifies the specified ones, ensuring that no essential data is inadvertently dropped or defaulted during the update process.

Thank you for catching this and pointing out the potential pitfall. The original implementation is indeed better for correctness and data integrity.

@kevinmessiaen kevinmessiaen self-assigned this Mar 11, 2026
@kevinmessiaen kevinmessiaen requested a review from mattbit March 11, 2026 09:05
Base automatically changed from 2287-scenario-builder-encourages-variable-shadowing to main March 11, 2026 09:51
@kevinmessiaen kevinmessiaen marked this pull request as ready for review March 11, 2026 09:56
Copy link
Copy Markdown
Member

@mattbit mattbit left a comment

Choose a reason for hiding this comment

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

Note: some hack with the Interact validator to set the private attribute needed for the generator. Fixed for now with a set_outputs but is something we'll need to get rid of in the future.

@mattbit mattbit merged commit 7658975 into main Mar 11, 2026
23 checks passed
@kevinmessiaen kevinmessiaen linked an issue Mar 11, 2026 that may be closed by this pull request
@mattbit mattbit deleted the 2290-data-structure-of-scenario-object-proposal branch March 11, 2026 10:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

Data structure of Scenario object: proposal

2 participants