From e9e9c354dba2a070da5e3ba14b11110f92bc5405 Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Fri, 17 Apr 2026 01:27:34 +0900 Subject: [PATCH] CLAUDE.md: relax Reason interface invariant to match demo reality MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The absolute "always define an …Interface" rule in §3 #8 was not followed by the canonical demos themselves — across all eight demos concrete Reason injection is used freely for pure-policy classes (IncomePolicy, JTASProtocol, EmailNormalizer, PasswordHasher, SlugGenerator, ExcerptExtractor, CoverageValidator, etc.), and interfaces are reserved for Reasons at external I/O boundaries (PaymentGateway, CreditBureau, DamageAppraiser, AdjusterAllocator, FraudDetector, InsuranceQuoter, PropertyAppraisal, EmailVerifier, AuthorResolver, PolicyRegistry, PaymentProcessor, InventoryReserver, ShippingArranger). The invariant now documents that observed policy instead of mandating a rule nothing obeys. --- CLAUDE.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 3088fbc..cce4b9f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -92,8 +92,14 @@ will not run under Ray.Di or will break framework expectations. 7. **Semantic validators**: one class per concept, one `#[Validate]` method, throw a domain exception from `src/Exception/`. Link to schema.org in the docblock when a standard term exists (`@link https://schema.org/…`). -8. **Reason services**: always define an `…Interface` and depend on the - interface, never the concrete class. Ray.Di binds the implementation. +8. **Reason services**: Reasons sitting at an **external I/O boundary** + (HTTP, DB, payment gateway, third-party API, filesystem, clock, randomness) + MUST define an `…Interface`; consumers depend on the interface and Ray.Di + binds the implementation — so tests can swap in a Fake. Reasons that are + **pure in-process policies or calculators** (rule-book classes with no + I/O) MAY be injected as concrete classes; no interface is required. + Examples: `PaymentGatewayInterface` and `CreditBureauInterface` (boundary); + `IncomePolicy` and `JTASProtocol` (pure policy). 9. **Namespaces**: follow the existing per-demo pattern (`Be\Pattern\\\…` or `Be\App\\…`). Never invent a new root namespace.