Skip to content

fix(projections): reject transient projection posts#425

Merged
yordis merged 1 commit into
masterfrom
yordis/fix-disable-transient-projection-posts
Jul 7, 2026
Merged

fix(projections): reject transient projection posts#425
yordis merged 1 commit into
masterfrom
yordis/fix-disable-transient-projection-posts

Conversation

@yordis

@yordis yordis commented Jul 7, 2026

Copy link
Copy Markdown
Member
  • Transient query-style projections keep legacy runtime behavior inside the core projection surface.
  • A single management boundary keeps public APIs consistent without carrying an unsupported query path forward.

@cursor

cursor Bot commented Jul 7, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Removes a public projection mode and API surface; clients relying on transient/ad-hoc queries will break, but continuous/one-time paths are unchanged.

Overview
Transient projection creation is rejected at ProjectionManager.Handle(Post) with OperationFailed("Transient projections are not supported.") instead of registering and running them via the removed PostNewTransientProjection path. The legacy ad-hoc Post(envelope, runAs, query, enabled) overload still sets ProjectionMode.Transient, so those callers hit the same failure.

Tests and gRPC parity are aligned: new/updated manager tests expect failure and NotFound on follow-up queries; gRPC Create with transient options must return FailedPrecondition with that message. Suites that exercised transient query behavior are ignored or short-circuited with Assert.Ignore in shared fixtures.

Comment-only tweaks in checkpoint/reader code clarify behavior unrelated to the new rejection policy.

Reviewed by Cursor Bugbot for commit 042838b. Bugbot is set up for automated code reviews on this repo. Configure here.

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1c46a9e5-5a8b-4791-b249-d3666511ddff

📥 Commits

Reviewing files that changed from the base of the PR and between 1bd5d21 and 042838b.

📒 Files selected for processing (14)
  • src/EventStore.Projections.Core.Tests/Integration/specification_with_a_v8_query_posted.cs
  • src/EventStore.Projections.Core.Tests/Services/Jint/Scenarios/specification_with_js_query_posted.cs
  • src/EventStore.Projections.Core.Tests/Services/grpc_service/ProjectionManagementParityTests.cs
  • src/EventStore.Projections.Core.Tests/Services/projections_manager/query/a_new_posted_projection.cs
  • src/EventStore.Projections.Core.Tests/Services/projections_manager/runas/when_posting_a_transient_projection.cs
  • src/EventStore.Projections.Core.Tests/Services/projections_manager/when_posting_a_transient_projection.cs
  • src/EventStore.Projections.Core.Tests/Services/projections_manager/when_posting_a_transient_query_projection.cs
  • src/EventStore.Projections.Core.Tests/Services/projections_manager/when_the_transient_query_projection_has_been_posted.cs
  • src/EventStore.Projections.Core.Tests/Services/projections_manager/when_updating_a_transient_query_projection_text.cs
  • src/EventStore.Projections.Core.Tests/Services/projections_manager/when_updating_a_transient_system_query_projection_text.cs
  • src/EventStore.Projections.Core/Messages/ProjectionManagementMessage.cs
  • src/EventStore.Projections.Core/Services/Management/ProjectionManager.cs
  • src/EventStore.Projections.Core/Services/Processing/Strategies/EventReaderBasedProjectionProcessingStrategy.cs
  • src/EventStore.Projections.Core/Services/Processing/Subscriptions/EventReorderingReaderSubscription.cs
✅ Files skipped from review due to trivial changes (3)
  • src/EventStore.Projections.Core/Messages/ProjectionManagementMessage.cs
  • src/EventStore.Projections.Core/Services/Processing/Strategies/EventReaderBasedProjectionProcessingStrategy.cs
  • src/EventStore.Projections.Core/Services/Processing/Subscriptions/EventReorderingReaderSubscription.cs
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/EventStore.Projections.Core.Tests/Services/grpc_service/ProjectionManagementParityTests.cs
  • src/EventStore.Projections.Core/Services/Management/ProjectionManager.cs
  • src/EventStore.Projections.Core.Tests/Services/projections_manager/when_posting_a_transient_projection.cs
  • src/EventStore.Projections.Core.Tests/Services/projections_manager/runas/when_posting_a_transient_projection.cs

Walkthrough

Transient projection posts are now rejected immediately with an operation-failed response. The related tests now assert rejection, NotFound query behavior, and skip transient query projection scenarios.

Changes

Transient Projection Rejection

Layer / File(s) Summary
ProjectionManager rejects transient projections
src/EventStore.Projections.Core/Services/Management/ProjectionManager.cs, src/EventStore.Projections.Core/Messages/ProjectionManagementMessage.cs, src/EventStore.Projections.Core/Services/Processing/Strategies/EventReaderBasedProjectionProcessingStrategy.cs, src/EventStore.Projections.Core/Services/Processing/Subscriptions/EventReorderingReaderSubscription.cs
Handle(Post) now returns OperationFailed for ProjectionMode.Transient without constructing or validating a pending projection, and related comments were updated.
Transient projection posting tests
src/EventStore.Projections.Core.Tests/Services/projections_manager/when_posting_a_transient_projection.cs, src/EventStore.Projections.Core.Tests/Services/projections_manager/runas/when_posting_a_transient_projection.cs
New and updated tests post a transient projection, assert the unsupported failure reason, and assert GetQuery returns NotFound.
gRPC parity tests for transient creation failure
src/EventStore.Projections.Core.Tests/Services/grpc_service/ProjectionManagementParityTests.cs
Parity setup no longer creates a transient projection; creation now throws RpcException, which is asserted for FailedPrecondition and the unsupported message.
Transient query fixtures are skipped
src/EventStore.Projections.Core.Tests/Integration/specification_with_a_v8_query_posted.cs, src/EventStore.Projections.Core.Tests/Services/Jint/Scenarios/specification_with_js_query_posted.cs, src/EventStore.Projections.Core.Tests/Services/projections_manager/query/a_new_posted_projection.cs, src/EventStore.Projections.Core.Tests/Services/projections_manager/when_posting_a_transient_query_projection.cs, src/EventStore.Projections.Core.Tests/Services/projections_manager/when_the_transient_query_projection_has_been_posted.cs, src/EventStore.Projections.Core.Tests/Services/projections_manager/when_updating_a_transient_query_projection_text.cs, src/EventStore.Projections.Core.Tests/Services/projections_manager/when_updating_a_transient_system_query_projection_text.cs
Transient query projection fixtures and scenarios now ignore execution before creating or posting query projections, and renamed fixtures reflect the transient-query scenario.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant ProjectionManager
  participant ProjectionStore

  Client->>ProjectionManager: Post(ProjectionMode.Transient)
  ProjectionManager-->>Client: OperationFailed("Transient projections are not supported.")
  Client->>ProjectionManager: GetQuery(projectionName)
  ProjectionManager->>ProjectionStore: lookup projection
  ProjectionStore-->>ProjectionManager: not found
  ProjectionManager-->>Client: NotFound
Loading

Possibly related PRs

Poem

A transient hop met a firm red light,
no query sprouted into sight.
The rabbit nodded, “All is well—
unsupported paths have tales to tell.” 🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: transient projection posts are now rejected.
Description check ✅ Passed The description is on-topic and matches the change to reject transient query-style projections at the management boundary.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch yordis/fix-disable-transient-projection-posts

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
src/EventStore.Projections.Core.Tests/Services/projections_manager/runas/when_posting_a_transient_projection.cs (1)

49-67: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider renaming for clarity.

Behavior is correct, but projection_owner_cannot_retrieve_projection_query implies an authorization failure. The actual reason is that the projection was never created (Post is now rejected upfront). The sibling fixture's the_projection_is_not_registered name reflects this more accurately.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/EventStore.Projections.Core.Tests/Services/projections_manager/runas/when_posting_a_transient_projection.cs`
around lines 49 - 67, Rename the test method
projection_owner_cannot_retrieve_projection_query in
when_posting_a_transient_projection to better reflect that the projection is
never created, not that access is denied. Keep the behavior unchanged, but align
the name with the sibling fixture’s phrasing like
the_projection_is_not_registered so the intent matches the
OperationFailed/GetQuery flow.
src/EventStore.Projections.Core.Tests/Services/grpc_service/ProjectionManagementParityTests.cs (1)

215-220: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Exclusion test no longer exercises real filtering.

all_non_transient_statistics_excludes_transient_projections checks that TransientProjectionName is absent from _allNonTransientStatistics. Since the transient projection is now never created (creation always fails per this PR), this assertion is trivially true regardless of whether AllNonTransient actually filters transient projections — it no longer verifies the filtering behavior it appears intended to test.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/EventStore.Projections.Core.Tests/Services/grpc_service/ProjectionManagementParityTests.cs`
around lines 215 - 220, The
`all_non_transient_statistics_excludes_transient_projections` test no longer
proves `AllNonTransient` filtering because `TransientProjectionName` is never
actually created. Update the parity test setup in
`ProjectionManagementParityTests` so a real transient projection is created and
included in the statistics source before querying `_allNonTransientStatistics`,
then keep the assertion on `TransientProjectionName` to verify the filtering
behavior exercised by `AllNonTransient`.
src/EventStore.Projections.Core/Services/Management/ProjectionManager.cs (1)

1226-1232: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

PostNewTransientProjection is now dead code.

With Handle(Post) rejecting ProjectionMode.Transient before constructing a PendingProjection, this private method has no remaining call sites in the file (it's private, so no external callers are possible). Consider removing it.

♻️ Proposed removal
-	private void PostNewTransientProjection(PendingProjection projection, IEnvelope replyEnvelope)
-	{
-		var initializer = projection.CreateInitializer(replyEnvelope);
-		ReadProjectionPossibleStream(projection.Name,
-			m => ReadProjectionPossibleStreamCompleted
-				(m, initializer, replyEnvelope));
-	}
-
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/EventStore.Projections.Core/Services/Management/ProjectionManager.cs`
around lines 1226 - 1232, `PostNewTransientProjection` in `ProjectionManager` is
now unreachable because `Handle(Post)` rejects `ProjectionMode.Transient` before
any `PendingProjection` is created. Remove this private helper and any
now-unused related code paths so the class no longer contains dead code.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In
`@src/EventStore.Projections.Core.Tests/Services/grpc_service/ProjectionManagementParityTests.cs`:
- Around line 215-220: The
`all_non_transient_statistics_excludes_transient_projections` test no longer
proves `AllNonTransient` filtering because `TransientProjectionName` is never
actually created. Update the parity test setup in
`ProjectionManagementParityTests` so a real transient projection is created and
included in the statistics source before querying `_allNonTransientStatistics`,
then keep the assertion on `TransientProjectionName` to verify the filtering
behavior exercised by `AllNonTransient`.

In
`@src/EventStore.Projections.Core.Tests/Services/projections_manager/runas/when_posting_a_transient_projection.cs`:
- Around line 49-67: Rename the test method
projection_owner_cannot_retrieve_projection_query in
when_posting_a_transient_projection to better reflect that the projection is
never created, not that access is denied. Keep the behavior unchanged, but align
the name with the sibling fixture’s phrasing like
the_projection_is_not_registered so the intent matches the
OperationFailed/GetQuery flow.

In `@src/EventStore.Projections.Core/Services/Management/ProjectionManager.cs`:
- Around line 1226-1232: `PostNewTransientProjection` in `ProjectionManager` is
now unreachable because `Handle(Post)` rejects `ProjectionMode.Transient` before
any `PendingProjection` is created. Remove this private helper and any
now-unused related code paths so the class no longer contains dead code.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a814126d-5fc4-478d-beb0-43cdf8298a81

📥 Commits

Reviewing files that changed from the base of the PR and between 8141ce5 and 1bd5d21.

📒 Files selected for processing (4)
  • src/EventStore.Projections.Core.Tests/Services/grpc_service/ProjectionManagementParityTests.cs
  • src/EventStore.Projections.Core.Tests/Services/projections_manager/runas/when_posting_a_transient_projection.cs
  • src/EventStore.Projections.Core.Tests/Services/projections_manager/when_posting_a_transient_projection.cs
  • src/EventStore.Projections.Core/Services/Management/ProjectionManager.cs

@yordis yordis force-pushed the yordis/fix-disable-transient-projection-posts branch from 1bd5d21 to e470aa4 Compare July 7, 2026 04:48
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis yordis force-pushed the yordis/fix-disable-transient-projection-posts branch from e470aa4 to 042838b Compare July 7, 2026 05:13
@yordis yordis merged commit 7b27273 into master Jul 7, 2026
21 checks passed
@yordis yordis deleted the yordis/fix-disable-transient-projection-posts branch July 7, 2026 05:42
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.

1 participant