Skip to content

Conversation

@madeindjs
Copy link
Collaborator

@madeindjs madeindjs commented Dec 22, 2025

Summary by CodeRabbit

  • New Features

    • Blueprints can be triggered via Cron scheduling in addition to API triggers.
    • Exposed Cron availability and trigger lookup for blueprints; payloads no longer require a trigger type.
  • Refactor

    • Trigger detection unified to recognize both API and Cron triggers.
    • Run flow simplified to a single consistent execution path that auto-selects API (preferred) or Cron.
  • Bug Fixes

    • Clearer error messages when no supported trigger is available.

✏️ Tip: You can customize this high-level summary in your review settings.

@madeindjs madeindjs self-assigned this Dec 22, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 22, 2025

Walkthrough

Adds generic trigger discovery and Cron-trigger support to blueprint execution. BlueprintRunner gains trigger-gatherers and Cron accessors; run_blueprint_via_api autonomously selects API or Cron triggers. serve.py broadens trigger checks to API or Cron and unifies task payloads. core.py no longer requires trigger_type in payloads.

Changes

Cohort / File(s) Summary
Blueprint runner (gatherers & Cron)
src/writer/blueprints.py
Added _gather_blueprints_by_trigger, _gather_api_blueprints, _gather_cron_blueprints; new cron_blueprints property, is_blueprint_cron_available, get_blueprint_cron_trigger. run_blueprint_via_api signature removed explicit trigger_type and now selects trigger internally (prefers API then Cron) with updated error handling.
Server trigger detection & task payloads
src/writer/serve.py
Renamed has_api_triggeris_blueprint_triggerable; detection now checks both blueprints_apitrigger and blueprints_crontrigger. Updated call sites and error messages. Unified task creation for invoking blueprints via API (single payload with branch_id + payload).
Core API payload handling
src/writer/core.py
Removed reading/forwarding of trigger_type from request payloads and no longer passes trigger_type into BlueprintRunner execution path.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Client
  participant Serve as Serve.py
  participant Runner as BlueprintRunner
  participant Registry as TriggerRegistry
  participant Worker

  Note over Client,Serve: Client requests blueprint run (no trigger_type)
  Client->>Serve: POST /run { blueprint_id, branch_id?, payload }
  Serve->>Runner: run_blueprint_via_api(blueprint_id, branch_id, payload)
  Runner->>Registry: _gather_api_blueprints() / _gather_cron_blueprints()
  alt API trigger found
    Registry-->>Runner: api_trigger_id
    Runner->>Worker: invoke using API trigger (api_trigger_id, payload)
  else Cron trigger found
    Registry-->>Runner: cron_trigger_id
    Runner->>Worker: invoke using Cron trigger (cron_trigger_id, payload)
  else no trigger
    Runner-->>Serve: raise ValueError (no supported trigger)
    Serve-->>Client: 4xx error (lacks a supported trigger)
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • bybash

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 70.59% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: enabling CRON trigger blocks to run alongside existing API trigger support.
Linked Issues check ✅ Passed The pull request implements the rebasing and merging of the scheduling PR, enabling CRON trigger blocks to be executable as intended.
Out of Scope Changes check ✅ Passed All changes are within scope: blueprint runner enhancements for CRON support, API refactoring to support multiple trigger types, and core logic updates to remove trigger_type coupling.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch AB-881

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • WF-881: Request failed with status code 404

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@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.

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/writer/blueprints.py (1)

170-183: Implementation is consistent with the API counterpart.

The static analysis tool flags that exception messages should ideally be defined within exception classes (TRY003). Since get_blueprint_api_trigger uses the same pattern, this is consistent. Consider creating a custom exception class if you plan to catch these specifically, but this is optional.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 5ee36de and 1fe0e42.

📒 Files selected for processing (2)
  • src/writer/blueprints.py
  • src/writer/serve.py
🧰 Additional context used
🪛 Ruff (0.14.10)
src/writer/blueprints.py

180-182: Avoid specifying long messages outside the exception class

(TRY003)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: tests (firefox)
  • GitHub Check: tests (webkit)
  • GitHub Check: tests (chromium)
  • GitHub Check: build (3.9)
  • GitHub Check: build (3.12)
  • GitHub Check: build (3.10)
  • GitHub Check: build (3.13)
  • GitHub Check: build (3.11)
🔇 Additional comments (6)
src/writer/serve.py (2)

388-396: Clean generalization of trigger detection.

The refactored function cleanly extends trigger support to both API and Cron types. Using a tuple for supported_triggers makes the code extensible for potential future trigger types while keeping the logic readable.


524-529: LGTM!

The validation and error message are correctly updated to reflect support for both trigger types. The existing bypass for branch_id execution is properly preserved.

src/writer/blueprints.py (4)

72-74: LGTM!

The property follows the established pattern of api_blueprints for consistency.


144-153: LGTM!

The implementation correctly mirrors is_blueprint_api_available and provides consistent API for checking Cron trigger availability.


185-230: Good refactoring to reduce duplication.

The generalized _gather_blueprints_by_trigger method cleanly consolidates the logic for both API and Cron trigger collection, making the code more maintainable and extensible.


252-258: Verify the asymmetric fallback behavior is intentional.

The fallback logic at line 254 has asymmetric behavior:

  • If trigger_type == "API" but API trigger is unavailable → silently falls back to Cron
  • If trigger_type == "Cron" but Cron trigger is unavailable → raises ValueError

This works correctly with the current serve.py code (where trigger_type="Cron" is only used when branch_id is provided, bypassing this logic), but could be confusing for direct callers of this method who might expect symmetric behavior.

Consider either:

  1. Documenting this fallback behavior explicitly in the docstring
  2. Or making the fallback symmetric (try both before failing)

@pullrequest
Copy link

pullrequest bot commented Dec 22, 2025

HackerOne Code Security Review

🟢 Scan Complete: 3 Issue(s)
🟢 Validation Complete: Any Issues detected were validated by one of our engineers. None were determined to require immediate action.

Here's how the code changes were interpreted and info about the tools used for scanning.

📖 Summary of Changes The modifications across multiple files in the writer module focus on enhancing blueprint trigger handling. Changes include introducing methods for gathering Cron blueprints, refactoring trigger type detection, and expanding blueprint triggerability checks. The updates appear to improve the flexibility and robustness of blueprint execution mechanisms, with minimal alterations to the core implementation.
File Summary
src/writer/blueprints.py The changes include adding methods for gathering Cron blueprints, introducing a new method run_blueprint_via_api with enhanced trigger type detection, and adding a new property cron_blueprints to the BlueprintRunner class to support Cron-triggered blueprints.
src/writer/core.py The changes between the old and new files are minimal. The primary differences appear to be in the EventHandlerRegistry class, specifically in the run_blueprint_via_api method, where the trigger_type parameter has been removed and the method signature slightly modified. The core logic and structure of the file remain substantially the same.
src/writer/serve.py The changes include renaming the function has_api_trigger to is_blueprint_triggerable and expanding its functionality to check for both API and Cron triggers. The function now supports a broader range of blueprint trigger types and provides a more descriptive name for its purpose.
ℹ️ Issues Detected

NOTE: These may not require action!

Below are unvalidated results from the Analysis Tools that ran during the latest scan for transparency. We investigate each of these for accuracy and relevance before surfacing them as a potential problem.

How will I know if something is a problem?
When validation completes, any concerns that warrant attention prior to merge will be posted as inline comments. These will show up in 2 ways:

  • Expert review (most cases): Issues will be posted by experts who manually reviewed and validated them. These are real HackerOne engineers (not bots) reviewing through an integrated IDE-like tool. You can communicate with them like any other reviewer. They'll stay assigned and get notified with commit & comment updates.
  • Automatically: In cases where our validation checks have highest confidence the problem is legitimate and urgent. These will include a description of contextual reasoning why & actionable next steps.
File & Line Issue
src/writer/blueprints.py Line 253 The modified code introduces a new feature for Cron triggers in blueprints, but there's a potential issue in the run_blueprint_via_api method. The function now attempts to determine the trigger type from the component, but doesn't validate that the component exists before accessing its type attribute. If trigger_id is provided but doesn't correspond to a valid component, line 253 will attempt to access component.type on a None value, causing an AttributeError.
src/writer/serve.py Line 526 The function is_blueprint_triggerable now checks for both API and Cron triggers, but the error message in the /private/api/blueprint/{blueprint_id} endpoint still refers only to API triggers. This could mislead users when a blueprint has a Cron trigger but no API trigger.
src/writer/core.py Line 1286 The run_blueprint_via_api method previously required a trigger_type parameter that was validated and passed to the blueprint runner. This validation has been removed, which means any API call to run a blueprint will now be accepted without validating the trigger type. This could allow unauthorized blueprint execution if the application relies on trigger type validation for security controls.
🧰 Analysis tools

⏱️ Latest scan covered changes up to commit 2ca3ee7 (latest)

@pullrequest
Copy link

pullrequest bot commented Dec 22, 2025

✅ Graham C reviewed all the included code changes and associated automation findings and determined that there were no immediately actionable security flaws. Note that they will continue to be notified of any new commits or comments and follow up as needed throughout the duration of this pull request's lifecycle.

Image of Graham C Graham C


Reviewed with ❤️ by PullRequest

Copy link
Contributor

@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.

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/writer/blueprints.py (1)

185-230: Nice refactor—generalizing trigger gathering reduces duplication.

The _gather_blueprints_by_trigger method cleanly abstracts the common logic, and the derived _gather_api_blueprints and _gather_cron_blueprints methods are concise.

Minor consideration: Both api_blueprints and cron_blueprints properties recompute the component tree traversal on each access. If these are accessed frequently in hot paths, caching could be beneficial. However, this is likely acceptable for the current usage patterns.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 1fe0e42 and b565397.

📒 Files selected for processing (3)
  • src/writer/blueprints.py
  • src/writer/core.py
  • src/writer/serve.py
💤 Files with no reviewable changes (1)
  • src/writer/core.py
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-06-16T15:34:16.165Z
Learnt from: ramedina86
Repo: writer/writer-framework PR: 935
File: src/writer/blueprints.py:210-212
Timestamp: 2025-06-16T15:34:16.165Z
Learning: In src/writer/blueprints.py, execution environments passed to run_branch and run_blueprint methods are intentionally mutated during execution. The environments need to be created beforehand and should not be deep-copied, as the mutation is part of the intended workflow design.

Applied to files:

  • src/writer/blueprints.py
🧬 Code graph analysis (2)
src/writer/serve.py (2)
src/writer/app_runner.py (2)
  • AppRunner (767-1360)
  • handle_event (1083-1084)
src/writer/ss_types.py (1)
  • WriterEvent (175-180)
src/writer/blueprints.py (1)
src/writer/core.py (1)
  • run_blueprint_via_api (1272-1293)
🪛 Ruff (0.14.10)
src/writer/blueprints.py

180-182: Avoid specifying long messages outside the exception class

(TRY003)


261-261: Avoid specifying long messages outside the exception class

(TRY003)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: build (3.9)
  • GitHub Check: build (3.13)
  • GitHub Check: tests (webkit)
  • GitHub Check: build (3.12)
  • GitHub Check: build (3.11)
  • GitHub Check: tests (firefox)
  • GitHub Check: build (3.10)
  • GitHub Check: tests (chromium)
🔇 Additional comments (7)
src/writer/serve.py (3)

388-396: LGTM! Clean refactor to support multiple trigger types.

The function rename from has_api_trigger to is_blueprint_triggerable with the expanded trigger type set is well-structured. The tuple-based supported_triggers lookup is efficient and easily extensible.


524-529: LGTM! Error message updated to reflect broader trigger support.

The condition check and error message correctly align with the renamed function and new multi-trigger capability.


542-556: LGTM! Unified payload structure simplifies the event flow.

Removing trigger_type from the payload and delegating trigger selection to run_blueprint_via_api in blueprints.py is a good design choice—it centralizes trigger resolution logic and keeps the API layer thin.

src/writer/blueprints.py (4)

72-74: LGTM! Consistent pattern with existing api_blueprints property.

The new cron_blueprints property mirrors the existing api_blueprints property structure, maintaining API consistency.


144-153: LGTM! Follows the established pattern from is_blueprint_api_available.

The method correctly checks availability by delegating to the cron_blueprints property.


170-183: LGTM! Mirrors get_blueprint_api_trigger implementation.

The method correctly validates availability before returning the trigger ID. The static analysis hint about long exception messages (TRY003) is a minor style preference and acceptable here given the existing pattern used in get_blueprint_api_trigger at lines 165-167.


250-267: and

…a_api and streamline trigger selection logic - AB-881
Copy link
Contributor

@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.

Actionable comments posted: 0

🧹 Nitpick comments (2)
src/writer/blueprints.py (2)

170-183: Consider extracting exception messages to constants.

The method logic is correct. However, static analysis suggests that long error messages could be extracted to constants or custom exception classes for better maintainability.

Optional refactor
+CRON_TRIGGER_NOT_FOUND_MSG = 'Cron trigger not found for blueprint "{}".'
+
 def get_blueprint_cron_trigger(
     self, blueprint_id: str
 ):
     """
     Retrieves the Cron trigger for a given blueprint key.

     :param blueprint_key: The blueprint identifier.
     :return: The Cron trigger component.
     """
     if not self.is_blueprint_cron_available(blueprint_id):
-        raise ValueError(
-            f'Cron trigger not found for blueprint "{blueprint_id}".'
-        )
+        raise ValueError(CRON_TRIGGER_NOT_FOUND_MSG.format(blueprint_id))
     return self.cron_blueprints[blueprint_id]

250-268: Trigger resolution logic is sound with API prioritization.

The trigger resolution correctly handles three scenarios:

  1. When branch_id is provided, it determines the trigger type from the component
  2. When branch_id is None, it prioritizes API triggers over Cron triggers
  3. When no triggers are available, it raises an appropriate error

The API-over-Cron prioritization when both exist is reasonable but could be documented in the docstring if this behavior is important to users.

Note: Static analysis suggests extracting the long exception message at line 268 to a constant, similar to the earlier comment.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b565397 and 2ca3ee7.

📒 Files selected for processing (3)
  • src/writer/blueprints.py
  • src/writer/core.py
  • src/writer/serve.py
💤 Files with no reviewable changes (1)
  • src/writer/core.py
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-06-16T15:34:16.165Z
Learnt from: ramedina86
Repo: writer/writer-framework PR: 935
File: src/writer/blueprints.py:210-212
Timestamp: 2025-06-16T15:34:16.165Z
Learning: In src/writer/blueprints.py, execution environments passed to run_branch and run_blueprint methods are intentionally mutated during execution. The environments need to be created beforehand and should not be deep-copied, as the mutation is part of the intended workflow design.

Applied to files:

  • src/writer/blueprints.py
🧬 Code graph analysis (1)
src/writer/blueprints.py (1)
src/writer/core.py (1)
  • run_blueprint_via_api (1272-1293)
🪛 Ruff (0.14.10)
src/writer/blueprints.py

180-182: Avoid specifying long messages outside the exception class

(TRY003)


268-268: Avoid specifying long messages outside the exception class

(TRY003)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: build (3.11)
  • GitHub Check: build (3.9)
  • GitHub Check: build (3.10)
  • GitHub Check: build (3.12)
  • GitHub Check: build (3.13)
  • GitHub Check: tests (chromium)
  • GitHub Check: tests (webkit)
  • GitHub Check: tests (firefox)
🔇 Additional comments (8)
src/writer/serve.py (3)

388-396: LGTM! Clear function name and implementation.

The renamed function is_blueprint_triggerable with its updated docstring and implementation correctly checks for both API and Cron triggers. The use of a tuple for supported_triggers is idiomatic and efficient.


413-413: LGTM! Consistent usage of renamed function.

The call site correctly uses the renamed is_blueprint_triggerable function.


542-556: LGTM! Unified task construction simplifies the flow.

The unified approach to blueprint execution removes the need for explicit trigger type discrimination at the API layer, delegating trigger resolution to run_blueprint_via_api. This simplifies the payload structure and aligns with the broader refactoring to make trigger selection automatic.

src/writer/blueprints.py (5)

72-74: LGTM! Consistent with existing pattern.

The cron_blueprints property follows the same pattern as the existing api_blueprints property, maintaining consistency in the API.


144-153: LGTM! Mirrors the API version.

The method correctly checks for Cron trigger availability, maintaining symmetry with is_blueprint_api_available.


185-214: LGTM! Good abstraction to reduce duplication.

The generic _gather_blueprints_by_trigger method effectively consolidates trigger discovery logic, making it easy to support additional trigger types in the future.


216-230: LGTM! Clean delegation pattern.

Both _gather_api_blueprints and _gather_cron_blueprints cleanly delegate to the shared _gather_blueprints_by_trigger method, eliminating code duplication.


269-274: LGTM! Clear execution with informative title.

The invocation of run_branch correctly passes the resolved trigger information, and the title format clearly indicates which trigger type was selected.

@madeindjs madeindjs merged commit 5bf4782 into dev Dec 23, 2025
16 checks passed
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