Skip to content

Chore/claude encode session lessons#28

Merged
emeraldleaf merged 14 commits into
mainfrom
chore/claude-encode-session-lessons
May 25, 2026
Merged

Chore/claude encode session lessons#28
emeraldleaf merged 14 commits into
mainfrom
chore/claude-encode-session-lessons

Conversation

@emeraldleaf

@emeraldleaf emeraldleaf commented May 24, 2026

Copy link
Copy Markdown
Owner

added tests

Summary by CodeRabbit

  • New Features

    • Introduced DTO-based read APIs and a new Shipment DTO for clearer, consistent query responses and ownership-aware hiding.
  • Tests

    • Added many unit/integration suites and strengthened Arrange/Act/Assert structure, security (IDOR) checks, idempotency, pagination and caching scenarios.
  • Documentation

    • Enforced read/write data-access guidance: project reads to DTOs, clarified pagination, N+1 avoidance, and cache semantics.
  • Chores

    • Updated review/checklist and tooling rules to enforce the new read/write and testing conventions.

Review Change Stack

emeraldleaf and others added 6 commits May 23, 2026 22:40
The 8-file architecture-reviewer agent pass on 2026-05-24 surfaced 12
must-fix items + 17 should-considers across security, EF Core, async,
distributed systems, and observability. The fixes shipped as PRs; this
commit captures the patterns so future code generation prevents the same
bugs rather than re-discovering them in review.

CLAUDE.md — 4 sections expanded:

1. "Security Requirements" — concrete IDOR-prevention pattern (was just
   "validate buyerId matches authenticated user"; now spells out the
   endpoint→query→handler→null→404 shape with reference templates +
   the 403-vs-404 reasoning). Adds explicit JWT defaults
   (ValidateIssuerSigningKey=true, ClockSkew=30s — not the dangerous
   5-minute default). Adds the trace-ID-exposure rule (use
   Activity.TraceId.ToString, not Activity.Id which leaks the span).
   Also explicitly cross-references the integration-test requirement.

2. "Transactional Outbox (Wolverine)" — adds the outbox-outside-handler
   atomicity trap that caused the PaymentRecoveryJob silent event drop.
   Wolverine's AutoApplyTransactions only wraps handler chains; code
   running outside (BackgroundService, recovery sweepers) needs an
   explicit SaveChangesAsync between PublishAsync and Commit, or
   Wolverine's staged envelope never reaches the outbox table.
   Includes the canonical safe wrapper as runnable code.

3. "Observability — HTTP middleware order" — strict ordering rule
   (UseExceptionHandler → UseAuthentication → CorrelationIdMiddleware →
   UseAuthorization). The first ServiceDefaults bug was middleware
   reading context.User before UseAuthentication populated it
   (UserId silently always null); the over-correction placed it after
   UseAuthorization which dropped UserId from 401/403 audit logs.
   Documents both failure modes + the correct middle ground.

4. "Testing" — IDOR test is now REQUIRED for every scoped-entity
   endpoint. Authorization behavior is only proven by an
   authorization-failure test; dotnet build + unit tests passing isn't
   sufficient. Also adds outbox-in-non-handler test requirement for
   sweepers/jobs.

.coderabbit.yaml — 3 new path_instructions blocks:

- **/Endpoints/**/*.cs gets explicit IDOR-prevention guidance with
  the canonical 4-step pattern + mass-assignment check + endpoint
  hygiene reminders.

- **/*RecoveryJob*.cs gets outbox-outside-handler trap guidance +
  per-iteration scope rule + distributed-lock rule.

- NextAurora.ServiceDefaults/**/*.cs gets the middleware-order rule,
  JWT explicit-defaults rule, trace-ID-exposure rule, and a hint that
  changes here should bump unit-test coverage (because the project has
  historically been undertested and codecov/patch will complain).

architecture-reviewer agent — new "Pattern checklist" section with
specific per-file-category scan rules. Six categories covered:
Endpoints (IDOR + mass-assignment), RecoveryJob (outbox + scope +
lock), ServiceDefaults (middleware + JWT + trace-ID), query handlers
(AsNoTracking + pagination + N+1), aggregates (rich domain entity +
collection encapsulation + concurrency token), workflows (bash
hygiene + persist-credentials + permissions). The agent now scans for
these patterns explicitly instead of re-deriving from first principles
on every review.

Issues doc (/tmp/nextaurora-issues-to-create.md) — 8 new backlog
entries from this session's findings, sized + scoped with acceptance
criteria. Includes the IDOR-test backfill, ServiceDefaults integration
tests, PaymentRecoveryJob outbox integration test, per-iteration DI
scope refactor, CORS helper, security headers, PlaceOrder defense-in-
depth, and HTTPS-redirect consolidation.

Paraphrase sweep: zero stale paraphrases. The new rules are NEW
additions, not modifications of existing wording, so none of the
existing `See CLAUDE.md` markers in code or docs need updating. The
in-flight fix PRs (IDOR, outbox, middleware) will add new markers in
their respective inline comments when they merge — that's PR-scope,
not lessons-learned-PR-scope.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…rule

The existing "Debugging Discipline" rule mandates that lessons from
debugging sessions get encoded in CLAUDE.md + supporting docs before
moving on. This commit generalizes that same discipline to ALL review
surfaces — architecture-reviewer agent passes, CodeRabbit findings,
manual code review, integration-test failures, prod incidents, security
audits.

CLAUDE.md: new "Continuous Rule Encoding (the compounding loop)" section
adjacent to Debugging Discipline. It explicitly mandates that when an
anti-pattern / rule / spec is identified worth keeping, it gets written
to ALL applicable artifacts in the same session:

  1. CLAUDE.md — the canonical rule
  2. .coderabbit.yaml path_instructions — PR-time detection
  3. architecture-reviewer agent Pattern Checklist — review-time detection
  4. .claude/skills/ — if the procedure is non-trivial
  5. docs/STATUS.md Open Issues — if deferred
  6. Supporting docs (architecture.md, performance-and-data-correctness.md,
     dev-loop.md) — when the *why* needs more than a one-liner

And it makes the threshold explicit: encode if a future author could
repeat the mistake OR re-derive the rule from first principles. Don't
encode trivial style nits; do encode security/perf/concurrency/
distributed-systems patterns. The closing line is the load-bearing
commitment: "A merged fix PR without the corresponding rule is a
half-finished job."

architecture-reviewer agent: added Step 7 to "How to work" — when the
agent identifies a pattern worth encoding, it must propose WHERE
(CLAUDE.md section / .coderabbit.yaml path / Pattern Checklist
category) and the proposed wording. Added a "Rules to encode" optional
section to the output format so the suggestions have a place to land
in the report rather than getting buried.

The point of these two changes together: the compounding loop becomes
mechanical rather than aspirational. Every review-surface finding now
has a clear path from "discovered" to "encoded so we don't discover
it again" — and the agent itself prompts for the encoding so we don't
forget.

Paraphrase sweep: clean. New section is purely additive; no existing
rule wording changed.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…in dev-loop md/svg

Round-trips the "Continuous Rule Encoding" meta-rule (introduced in the
preceding commit) into the surfaces a human or AI assistant would actually
read when working in this repo:

.claude/README.md (new): the missing "how to use this directory" guide.
  - Directory layout
  - Decision tree for picking between agents / commands / skills
  - Per-surface deep-dive: what each is, when to use, how to invoke,
    how to author, current inventory in this repo
  - Hooks + architecture-map sections (briefly; pointers to source)
  - "When to add a new extension" table that mirrors the Continuous Rule
    Encoding decision matrix from CLAUDE.md

docs/dev-loop.md: adds "Continuous Rule Encoding (the compounding feedback
loop)" section between the 5 stages and the Gaps list. Includes the
encoding-surface table (CLAUDE.md / .coderabbit.yaml / agent / skill /
status / docs) + a tiny ASCII diagram of the loop + an explicit pointer
to .claude/README.md for invocation details. Names the load-bearing rule:
"a merged fix PR without the corresponding .claude/ encoding is a
half-finished job."

docs/dev-loop.svg: two changes.
  1. Iteration-loop arrow label updated from "findings → fix → push
     → re-review" to "findings → fix → encode rule in .claude/
     → push → re-review". The encoding step is now visible at a
     glance, not buried in prose.
  2. New "Continuous Rule Encoding" section at the bottom (180px tall,
     purple/AI-LLM color matching the Stage 1 Edit-time block). Shows the
     Finding → Encode-in-four-places → Next-cycle-prevented flow
     inline. Cross-references .claude/README.md for invocation patterns.
  3. SVG viewBox + width + height bumped from 1750 to 1940 to accommodate
     the new section. Background rect resized to match.

Why all three: a human reading dev-loop.md gets the prose version. A human
viewing dev-loop.svg gets the visual. A human (or AI) opening the .claude/
directory gets the README explaining what each file in there is for.
Three surfaces, same message, picked up at whichever angle the reader
approaches from.

The architecture-reviewer agent already has Step 7 (suggest encodings)
from the previous commit. Together with this commit, the encoding loop is
now mechanical rather than aspirational at every surface.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
… OrderService

- Implement tests for GetAllProductsHandler to verify product retrieval and pagination.
- Add tests for ReserveStockHandler to ensure stock reservation logic and cache invalidation.
- Create tests for SearchProductsHandler to validate product search functionality.
- Introduce UpdateProductHandler tests to check product updates and cache management.
- Add tests for GetOrderByIdHandler to ensure correct order retrieval and mapping.
- Implement GetOrdersByBuyerHandler tests to verify order retrieval by buyer.
- Add PaymentFailedHandler tests to ensure correct handling of payment failure events.
- Introduce OrderPlacedHandler tests to validate event translation into commands.
- Add GetShipmentByOrderHandler tests to ensure shipment retrieval and ownership validation.
@coderabbitai

coderabbitai Bot commented May 24, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

<review_stack_artifact>

</review_stack_artifact>

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/claude-encode-session-lessons

@emeraldleaf

Copy link
Copy Markdown
Owner Author

@copilot resolve the merge conflicts in this pull request

…ession-lessons

# Conflicts:
#	.claude/agents/architecture-reviewer.md

Co-authored-by: emeraldleaf <5404190+emeraldleaf@users.noreply.github.com>

Copilot AI commented May 24, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

Resolved and pushed in 93a7a03.

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

Actionable comments posted: 10

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

Inline comments:
In `@tests/CatalogService.Tests.Unit/Application/CreateProductHandlerTests.cs`:
- Around line 30-31: Replace the bare phase comments with the required AAA-style
single-line markers including an em-dash and short narrative: in
CreateProductHandlerTests update "// ACT" to something like "// ACT — invoke
_sut.HandleAsync(command, CancellationToken.None) to execute the command" and
update corresponding "// ASSERT" comments to "// ASSERT — verify result contains
expected product details / side-effects" (and apply the same pattern for the
other occurrences in this test file). Ensure all phase labels are all-caps
(ARRANGE, ACT, ASSERT) and include a concise story context on the same line.

In `@tests/CatalogService.Tests.Unit/Application/GetAllProductsHandlerTests.cs`:
- Around line 31-32: Replace bare phase comments in the
GetAllProductsHandlerTests unit file with the required narrative AAA format:
change occurrences of "// ACT" and "// ASSERT" around calls like
_sut.HandleAsync(new GetAllProductsQuery(), CancellationToken.None) and
subsequent verification blocks to "// ACT — <what this phase does>" and "//
ASSERT — <what this verifies>" respectively; update the other two test locations
referenced (the blocks around lines with the second ACT/ASSERT and third
ACT/ASSERT) so each comment includes an em-dash and a brief explicit intent
describing the action or expectation for that phase.

In `@tests/CatalogService.Tests.Unit/Application/ReserveStockHandlerTests.cs`:
- Around line 33-37: Replace the bare phase comments in this test so they follow
the required "PHASE — narrative" AAA format: update the lines that currently
read "// ACT" and "// ASSERT" to include same-line em-dash explanations
describing intent and verification (e.g. "// ACT — invoke
ReserveStockHandler.HandleAsync to attempt reservation" and "// ASSERT — result
is true and invariants hold"), and apply the same change for the other phase
markers in this file (around usages of _sut.HandleAsync, command, and result at
the other noted ranges) so every test uses the explicit narrative comments.

In `@tests/CatalogService.Tests.Unit/Application/SearchProductsHandlerTests.cs`:
- Around line 33-34: Replace the loose phase comments in
SearchProductsHandlerTests with strict AAA-style markers: change bare "// ACT"
and "// ASSERT" comments to the all-caps, em-dash style with a short narrative
on the same line (e.g. "// ACT — invoke SearchProductsQuery via
SearchProductsHandler.HandleAsync(...)" and "// ASSERT — verify expected
results/behavior"); update every occurrence in this test (including the other
occurrences noted around the later assertions) so the SearchProductsHandlerTests
class follows the required "// ACT — ..." and "// ASSERT — ..." convention.

In `@tests/CatalogService.Tests.Unit/Application/UpdateProductHandlerTests.cs`:
- Around line 38-41: Replace the bare `// ACT` and `// ASSERT` comments with the
required AAA narrative format (e.g. `// ACT — Run the handler.` and `// ASSERT —
Verify expected invariants.`) in this test class (UpdateProductHandlerTests) so
each phase includes the em-dash and short rationale; specifically update the
comment above the `_sut.HandleAsync(command, CancellationToken.None);` call and
the subsequent assertion markers (and the other similar occurrences in the same
file) to follow the `// ARRANGE — <what/why>`, `// ACT — <what/why>`, `// ASSERT
— <what/why>` pattern.
- Around line 95-103: The test currently asserts an UnauthorizedAccessException
on owner mismatch; change it to follow the null→404 anti-enumeration contract:
call the handler via act and assert it does not throw, then assert the handler
returned null (instead of throwing) and that the stored entity remains unchanged
(product.Name == originalName, product.Price unchanged) and that neither
UpdateAsync nor InvalidateAsync were called; update any related endpoint tests
to map this null result to a 404 response. Use the existing symbols to locate
code: UpdateProductHandlerTests, act, product, originalName, UpdateAsync, and
InvalidateAsync.

In `@tests/OrderService.Tests.Unit/Application/ShipmentDispatchedHandlerTests.cs`:
- Around line 50-62: The test Handle_WhenOrderNotFound_ReturnsWithoutError
currently asserts no exception but doesn't verify no persistence occurred; after
invoking _sut.HandleAsync(EventFor(Guid.NewGuid()), CancellationToken.None) add
an assertion that _repository.UpdateAsync was not called (e.g. using
NSubstitute: _repository.DidNotReceive().UpdateAsync(Arg.Any<Order>(),
Arg.Any<CancellationToken>()) or _repository.Received(0).UpdateAsync(...)) to
enforce the no-op/idempotent path. Ensure you reference the same mocked
_repository and keep the existing GetByIdAsync setup and act invocation
unchanged.

In
`@tests/ShippingService.Tests.Unit/Application/PaymentCompletedHandlerTests.cs`:
- Around line 63-67: Update the test's AAA comments to match the file's em-dash
story style: change the existing "// ACT" and "// ASSERT" markers around the
call to PaymentCompletedHandler.Handle(`@event`) and the result assertion to
include the story text after an em-dash (e.g., "// ACT — when payment completed
is handled" and "// ASSERT — result should not be null"), so the // ACT and //
ASSERT comments follow the same Arrange→Act→Assert narrative convention used
elsewhere in the test file and reference the action
(PaymentCompletedHandler.Handle) and the verification
(result.Should().NotBeNull()).
- Around line 46-69: The test name promises that PaymentCompletedHandler.Handle
always returns a new command instance but currently only calls Handle once;
update the test Handle_AlwaysReturnsNewCommand to invoke
PaymentCompletedHandler.Handle twice with the same PaymentCompletedEvent,
capturing two results (e.g., result1 and result2), then assert both are not
null, have the same OrderId, and are different instances by reference (use a
"not same as" / reference inequality assertion) to verify a new object is
allocated each call.

In `@tests/ShippingService.Tests.Unit/Domain/ShipmentTests.cs`:
- Around line 15-16: Update each bare "// ACT" comment to follow the repo's AAA
pattern by adding an em-dash story explaining what the action does and what will
be verified; e.g., replace the ACT markers surrounding the call to
Shipment.Create(Guid.NewGuid(), Guid.NewGuid(), "FedEx") (and the similar ACT
markers near other Shipment.Create calls) with "// ACT — create a shipment
instance to verify creation succeeds and properties are initialized correctly"
(adjust the verb and verification text to match each test's intent), so the
comment is all-caps "ACT" followed by an em-dash and the narrative explanation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 7b1cad17-7cf0-431e-825b-44bee80b6aa9

📥 Commits

Reviewing files that changed from the base of the PR and between 220a520 and 7b30272.

⛔ Files ignored due to path filters (1)
  • docs/dev-loop.svg is excluded by !**/*.svg
📒 Files selected for processing (33)
  • .claude/README.md
  • .claude/agents/architecture-reviewer.md
  • .coderabbit.yaml
  • CLAUDE.md
  • docs/dev-loop.md
  • tests/CatalogService.Tests.Integration/ProductCachingTests.cs
  • tests/CatalogService.Tests.Unit/Application/ContextPropagationMiddlewareTests.cs
  • tests/CatalogService.Tests.Unit/Application/CreateProductHandlerTests.cs
  • tests/CatalogService.Tests.Unit/Application/GetAllProductsHandlerTests.cs
  • tests/CatalogService.Tests.Unit/Application/GetProductByIdHandlerTests.cs
  • tests/CatalogService.Tests.Unit/Application/ReserveStockHandlerTests.cs
  • tests/CatalogService.Tests.Unit/Application/SearchProductsHandlerTests.cs
  • tests/CatalogService.Tests.Unit/Application/UpdateProductHandlerTests.cs
  • tests/NotificationService.Tests.Unit/Application/NotificationEventHandlersTests.cs
  • tests/NotificationService.Tests.Unit/Application/SendNotificationHandlerTests.cs
  • tests/OrderService.Tests.Integration/OrderSagaTests.cs
  • tests/OrderService.Tests.Unit/Application/ContextPropagationMiddlewareTests.cs
  • tests/OrderService.Tests.Unit/Application/CorrelationIdMiddlewareTests.cs
  • tests/OrderService.Tests.Unit/Application/GetOrderByIdHandlerTests.cs
  • tests/OrderService.Tests.Unit/Application/GetOrdersByBuyerHandlerTests.cs
  • tests/OrderService.Tests.Unit/Application/OutgoingContextMiddlewareTests.cs
  • tests/OrderService.Tests.Unit/Application/PaymentCompletedHandlerTests.cs
  • tests/OrderService.Tests.Unit/Application/PaymentFailedHandlerTests.cs
  • tests/OrderService.Tests.Unit/Application/ShipmentDispatchedHandlerTests.cs
  • tests/OrderService.Tests.Unit/Domain/OrderLineTests.cs
  • tests/OrderService.Tests.Unit/Domain/OrderTests.cs
  • tests/PaymentService.Tests.Unit/Application/ContextPropagationMiddlewareTests.cs
  • tests/PaymentService.Tests.Unit/Application/OrderPlacedHandlerTests.cs
  • tests/PaymentService.Tests.Unit/Application/PaymentRecoveryJobTests.cs
  • tests/ShippingService.Tests.Unit/Application/ContextPropagationMiddlewareTests.cs
  • tests/ShippingService.Tests.Unit/Application/GetShipmentByOrderHandlerTests.cs
  • tests/ShippingService.Tests.Unit/Application/PaymentCompletedHandlerTests.cs
  • tests/ShippingService.Tests.Unit/Domain/ShipmentTests.cs

Comment thread tests/CatalogService.Tests.Unit/Application/CreateProductHandlerTests.cs Outdated
Comment thread tests/CatalogService.Tests.Unit/Application/GetAllProductsHandlerTests.cs Outdated
Comment thread tests/CatalogService.Tests.Unit/Application/ReserveStockHandlerTests.cs Outdated
Comment thread tests/CatalogService.Tests.Unit/Application/SearchProductsHandlerTests.cs Outdated
Comment thread tests/CatalogService.Tests.Unit/Application/UpdateProductHandlerTests.cs Outdated
Comment thread tests/CatalogService.Tests.Unit/Application/UpdateProductHandlerTests.cs Outdated
Comment thread tests/OrderService.Tests.Unit/Application/ShipmentDispatchedHandlerTests.cs Outdated
Comment thread tests/ShippingService.Tests.Unit/Application/PaymentCompletedHandlerTests.cs Outdated
Comment thread tests/ShippingService.Tests.Unit/Application/PaymentCompletedHandlerTests.cs Outdated
Comment thread tests/ShippingService.Tests.Unit/Domain/ShipmentTests.cs Outdated
@codecov

codecov Bot commented May 24, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 84.24658% with 23 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...ippingService/Infrastructure/ShipmentRepository.cs 0.00% 13 Missing ⚠️
NextAurora.Contracts/DTOs/ShipmentDto.cs 45.45% 6 Missing ⚠️
OrderService/Infrastructure/OrderRepository.cs 91.11% 1 Missing and 3 partials ⚠️

📢 Thoughts on this report? Let us know!

- Updated comments in various test files to provide clearer context for actions taken during tests.
- Replaced null return value handling with ReturnsNull() for better readability in mocks.
- Ensured that all test cases consistently describe the action being performed in the ACT section.
- Enhanced assertions to clarify expected outcomes and improve test reliability.

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
tests/OrderService.Tests.Unit/Application/PaymentFailedHandlerTests.cs (1)

61-67: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Number and explain the two ASSERT invariants in the idempotency no-op test.

This ASSERT block checks multiple invariants (NotThrowAsync and DidNotReceive) but does not number/explain them, which makes the guarded failure mode less explicit.

Suggested comment-only patch
-        // ASSERT — No throw, no save.
+        // ASSERT — Two invariants:
+        //  1) No exception — late benign deliveries should be consumed, not DLQ'd.
+        //  2) No UpdateAsync call — proves true no-op behavior when the order is missing.
         await act.Should().NotThrowAsync();
         await _repository.DidNotReceive().UpdateAsync(Arg.Any<Order>(), Arg.Any<CancellationToken>());

As per coding guidelines: when ASSERT checks multiple invariants in idempotency scenarios, number them and explain why each matters.

🤖 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 `@tests/OrderService.Tests.Unit/Application/PaymentFailedHandlerTests.cs`
around lines 61 - 67, Update the ASSERT block to enumerate and explain the two
invariants being checked: 1) that invoking
_sut.HandleAsync(EventFor(Guid.NewGuid()), CancellationToken.None) does not
throw (use act and await act.Should().NotThrowAsync()) — explain this verifies
idempotent handling completes without exceptions, and 2) that
_repository.DidNotReceive().UpdateAsync(Arg.Any<Order>(),
Arg.Any<CancellationToken>()) — explain this verifies no state changes/saves
occur for already-handled events; add short numbered comments immediately above
each assertion referencing act and _repository.DidNotReceive to make the guarded
failure mode explicit.
🤖 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.

Inline comments:
In `@tests/OrderService.Tests.Unit/Application/OutgoingContextMiddlewareTests.cs`:
- Around line 72-74: Update the ASSERT comment above the envelope.Headers checks
to enumerate and briefly explain the two invariants: (1) "X-User-Id" must not be
present on envelope.Headers to ensure no user-id header pollution when no user
context is provided, and (2) "X-Session-Id" must not be present to ensure no
session-id leakage; reference the exact assertion lines using envelope.Headers
and the header keys "X-User-Id" and "X-Session-Id" so reviewers can see which
invariant each explanation maps to.

---

Outside diff comments:
In `@tests/OrderService.Tests.Unit/Application/PaymentFailedHandlerTests.cs`:
- Around line 61-67: Update the ASSERT block to enumerate and explain the two
invariants being checked: 1) that invoking
_sut.HandleAsync(EventFor(Guid.NewGuid()), CancellationToken.None) does not
throw (use act and await act.Should().NotThrowAsync()) — explain this verifies
idempotent handling completes without exceptions, and 2) that
_repository.DidNotReceive().UpdateAsync(Arg.Any<Order>(),
Arg.Any<CancellationToken>()) — explain this verifies no state changes/saves
occur for already-handled events; add short numbered comments immediately above
each assertion referencing act and _repository.DidNotReceive to make the guarded
failure mode explicit.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: a8f83d44-b62c-4ecb-a10d-6edc20723c3d

📥 Commits

Reviewing files that changed from the base of the PR and between 7b30272 and a89713c.

📒 Files selected for processing (27)
  • tests/CatalogService.Tests.Unit/Application/ContextPropagationMiddlewareTests.cs
  • tests/CatalogService.Tests.Unit/Application/CreateProductHandlerTests.cs
  • tests/CatalogService.Tests.Unit/Application/GetAllProductsHandlerTests.cs
  • tests/CatalogService.Tests.Unit/Application/GetProductByIdHandlerTests.cs
  • tests/CatalogService.Tests.Unit/Application/ReserveStockHandlerTests.cs
  • tests/CatalogService.Tests.Unit/Application/SearchProductsHandlerTests.cs
  • tests/CatalogService.Tests.Unit/Application/UpdateProductHandlerTests.cs
  • tests/NotificationService.Tests.Unit/Application/NotificationEventHandlersTests.cs
  • tests/NotificationService.Tests.Unit/Application/SendNotificationHandlerTests.cs
  • tests/OrderService.Tests.Integration/OrderSagaTests.cs
  • tests/OrderService.Tests.Unit/Application/ContextPropagationMiddlewareTests.cs
  • tests/OrderService.Tests.Unit/Application/CorrelationIdMiddlewareTests.cs
  • tests/OrderService.Tests.Unit/Application/GetOrderByIdHandlerTests.cs
  • tests/OrderService.Tests.Unit/Application/GetOrdersByBuyerHandlerTests.cs
  • tests/OrderService.Tests.Unit/Application/OutgoingContextMiddlewareTests.cs
  • tests/OrderService.Tests.Unit/Application/PaymentCompletedHandlerTests.cs
  • tests/OrderService.Tests.Unit/Application/PaymentFailedHandlerTests.cs
  • tests/OrderService.Tests.Unit/Application/ShipmentDispatchedHandlerTests.cs
  • tests/OrderService.Tests.Unit/Domain/OrderLineTests.cs
  • tests/OrderService.Tests.Unit/Domain/OrderTests.cs
  • tests/PaymentService.Tests.Unit/Application/ContextPropagationMiddlewareTests.cs
  • tests/PaymentService.Tests.Unit/Application/OrderPlacedHandlerTests.cs
  • tests/PaymentService.Tests.Unit/Application/PaymentRecoveryJobTests.cs
  • tests/ShippingService.Tests.Unit/Application/ContextPropagationMiddlewareTests.cs
  • tests/ShippingService.Tests.Unit/Application/GetShipmentByOrderHandlerTests.cs
  • tests/ShippingService.Tests.Unit/Application/PaymentCompletedHandlerTests.cs
  • tests/ShippingService.Tests.Unit/Domain/ShipmentTests.cs

Comment thread tests/OrderService.Tests.Unit/Application/OutgoingContextMiddlewareTests.cs Outdated
- Introduced IProductReadStore interface for read operations, separating it from IProductRepository.
- Created ProductReadStore class implementing IProductReadStore, projecting to ProductDto directly in EF.
- Updated GetAllProductsHandler, GetProductByIdHandler, SearchProductsHandler, and related tests to use IProductReadStore.
- Refactored order and shipment handlers to utilize read projections, ensuring no entity materialization occurs on read paths.
- Enhanced tests to verify DTOs are returned directly from read store methods, maintaining separation of concerns.

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

Actionable comments posted: 8

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

Inline comments:
In @.coderabbit.yaml:
- Line 64: Replace the narrow glob pattern "**/Infrastructure/*Repository.cs" in
the .coderabbit.yaml with the broader pattern
"**/Infrastructure/**/*Repository*.cs" so nested repository files (e.g.,
Infrastructure/Repositories/ProductRepository.cs) are matched; update the
pattern string in the YAML entry to the new value and save the file.

In
`@CatalogService/CatalogService.Infrastructure/Repositories/ProductReadStore.cs`:
- Around line 64-81: The SearchAsync method uses case-sensitive Contains;
replace those predicates with PostgreSQL ILIKE via EF.Functions.ILike to make
search case-insensitive: update the Where clause on context.Products in
SearchAsync to use EF.Functions.ILike for p.Name and p.Description with
wildcarded query (e.g., %query%) and ensure Microsoft.EntityFrameworkCore is
imported so EF.Functions is available. Keep the rest of the projection and
paging logic unchanged.

In `@CLAUDE.md`:
- Around line 189-190: The CLAUDE.md note was changed and any paraphrase in the
repo that ends with "See CLAUDE.md" must be audited and updated to reflect the
new EF Core guidance: locate uses of the phrasing (e.g., places referencing
AsNoTracking(), AsNoTrackingWithIdentityResolution(), AsSplitQuery(),
repo.GetX(), Mapper.ToDto(entity), GetByIdAsync, IFooReadStore or
docs/cqrs-data-access.md) and ensure they now recommend projecting into DTOs
inside the IQueryable for reads, using
AsNoTracking()/AsNoTrackingWithIdentityResolution()/AsSplitQuery() where
appropriate, splitting read/write methods (or adding IFooReadStore) instead of
reusing entity-returning GetByIdAsync for queries, and that any "See CLAUDE.md"
link points to the updated section; update the paraphrase text to match the new
guidance and run /check-rules locally to confirm no paraphrase violations
remain.

In `@docs/architecture.md`:
- Around line 500-516: The sentence "Full read/write repository separation
(Interface Segregation) is a future consideration." in the "EF Core Read/Write
Method Split" section is now stale; remove or reword it so the text consistently
states that CQRS read/write separation is the established rule (per guidance) —
locate the paragraph that contains that exact phrase and either delete it or
replace it with a definitive statement like "Full read/write repository
separation (Interface Segregation) is enforced" to avoid conflicting guidance
with the rest of the section.

In `@docs/ef-core.md`:
- Line 567: The TOC entry still references the old "shared-method wrinkle"
anchor; update the table-of-contents link text/anchor to match the renamed
section header "Read/write method split — the hard rule" so the in-page
anchor/slug and link match (e.g., replace the old "shared-method wrinkle"
label/anchor with the new header slug or explicit anchor for "Read/write method
split — the hard rule"). Ensure the TOC link target exactly matches the
generated header id used by your markdown renderer.

In `@docs/performance-and-data-correctness.md`:
- Line 200: Update any internal links that still point to the old anchor
"`#decision-asnotracking-strategy`" so they match the new heading "Decision:
read/write method split (CQRS data access)"; search the markdown for the old
anchor and replace it with the new generated anchor for that heading (e.g.
"`#decision-readwrite-method-split-cqrs-data-access`" or whatever your markdown
renderer generates) so in-page navigation from references (previously pointing
to "`#decision-asnotracking-strategy`") correctly jumps to the "Decision:
read/write method split (CQRS data access)" section.

In `@docs/STATUS.md`:
- Line 5: Update the stale timestamp string "**Last updated:** 2026-05-24" in
docs/STATUS.md to today's date by replacing "2026-05-24" with "2026-05-25" so
the file reflects the current last-updated date.

In `@OrderService/Infrastructure/OrderRepository.cs`:
- Around line 53-59: GetSummariesByBuyerIdAsync currently uses caller-supplied
page and pageSize directly; enforce bounds by validating and normalizing the
inputs inside the method (e.g., ensure page >= 1 and pageSize between 1 and a
server-side cap of 100), clamp pageSize to the cap if it exceeds 100 or set a
sensible default if zero/negative, and recalculate Skip using the sanitized
values before applying Skip/Take on context.Orders so all queries honor the
repo-wide pagination cap and avoid negative/oversized paging.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 38b77871-d13e-4762-b2d7-152a8a008206

📥 Commits

Reviewing files that changed from the base of the PR and between a89713c and ff4a7ba.

📒 Files selected for processing (36)
  • .claude/agents/architecture-reviewer.md
  • .coderabbit.yaml
  • .github/copilot-instructions.md
  • CLAUDE.md
  • CatalogService/CatalogService.Application/Handlers/GetAllProductsHandler.cs
  • CatalogService/CatalogService.Application/Handlers/GetProductByIdHandler.cs
  • CatalogService/CatalogService.Application/Handlers/SearchProductsHandler.cs
  • CatalogService/CatalogService.Application/Interfaces/IProductReadStore.cs
  • CatalogService/CatalogService.Application/Mappers/ProductMapper.cs
  • CatalogService/CatalogService.Domain/Interfaces/IProductRepository.cs
  • CatalogService/CatalogService.Infrastructure/Data/CatalogDbContext.cs
  • CatalogService/CatalogService.Infrastructure/DependencyInjection.cs
  • CatalogService/CatalogService.Infrastructure/Repositories/ProductReadStore.cs
  • CatalogService/CatalogService.Infrastructure/Repositories/ProductRepository.cs
  • NextAurora.Contracts/DTOs/ShipmentDto.cs
  • OrderService/Domain/IOrderRepository.cs
  • OrderService/Features/GetOrderById.cs
  • OrderService/Features/GetOrdersByBuyer.cs
  • OrderService/Features/OrderSummaryMapper.cs
  • OrderService/Infrastructure/OrderRepository.cs
  • PaymentService/Infrastructure/PaymentRepository.cs
  • ShippingService/Domain/IShipmentRepository.cs
  • ShippingService/Endpoints/ShippingEndpoints.cs
  • ShippingService/Features/GetShipmentByOrder.cs
  • ShippingService/Infrastructure/ShipmentRepository.cs
  • docs/STATUS.md
  • docs/architecture.md
  • docs/cqrs-data-access.md
  • docs/ef-core.md
  • docs/performance-and-data-correctness.md
  • tests/CatalogService.Tests.Unit/Application/GetAllProductsHandlerTests.cs
  • tests/CatalogService.Tests.Unit/Application/GetProductByIdHandlerTests.cs
  • tests/CatalogService.Tests.Unit/Application/SearchProductsHandlerTests.cs
  • tests/OrderService.Tests.Unit/Application/GetOrderByIdHandlerTests.cs
  • tests/OrderService.Tests.Unit/Application/GetOrdersByBuyerHandlerTests.cs
  • tests/ShippingService.Tests.Unit/Application/GetShipmentByOrderHandlerTests.cs
💤 Files with no reviewable changes (2)
  • CatalogService/CatalogService.Application/Mappers/ProductMapper.cs
  • OrderService/Features/OrderSummaryMapper.cs

Comment thread .coderabbit.yaml Outdated
Comment thread CLAUDE.md
Comment thread docs/architecture.md Outdated
Comment thread docs/ef-core.md
Comment thread docs/performance-and-data-correctness.md
Comment thread docs/STATUS.md Outdated
Comment thread OrderService/Infrastructure/OrderRepository.cs
…ration tests for ProductReadStore and OrderRepository

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

Actionable comments posted: 1

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

Inline comments:
In `@tests/OrderService.Tests.Integration/OrderReadProjectionTests.cs`:
- Around line 145-148: The test currently pre-filters dtos into buyerAOrders
before asserting count, allowing rows from other buyers to leak in; update the
assertions so they verify the returned dtos are strictly scoped to buyerA (not
just excluding buyerB). Specifically, replace the pre-filter+count check with an
assertion that every dto in dtos has BuyerId == buyerA (e.g., dtos.All(d =>
d.BuyerId == buyerA)) and still assert the total count is 3, keep the order-id
equality check using aNewest.Id, aMiddle.Id, aOldest.Id, and remove or tighten
the dtos.Should().NotContain(d => d.BuyerId == buyerB) check since the
strict-all-BuyerId assertion covers all non-requested buyers. Ensure you update
references to buyerAOrders accordingly in the OrderReadProjectionTests so all
assertions operate on dtos and not the pre-filtered collection.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 1ed79a59-1430-4a3b-a625-5f3616195531

📥 Commits

Reviewing files that changed from the base of the PR and between ff4a7ba and 2d24d02.

📒 Files selected for processing (10)
  • .coderabbit.yaml
  • CatalogService/CatalogService.Infrastructure/Repositories/ProductReadStore.cs
  • docs/STATUS.md
  • docs/architecture.md
  • docs/ef-core.md
  • docs/performance-and-data-correctness.md
  • tests/CatalogService.Tests.Integration/ProductReadStoreTests.cs
  • tests/OrderService.Tests.Integration/OrderReadProjectionTests.cs
  • tests/OrderService.Tests.Unit/Application/OutgoingContextMiddlewareTests.cs
  • tests/OrderService.Tests.Unit/Application/PaymentFailedHandlerTests.cs

Comment thread tests/OrderService.Tests.Integration/OrderReadProjectionTests.cs Outdated
- OrderRepository.GetSummariesByBuyerIdAsync: clamp page (>= 1) and
  pageSize (1..100, defaults to 50 on invalid) as defense-in-depth.
  HTTP endpoint's ClampPaging already enforces these, so this is a
  no-op under normal call flow. The clamp protects future non-endpoint
  callers (admin tools, background jobs, gRPC handlers) from oversized
  or malformed queries. Honors CLAUDE.md "Performance Rules" pagination
  cap at the repo layer.

- OrderReadProjectionTests.GetSummariesByBuyerIdAsync ordering test:
  rewrote the buyer-scope IDOR assertion to use OnlyContain on the raw
  projection result instead of pre-filtering with .Where(buyerA). The
  pre-filter could mask a cross-buyer leak; OnlyContain catches it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

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

Actionable comments posted: 1

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

Inline comments:
In `@OrderService/Infrastructure/OrderRepository.cs`:
- Around line 64-70: The Skip offset calculation can overflow when (safePage -
1) * safePageSize exceeds int range; in the method in OrderRepository that
builds the query
(context.Orders...Where(...).OrderByDescending(...).Skip(...).Take(...)),
compute the offset using long arithmetic, clamp it to int.MaxValue, then cast to
int before calling Skip. e.g. compute a long offset = (long)(safePage - 1) *
safePageSize; if (offset > int.MaxValue) offset = int.MaxValue; then use
Skip((int)offset). This prevents negative offsets from integer overflow.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: f5c5e55b-f048-4b10-b73f-79365ba7f3a4

📥 Commits

Reviewing files that changed from the base of the PR and between 2d24d02 and 9c2c617.

📒 Files selected for processing (2)
  • OrderService/Infrastructure/OrderRepository.cs
  • tests/OrderService.Tests.Integration/OrderReadProjectionTests.cs

Comment thread OrderService/Infrastructure/OrderRepository.cs Outdated
emeraldleaf and others added 2 commits May 24, 2026 21:41
- OrderRepository.GetSummariesByBuyerIdAsync: compute Skip's offset in
  long arithmetic to prevent int overflow when a non-endpoint caller
  passes a huge page (e.g. int.MaxValue). (safePage - 1) * safePageSize
  in int arithmetic would wrap negative; Skip(-N) throws at execution.
  Return empty when the offset exceeds the addressable result set
  rather than letting EF translate a too-large OFFSET into a slow
  no-result query.

- STATUS.md "Last updated" bumped 2026-05-24 → 2026-05-25. The
  disagreement with CodeRabbit was a timezone issue (UTC vs MDT
  during the late-evening window where the date crosses); CodeRabbit's
  UTC timestamp is what GitHub records, so matching that here.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CLAUDE.md "Security Requirements" lists PUT /api/v1/products/{id} as a
reference template for the canonical null/404 anti-enumeration pattern,
but the implementation drifted to throw UnauthorizedAccessException
which mapped to 403. A 403 on owner mismatch leaks existence ("this
product is there, just not yours") and lets an attacker enumerate the
product-ID space. 404 is indistinguishable from "doesn't exist."

Changes:
- UpdateProductHandler.HandleAsync: Task -> Task<bool>. Returns false
  on BOTH "product not found" AND "seller mismatch" -- callers cannot
  distinguish the two. Returns true on success.
- CatalogEndpoints PUT /products/{id}: awaits the bool, maps false to
  404 NotFound, true to 204 NoContent. Endpoint-layer 403 on
  JWT-vs-body mismatch stays (different concern: caller lied about
  their own identity, not anti-enumeration).
- GlobalExceptionHandler: drop the UnauthorizedAccessException -> 403
  case. No production code throws this exception after the handler
  refactor -- dead branch.
- UpdateProductHandlerTests: rewrite NotFound and SellerMismatch tests
  to assert the false-return contract instead of the throw. Numbered
  ASSERT invariants explain the anti-enumeration property.
- ProductAuthorizationTests (new integration suite): IDOR coverage
  per CLAUDE.md "Testing" rule. Two tests: (1) PUT by non-owner
  returns 404 and leaves the stored row unchanged (the security
  invariant); (2) PUT by owner returns 204 and persists the update
  (the happy path -- pairs with the IDOR test so a regression that
  broke ALL PUTs would still fail visibly).

Resolves CodeRabbit finding on UpdateProductHandlerTests.cs:114.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@emeraldleaf emeraldleaf merged commit 8c75b70 into main May 25, 2026
7 checks passed
emeraldleaf added a commit that referenced this pull request May 25, 2026
…stions

Triggered by Milan Jovanović's "Solving the distributed cache
invalidation problem with Redis and HybridCache" article, which argues
that the TTL-shortening mitigation NextAurora currently calls "the right
move for ship multi-replica with reasonable consistency" is in fact a
band-aid — shorter TTL shrinks the inconsistency window but doesn't
eliminate it, and trades L1 hit rate to do so.

Changes:
- STATUS.md "If we deploy multi-replica" section: relabel options 1-3.
  Option 1 (TTL drop) explicitly called a band-aid acceptable for
  Catalog reads, not OK for pricing/permissions/flags. Option 2 added:
  hand-roll a Redis Pub/Sub backplane (~50-100 lines, reuses existing
  Redis). Option 3 (FusionCache migration) kept as the heavier "do it
  right out-of-the-box" path.
- docs/code-flows/catalogservice.md: new Open questions section,
  same shape as the OrderService one (#28). Documents the gap, the
  two proper fixes, the band-aid's trade-off, and the trigger to
  act (second replica gets deployed).

No code changes — documentation-only. Captures the design question
in writing so the decision is informed if/when multi-replica lands.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
emeraldleaf added a commit that referenced this pull request May 25, 2026
* docs: per-service code-flow walkthroughs (Mermaid)

Adds one walkthrough per microservice + an index page. Each walkthrough
shows which files, classes, and interfaces get touched along the most
load-bearing request path in that service, using Mermaid sequenceDiagram
(with class+file lane labels), stateDiagram-v2 for state machines, and
graph LR for structural relationships.

- docs/code-flows.md                       — index + the saga at a glance
- docs/code-flows/orderservice.md          — PlaceOrder + 3 saga handlers
- docs/code-flows/catalogservice.md        — cached GET, IDOR-checked PUT, gRPC ReserveStock
- docs/code-flows/paymentservice.md        — event consume + cascade + recovery sweeper
- docs/code-flows/shippingservice.md       — PaymentCompleted consume + IDOR-checked GET
- docs/code-flows/notificationservice.md   — minimal stateless service (no Domain folder)

Mermaid chosen over Excalidraw for this use case: native GitHub markdown
rendering (no PNG/SVG sibling files), no Playwright dependency, text-based
source easier to maintain. Excalidraw still owns the existing visual
set-pieces (nextaurora-architecture.svg, hybridcache-flow.svg, etc.).

All 19 Mermaid blocks parser-clean. Gotcha worth knowing for future edits
(documented in the index): inside Note over X: <content>, neither ';' nor
in-content ':' is allowed — both are Mermaid parser delimiters; use em-dash
or comma instead.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(orderservice): add Open questions on per-aggregate ordering

Two-paragraph section at the bottom of the OrderService walkthrough that
captures the gap surfaced by Milan Jovanović's "Solving message ordering
from first principles" article:

- Our per-aggregate ordering is enforced via state guards + RowVersion
  retry, not bus-level sessions. That matches the "model the workflow,
  don't fight the queue" pattern. Sessions would be additive insurance
  (they fix ordering, not duplicate delivery).
- The validation is undertested — integration tests don't exercise
  concurrent same-aggregate processing, which is exactly the "subtle bug
  that only appears under load" the article warns about. Two cheap
  additions (a concurrent-event test + a retry-exhaustion metric) would
  let us measure rather than guess whether bus sessions are needed.

No code changes — captures the design question in writing so the decision
is evidence-driven if/when it lands.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs: reframe HybridCache backplane mitigation + add catalog Open questions

Triggered by Milan Jovanović's "Solving the distributed cache
invalidation problem with Redis and HybridCache" article, which argues
that the TTL-shortening mitigation NextAurora currently calls "the right
move for ship multi-replica with reasonable consistency" is in fact a
band-aid — shorter TTL shrinks the inconsistency window but doesn't
eliminate it, and trades L1 hit rate to do so.

Changes:
- STATUS.md "If we deploy multi-replica" section: relabel options 1-3.
  Option 1 (TTL drop) explicitly called a band-aid acceptable for
  Catalog reads, not OK for pricing/permissions/flags. Option 2 added:
  hand-roll a Redis Pub/Sub backplane (~50-100 lines, reuses existing
  Redis). Option 3 (FusionCache migration) kept as the heavier "do it
  right out-of-the-box" path.
- docs/code-flows/catalogservice.md: new Open questions section,
  same shape as the OrderService one (#28). Documents the gap, the
  two proper fixes, the band-aid's trade-off, and the trigger to
  act (second replica gets deployed).

No code changes — documentation-only. Captures the design question
in writing so the decision is informed if/when multi-replica lands.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs: address CodeRabbit findings on PR #29

- paymentservice.md "outbox-outside-handler trap": narrow the
  outside-handler category to truly external execution contexts
  (BackgroundService, cron, code calling PublishAsync without entering
  a handler). Admin endpoints routed through bus.InvokeAsync (as Flow 2
  shows) DO enter the handler pipeline and get AutoApplyTransactions.
  The original wording lumped them in with sweepers, contradicting
  Flow 2 in the same doc.

- orderservice.md idempotency boundary: rewrite 4 spots + the Phase 2
  sequence diagram to correctly separate the two enforcement layers:
    * Handlers pre-check Status and return early on duplicate
      (idempotency — actual behavior in
      PaymentCompletedHandler/PaymentFailedHandler/ShipmentDispatchedHandler).
    * Aggregate MarkAsX methods throw InvalidOperationException on
      invalid transitions (invariant guard, not idempotency — actual
      behavior in Order.cs:74-86).
  Original doc said the aggregate no-ops, which is wrong on both
  counts. The sequence diagram now shows BOTH the handler pre-check
  Note and the aggregate invariant Note, making the layered defense
  visible.

- catalogservice.md: update stale literal quote. The earlier STATUS.md
  edit (commit 48035ec) rewrote the phrasing from "right move for ship
  multi-replica" to "Acceptable for ship multi-replica", and the quote
  in catalogservice.md was attributing text that no longer exists in
  STATUS.md. Paraphrased instead of attributing a literal quote so
  future STATUS.md rewordings don't break the doc again.

Plus one Mermaid syntax fix: replaced a semicolon inside a Note over
block with em-dash (the doc-wide gotcha).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@emeraldleaf emeraldleaf deleted the chore/claude-encode-session-lessons branch June 4, 2026 00:40
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