Skip to content

Improve manual clarity and add Getting Started navigation - #20

Merged
koriym merged 12 commits into
masterfrom
claude/review-chapter-one-s0e8O
Mar 24, 2026
Merged

koriym merged 12 commits into
masterfrom
claude/review-chapter-one-s0e8O

Conversation

@koriym

@koriym koriym commented Mar 24, 2026 •

Copy link
Copy Markdown
Contributor

Summary

マニュアル全体の読みやすさ改善。読者が混乱しやすい箇所の修正と、実践コンテンツへの導線追加。

  • Overview: DeletedUserの伏線を章内で回収。末尾にGetting Started / Tutorialへの導線を追加
  • Being Classes: プロパティが「誰も触れない」→ フレームワークが#[Input]として次のクラスに渡すことを明記
  • Final Objects: BeenProcessedがフレームワーク提供であることを説明。$becomingの前方参照を追加
  • Reason Layer: 同じReasonオブジェクトが#[Inject]にも$beingにもなれることを説明

All changes applied to both EN and JA versions.

https://claude.ai/code/session_01SKnc7oHPsyYZU3JkSRBi4T

Summary by CodeRabbit

  • Documentation
    • Added explanation of type-based state (e.g., DeletedUser) and type-driven state transitions
    • Clarified constructor input forwarding, #[Input]/#[Inject] resolution, and selection rules
    • Revised examples: domain-specific “$been” naming and updated example types/instantiations
    • Reframed “Reason” terminology and tutorial steps; added coordinated Potential/Moment commit guidance
    • Improved navigation with explicit Getting Started and Tutorial links; synced EN/JA docs

claude added 8 commits March 24, 2026 06:37
- Ch1: Resolve the DeletedUser teaser within the chapter itself instead
  of leaving an unfulfilled promise to later chapters
- Ch3: Clarify that the framework reads public properties to pass them
  as #[Input] to the next class (was misleadingly saying "no one touches
  those properties")
- Ch4: Add explanation that BeenProcessed is framework-provided, and
  add forward reference for $becoming which was used before introduction

Applied to both EN and JA versions.

https://claude.ai/code/session_01SKnc7oHPsyYZU3JkSRBi4T
…vided

BeenProcessed is designed by the application developer based on what
the domain requires as completion evidence, not provided by the framework.

https://claude.ai/code/session_01SKnc7oHPsyYZU3JkSRBi4T
The $been class should have a domain-specific name, not a generic one.
SuccessfulOrder uses BeenConfirmed, FailedOrder uses BeenRejected,
DeletedUser would use BeenDeleted, etc. Updated explanation to clarify
this naming convention.

https://claude.ai/code/session_01SKnc7oHPsyYZU3JkSRBi4T
Readers encounter these attributes in chapter 3 but the detailed
matching rules don't appear until chapter 5. Added a concise paragraph
after the basic structure example explaining that #[Input] receives
values by name matching and #[Inject] receives DI dependencies,
with a forward reference to chapter 5 for details.

https://claude.ai/code/session_01SKnc7oHPsyYZU3JkSRBi4T
- Rename ApprovedApplication/RejectedApplication to Approved/Rejected
  as Reason-layer destiny markers (matching tutorial's Emergency/Observation)
- Fix #[Be()] to list next classes (ApprovalNotification/RejectionNotification)
  instead of the markers themselves
- Clarify type-based continuation: framework selects the candidate whose
  #[Input] parameters can be satisfied by current object's properties
- Add explanation of Reason vs Final: constructor-complete logic belongs
  in Reason layer; deferred methods (like assignER()) belong on Final class

https://claude.ai/code/session_01SKnc7oHPsyYZU3JkSRBi4T
Replace "destiny marker" with "Reason object" throughout. The Reason
determines the destiny: when assigned to $being, the Reason's type
decides which class comes next. No separate term needed—Emergency and
JTASProtocol are both Reason objects with different roles.

- Tutorial Step 5: "Create Destiny Markers" → "Create Reason Objects"
- Tutorial project structure comments updated
- Chapter 5: unified explanation

https://claude.ai/code/session_01SKnc7oHPsyYZU3JkSRBi4T
The same Reason object can provide transcendent capabilities (#[Inject])
or determine destiny ($being). The difference is not in the object
itself but in how it is used.

https://claude.ai/code/session_01SKnc7oHPsyYZU3JkSRBi4T
Readers now have two clear paths: hands-on first (Getting Started /
Tutorial) or concepts first (Input Classes). Previously only the
conceptual path was shown.

https://claude.ai/code/session_01SKnc7oHPsyYZU3JkSRBi4T
@coderabbitai

coderabbitai Bot commented Mar 24, 2026 •

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

This PR updates English and Japanese manuals to reframe “Destiny Markers” as “Reason Objects,” clarify #[Input] auto-population from prior public properties and #[Inject] DI resolution, adjust example domain evidence types (e.g., BeenProcessed → BeenConfirmed), and align metamorphosis and tutorial terminology and examples.

Changes

Cohort / File(s) Summary
Overview & Navigation
manuals/1.0/en/01-overview.md, manuals/1.0/ja/01-overview.md
Added explanation framing DeletedUser as a type-based state; updated CTA/navigation to point to Getting Started (Hello World), Tutorial, and Input Classes.
Being Classes & Inputs
manuals/1.0/en/03-being-classes.md, manuals/1.0/ja/03-being-classes.md
Clarified that #[Input] params are auto-populated from the previous class’s public properties by name-matching and that #[Inject] is resolved from the DI container; expanded “Life” section to describe property forwarding to the next class.
Final Objects / Evidence
manuals/1.0/en/04-final-objects.md, manuals/1.0/ja/04-final-objects.md
Changed example SuccessfulOrder::$been from BeenProcessed → BeenConfirmed and constructor instantiation accordingly; generalized $been as domain-defined and expanded explanation of $becoming/multiple final destinies.
Metamorphosis Patterns
manuals/1.0/en/05-metamorphosis-patterns.md, manuals/1.0/ja/05-metamorphosis-patterns.md
Replaced candidate types (`ApprovedApplication
Reason Layer & Potential
manuals/1.0/en/08-reason-layer.md, manuals/1.0/ja/08-reason-layer.md
Added note that the same Reason type may be used as #[Inject] or $being depending on context; introduced Potential as a deferred-return pattern, Moment holders, and commit-via-be() semantics for atomic multi-operation coordination.
Tutorial & Terminology
manuals/1.0/en/tutorial.md, manuals/1.0/ja/tutorial.md
Renamed Step 5 to “Create Reason Objects,” updated narrative and project-tree comments to show Reason objects determine which Final class is produced, aligning terminology across examples.

Sequence Diagram(s)

sequenceDiagram
  participant Dev as "Developer/Reason"
  participant Moment as "Moment (holds Potential)"
  participant Final as "Final (aggregator)"
  participant External as "ExternalService"

  Dev->>Moment: create Potential (deferred op)
  Note over Moment: Potential stored inside Moment
  Dev->>Final: provide Moment(s)
  Final->>Moment: call be() on each Moment
  Moment->>External: commit Potential -> External operation
  External-->>Moment: success / failure
  alt all commit succeed
    Moment-->>Final: confirmed
    Final-->>Dev: constructed Final (all committed)
  else any failure
    Moment-->>Final: failure (construction prevented)
    Final-->>Dev: construction aborted
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 I hop from Being into Reason's light,
I tuck a Potential for a careful night,
Moments hold promises till Final says "be",
Types guide destiny — no flags, just glee. ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main changes: manual clarity improvements and navigation additions to Getting Started are primary throughout.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/review-chapter-one-s0e8O

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 and usage tips.

@claude

claude Bot commented Mar 24, 2026

Copy link
Copy Markdown

PR Review

This is a documentation-only PR. No security, performance, or test coverage concerns apply. Review focuses on accuracy, consistency, and reader experience.

Overall Assessment

The changes are well-motivated and address real confusion points. The English and Japanese versions are correctly kept in sync. A few items worth discussing:


Positives

  • Ch1 DeletedUser resolution — Answering the opening question within the chapter itself is a significant UX improvement. Previously, readers were told to press forward to find out; now the payoff is immediate.
  • Ch3 property-reading fix — The old "no one touches those properties" was factually wrong and potentially confusing for developers trying to understand the data flow. The fix is accurate.
  • BeenProcessed → BeenConfirmed — Better demonstrates domain-specificity, which is a core framework value.
  • Terminology unification — Replacing "destiny marker" with "Reason object" throughout tutorial + ch5 + ch8 removes an extra term readers had to track.

Issues

1. PR title/description don't match actual scope

The title says "chapters 1, 3, and 4" but the PR also modifies ch5, ch8, and the tutorial (6 chapters + tutorial in total). This is minor but could cause confusion when reading git history.

2. #[Be()] argument semantics in Ch5

Before:

#[Be([ApprovedApplication::class, RejectedApplication::class])]

After:

#[Be([ApprovalNotification::class, RejectionNotification::class])]

The $being union type is Approved|Rejected, but #[Be()] now lists ApprovalNotification|RejectionNotification. These are different layers — the Reason objects vs. the Final destination classes. Is the #[Be()] attribute actually supposed to list the next destination classes (Final layer) rather than the Reason types? If so, the before-state was a bug (listing Reason types in #[Be()]), and this fix is correct — but the explanation could be more explicit about why the two lists differ.

3. Very short Reason class names (Approved, Rejected)

These are generic enough to risk namespace collisions in real applications. The tutorial uses Emergency and Observation which are also short, but this example might benefit from a note that in practice these would live in a Reason\ namespace (as the tutorial's file tree shows). Minor concern since this is illustrative code.

4. $approval->getEmail() in Ch5 example

$mailer->send($approval->getEmail(), 'Approved!');

The Approved Reason object now carries $documents and $score (from its constructor call), not an email. getEmail() implies email access, which is not obviously derivable from $documents. A small note or adjusted method name would avoid reader confusion about where the email comes from.


Minor / Nits

  • The $becoming forward reference added in Ch4 points to 04a-becoming.html — confirmed the file exists, so the link is valid. ✓
  • EN/JA symmetry is maintained across all 12 files. ✓
  • All internal cross-links use .html extensions per CLAUDE.md conventions. ✓

@koriym koriym changed the title Fix reader confusion points in chapters 1, 3, and 4 Improve manual clarity: resolve confusion points and add navigation Mar 24, 2026
@koriym koriym changed the title Improve manual clarity: resolve confusion points and add navigation Improve manual clarity and add Getting Started navigation Mar 24, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@manuals/1.0/en/04-final-objects.md`:
- Line 53: The text incorrectly calls `$been` a "class" — update the sentence to
say the `$been` property uses an application-defined, domain-specific type;
e.g., rephrase to: "The `$been` property uses an application-defined,
domain-specific type: `SuccessfulOrder` may use `BeenConfirmed`, `FailedOrder`
may use `BeenRejected`, a `DeletedUser` may use `BeenDeleted`." Ensure
references to `$been`, SuccessfulOrder, BeenConfirmed, FailedOrder,
BeenRejected, DeletedUser, and BeenDeleted remain as examples.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b93dfa23-bac2-4754-a850-6487a952ad3b

📥 Commits

Reviewing files that changed from the base of the PR and between 8c330ea and e402c3e.

📒 Files selected for processing (12)
  • manuals/1.0/en/01-overview.md
  • manuals/1.0/en/03-being-classes.md
  • manuals/1.0/en/04-final-objects.md
  • manuals/1.0/en/05-metamorphosis-patterns.md
  • manuals/1.0/en/08-reason-layer.md
  • manuals/1.0/en/tutorial.md
  • manuals/1.0/ja/01-overview.md
  • manuals/1.0/ja/03-being-classes.md
  • manuals/1.0/ja/04-final-objects.md
  • manuals/1.0/ja/05-metamorphosis-patterns.md
  • manuals/1.0/ja/08-reason-layer.md
  • manuals/1.0/ja/tutorial.md

Comment thread manuals/1.0/en/04-final-objects.md Outdated
claude added 2 commits March 24, 2026 07:43
- Ch4: "$been class" → "$been property uses a domain-specific type"
  (CodeRabbit review feedback)
- Ch5: Replace $approval->getEmail() with $approval->documents and
  $approval->score to match Approved constructor args ($documents, $score)

https://claude.ai/code/session_01SKnc7oHPsyYZU3JkSRBi4T
The previous fix replaced getEmail() with $approval->documents, but
documents (array) is not a valid mailer recipient. Add $email as an
Input to ApplicationReview and pass it through Approved/Rejected
Reason objects so the code example is internally consistent.

https://claude.ai/code/session_01SKnc7oHPsyYZU3JkSRBi4T

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
manuals/1.0/ja/04-final-objects.md (1)

80-80: Optional: Consider simplifying the phrasing.

The static analysis tool suggests that "複数の最終形態を持つことができます" could be streamlined to "複数の最終形態を持ちます" to reduce redundancy. This is a minor stylistic point and does not affect correctness.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@manuals/1.0/ja/04-final-objects.md` at line 80,
修正箇所は「オブジェクトはその性質によって複数の最終形態を持つことができます。」という文で、冗長な語尾を「オブジェクトはその性質によって複数の最終形態を持ちます。」に置き換えてください(該当テキスト内の`$becoming`の説明とリンク(次章
./04a-becoming.html)周辺の文脈はそのまま維持してください)。
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@manuals/1.0/ja/04-final-objects.md`:
- Line 80:
修正箇所は「オブジェクトはその性質によって複数の最終形態を持つことができます。」という文で、冗長な語尾を「オブジェクトはその性質によって複数の最終形態を持ちます。」に置き換えてください(該当テキスト内の`$becoming`の説明とリンク(次章
./04a-becoming.html)周辺の文脈はそのまま維持してください)。

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 59b2c96e-eb47-4ba8-a714-b9e76d7ab5d6

📥 Commits

Reviewing files that changed from the base of the PR and between e402c3e and bc48e13.

📒 Files selected for processing (4)
  • manuals/1.0/en/04-final-objects.md
  • manuals/1.0/en/05-metamorphosis-patterns.md
  • manuals/1.0/ja/04-final-objects.md
  • manuals/1.0/ja/05-metamorphosis-patterns.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • manuals/1.0/en/05-metamorphosis-patterns.md

Expand chapter 8 to cover the pattern where Reason returns Potential
objects for atomic multi-operation coordination, introducing Moment
and be() within the Reason context rather than as a separate chapter.

https://claude.ai/code/session_01SKnc7oHPsyYZU3JkSRBi4T

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (6)
manuals/1.0/ja/05-metamorphosis-patterns.md (1)

46-64: Consider showing the Reason class definitions.

Lines 60-61 construct Approved and Rejected with parameters, and line 81 accesses their properties ($approval->email, $approval->score). However, the class definitions aren't shown in the example.

While the tutorial demonstrates the simplest case with empty Reason classes (Emergency/Observation), this example uses data-carrying Reason objects—a more advanced pattern. Showing the Reason class definitions would help readers understand how to implement this pattern:

// Example Reason class definitions (could be added after line 64)
final readonly class Approved {
    public function __construct(
        public string $email,
        public float $score
    ) {}
}

final readonly class Rejected {
    public function __construct(
        public string $email,
        public array $reasons
    ) {}
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@manuals/1.0/ja/05-metamorphosis-patterns.md` around lines 46 - 64, The
example constructs data-carrying Reason objects (Approved, Rejected) but their
class definitions are missing; add simple readonly classes for Approved and
Rejected (referenced by ApplicationReview) showing their public properties and
constructors—e.g., Approved with public string $email and public float $score,
and Rejected with public string $email and public array $reasons—so readers can
see how those payloads are shaped and accessed (used later as $approval->email
and $approval->score).
manuals/1.0/en/08-reason-layer.md (5)

161-173: Consider showing the PaymentCapture class definition.

The example instantiates PaymentCapture with three arguments (lines 167-171), but readers never see this class's structure. Without knowing its constructor signature or how it implements the deferred capture pattern, the example might be confusing.

📝 Suggested addition before or after this code block
final readonly class PaymentCapture
{
    public function __construct(
        public string $authorizationCode,
        public int $amount,
        private \Closure $captureOperation,
    ) {}

    public function be(): void
    {
        ($this->captureOperation)();
    }
}

This shows readers that a Potential holds both immediate data ($authorizationCode, $amount) and a deferred operation ($captureOperation) that executes in be().

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@manuals/1.0/en/08-reason-layer.md` around lines 161 - 173, Add a short
PaymentCapture class definition to accompany the PaymentGateway::authorize
example: define final readonly class PaymentCapture with a constructor accepting
string $authorizationCode, int $amount and a private \Closure $captureOperation,
expose the authorizationCode and amount as public properties, and provide a
method (e.g., be() or capture()) that invokes ($this->captureOperation)() to
demonstrate the deferred capture behavior; reference PaymentCapture in the
example so readers can see the constructor signature and how the deferred
operation is executed.

150-238: Consider cross-referencing the $been property pattern from Chapter 4.

This new Potential/Moment/be() method pattern is architecturally distinct from the $been property pattern shown in Chapter 4 (Final Objects). That chapter shows Finals holding a $been property (e.g., BeenConfirmed, BeenRejected) as evidence of completion, while this chapter introduces Moments with a be() method for atomic commit coordination.

Readers might benefit from understanding when to use each pattern:

  • $been property: Evidence of what has already completed (past perfect)
  • be() method on Moments: Deferred commit for atomic multi-operation coordination
📝 Suggested addition

Consider adding a brief note at the beginning of this section (around line 152):

> **Note**: This pattern complements the `$been` property pattern shown in [Final Objects](./04-final-objects.html). Use `$been` to record evidence of completion; use Moment's `be()` method when multiple external operations must commit atomically.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@manuals/1.0/en/08-reason-layer.md` around lines 150 - 238, Add a brief
cross-reference note at the start of the Potential/Moment section clarifying how
this pattern relates to the $been property from Chapter 4: explain that $been
properties (e.g., BeenConfirmed/BeenRejected) are evidence of completed state
while Moments with a be() method (e.g., PaymentCompleted->be(),
PaymentCapture->be()) are for deferred atomic commits across multiple external
operations; place this note near the top of the section (around the existing
discussion starting “Potential: Prepared but Uncommitted”) and link to Chapter 4
(Final Objects) so readers know when to prefer $been vs. be().

68-69: Consider clarifying the attribute used for the $being pattern.

The explanation states Reason objects can serve as "#[Inject] (providing transcendent capabilities) or $being (determining destiny)," but the code examples above (lines 47, 59) show #[Input] ExpressShipping $being and #[Input] StandardShipping $being—using #[Input], not #[Inject].

Based on learnings, when a Reason object is used as $being for type-based routing, it should use #[Input] to participate in framework type matching. The current wording might lead readers to think they should write #[Inject] $being, which would bypass type matching entirely.

📝 Suggested clarification
-Any Reason object can serve as either `#[Inject]` (providing transcendent capabilities) or `$being` (determining destiny). The difference is not in the object itself, but in how it is used. A `JTASProtocol` that evaluates patients as `#[Inject]` in one context could determine destiny as `$being` in another.
+Any Reason object can serve as either `#[Inject]` (providing transcendent capabilities) or `#[Input] $being` (determining destiny). The difference is not in the object itself, but in how it is used. A `JTASProtocol` that evaluates patients as `#[Inject]` in one context could determine destiny as `#[Input] $being` in another.

Based on learnings: In Be Framework, the "Reason as $being" pattern intentionally uses #[Input] (not #[Inject]) when a Reason/capability object needs to participate in framework type matching to determine the transformation destination.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@manuals/1.0/en/08-reason-layer.md` around lines 68 - 69, The documentation
wording is ambiguous about which attribute to use when a Reason object is acting
as $being for type-based routing; update the text to state that when a Reason
object must participate in framework type matching (the "$being" pattern) it
should be annotated with #[Input] rather than #[Inject], and clarify that
#[Inject] provides transcendent capabilities but bypasses type matching;
reference the existing symbols Reason, $being, #[Input], #[Inject], and
JTASProtocol to show the distinction and mention that the examples using
#[Input] ExpressShipping and #[Input] StandardShipping illustrate the correct
usage.

233-234: Clarify the failure propagation mechanism.

The statement "If any Moment cannot be created (because its Reason failed), the Final Object is never constructed" describes the behavior but doesn't explain how construction failure propagates. Does the Reason throw an exception? Does the DI container prevent construction?

Without this detail, readers might not understand how to implement the "all-or-nothing" guarantee in their own Reason classes.

💡 Suggested clarification

Consider adding a sentence like:

 If any Moment cannot be created (because its Reason failed), the Final Object is never constructed.
+Construction failure propagates through exceptions—if a Reason method throws, the Moment constructor fails, preventing the Final Object from being created.
 If all Moments exist, `be()` commits every deferred operation.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@manuals/1.0/en/08-reason-layer.md` around lines 233 - 234, Clarify the
failure propagation by adding a sentence after the existing line that explains
that failure is propagated via exceptions from Reason implementations which
bubble up to the orchestration layer (the DI/creation process) so construction
of subsequent Moments and the Final Object is aborted, and that be() only
commits when no exceptions occurred (i.e., it short-circuits on any thrown error
from a Reason); reference the terms Moment, Reason, Final Object, and the be()
commit behavior to make it clear that Reasons must throw on failure and the
container/coordination logic must catch and prevent commit to guarantee the
all-or-nothing semantics.

194-195: Note the consistent use of #[Input] with primitives in the tutorial sections.

The pattern of using #[Input] with primitives (string $cardNumber, int $amount) is consistent with how tutorial.md demonstrates Moments. While the framework also shows value objects (Money, CreditCard) with #[Input] in other examples, and demos.md uses custom attributes (#[CardNumber], #[Amount]) with primitives as an alternative, the current approach is valid and pedagogically clear for an introductory example.

If alignment with the framework's value object philosophy is desired, consider using CardNumber and Money types instead, but this is not required—the current implementation is consistent with the documented patterns.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@manuals/1.0/en/08-reason-layer.md` around lines 194 - 195, The tutorial
currently uses the #[Input] attribute on primitive types (#[Input] public string
$cardNumber, #[Input] public int $amount) which is consistent with other
tutorial examples; you can leave these as-is for clarity. If you prefer
alignment with the framework’s value-object approach, replace the primitive
types with the framework types (e.g., use Money and CreditCard for amounts and
card numbers) or apply the custom attributes shown elsewhere (#[CardNumber],
#[Amount]) but this change is optional—no code change is required unless you
decide to adopt value objects or custom input attributes for consistency.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@manuals/1.0/en/08-reason-layer.md`:
- Around line 189-206: The document references MomentInterface (used by the
PaymentCompleted class and its be() method) but never defines or links to it;
add a short definition or an explicit reference stating where MomentInterface is
defined and what it requires (e.g., that it declares public function be():
void), and update the surrounding text to either include the interface snippet
before the PaymentCompleted example or note that the framework provides
MomentInterface and point to its location.

---

Nitpick comments:
In `@manuals/1.0/en/08-reason-layer.md`:
- Around line 161-173: Add a short PaymentCapture class definition to accompany
the PaymentGateway::authorize example: define final readonly class
PaymentCapture with a constructor accepting string $authorizationCode, int
$amount and a private \Closure $captureOperation, expose the authorizationCode
and amount as public properties, and provide a method (e.g., be() or capture())
that invokes ($this->captureOperation)() to demonstrate the deferred capture
behavior; reference PaymentCapture in the example so readers can see the
constructor signature and how the deferred operation is executed.
- Around line 150-238: Add a brief cross-reference note at the start of the
Potential/Moment section clarifying how this pattern relates to the $been
property from Chapter 4: explain that $been properties (e.g.,
BeenConfirmed/BeenRejected) are evidence of completed state while Moments with a
be() method (e.g., PaymentCompleted->be(), PaymentCapture->be()) are for
deferred atomic commits across multiple external operations; place this note
near the top of the section (around the existing discussion starting “Potential:
Prepared but Uncommitted”) and link to Chapter 4 (Final Objects) so readers know
when to prefer $been vs. be().
- Around line 68-69: The documentation wording is ambiguous about which
attribute to use when a Reason object is acting as $being for type-based
routing; update the text to state that when a Reason object must participate in
framework type matching (the "$being" pattern) it should be annotated with
#[Input] rather than #[Inject], and clarify that #[Inject] provides transcendent
capabilities but bypasses type matching; reference the existing symbols Reason,
$being, #[Input], #[Inject], and JTASProtocol to show the distinction and
mention that the examples using #[Input] ExpressShipping and #[Input]
StandardShipping illustrate the correct usage.
- Around line 233-234: Clarify the failure propagation by adding a sentence
after the existing line that explains that failure is propagated via exceptions
from Reason implementations which bubble up to the orchestration layer (the
DI/creation process) so construction of subsequent Moments and the Final Object
is aborted, and that be() only commits when no exceptions occurred (i.e., it
short-circuits on any thrown error from a Reason); reference the terms Moment,
Reason, Final Object, and the be() commit behavior to make it clear that Reasons
must throw on failure and the container/coordination logic must catch and
prevent commit to guarantee the all-or-nothing semantics.
- Around line 194-195: The tutorial currently uses the #[Input] attribute on
primitive types (#[Input] public string $cardNumber, #[Input] public int
$amount) which is consistent with other tutorial examples; you can leave these
as-is for clarity. If you prefer alignment with the framework’s value-object
approach, replace the primitive types with the framework types (e.g., use Money
and CreditCard for amounts and card numbers) or apply the custom attributes
shown elsewhere (#[CardNumber], #[Amount]) but this change is optional—no code
change is required unless you decide to adopt value objects or custom input
attributes for consistency.

In `@manuals/1.0/ja/05-metamorphosis-patterns.md`:
- Around line 46-64: The example constructs data-carrying Reason objects
(Approved, Rejected) but their class definitions are missing; add simple
readonly classes for Approved and Rejected (referenced by ApplicationReview)
showing their public properties and constructors—e.g., Approved with public
string $email and public float $score, and Rejected with public string $email
and public array $reasons—so readers can see how those payloads are shaped and
accessed (used later as $approval->email and $approval->score).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2aab57d7-ff08-45f4-abea-038b8e1869b9

📥 Commits

Reviewing files that changed from the base of the PR and between bc48e13 and b091060.

📒 Files selected for processing (4)
  • manuals/1.0/en/05-metamorphosis-patterns.md
  • manuals/1.0/en/08-reason-layer.md
  • manuals/1.0/ja/05-metamorphosis-patterns.md
  • manuals/1.0/ja/08-reason-layer.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • manuals/1.0/ja/08-reason-layer.md
  • manuals/1.0/en/05-metamorphosis-patterns.md

Comment thread manuals/1.0/en/08-reason-layer.md
Address review feedback: MomentInterface was referenced but never
defined. Added the interface snippet before the PaymentCompleted
example in both EN and JA versions.

https://claude.ai/code/session_01SKnc7oHPsyYZU3JkSRBi4T

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@manuals/1.0/en/08-reason-layer.md`:
- Around line 161-182: The docs reference a PaymentCapture type but never
defines it; add a small immutable class named PaymentCapture that stores the
authorizationCode and amount and accepts a deferred capture operation (e.g. a
Closure) in the constructor, expose the authorizationCode (and amount) as
accessible properties, and implement a be() method that invokes the stored
capture operation to perform the deferred capture; ensure the constructor
parameter names match those used when new PaymentCapture(...) is called in
PaymentGateway::authorize so the example compiles and the behavior is clear.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 53f719a6-8700-4be7-9d81-8291e7fbf155

📥 Commits

Reviewing files that changed from the base of the PR and between b091060 and 7db7ba5.

📒 Files selected for processing (2)
  • manuals/1.0/en/08-reason-layer.md
  • manuals/1.0/ja/08-reason-layer.md
✅ Files skipped from review due to trivial changes (1)
  • manuals/1.0/ja/08-reason-layer.md

Comment on lines +161 to +182
final class PaymentGateway
{
public function authorize(string $cardNumber, int $amount): PaymentCapture
{
$authCode = $this->api->authorize($cardNumber, $amount);

return new PaymentCapture(
$authCode,
$amount,
fn () => $this->api->capture($authCode, $amount),
);
}
}
```

`PaymentCapture` is a Potential—it holds the authorization code and a deferred capture operation. The payment is authorized but not yet captured. Calling `be()` commits it:

```php
$capture = $gateway->authorize($cardNumber, $amount);
$capture->authorizationCode; // Available immediately
$capture->be(); // Commits the capture
```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Define the PaymentCapture class structure.

The example shows PaymentCapture being constructed (lines 167-171) and used (lines 180-181), but never defines the class itself. Readers need to see how PaymentCapture holds the authorization code and implements be() to understand the Potential pattern.

📖 Suggested addition after line 173

Add the PaymentCapture class definition before the usage example:

final readonly class PaymentCapture
{
    public function __construct(
        public string $authorizationCode,
        public int $amount,
        private \Closure $captureOperation,
    ) {}

    public function be(): void
    {
        ($this->captureOperation)();
    }
}

Then the usage example at lines 178-182 becomes clear: the authorization code is immediately available as a public property, and calling be() executes the deferred capture closure.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@manuals/1.0/en/08-reason-layer.md` around lines 161 - 182, The docs reference
a PaymentCapture type but never defines it; add a small immutable class named
PaymentCapture that stores the authorizationCode and amount and accepts a
deferred capture operation (e.g. a Closure) in the constructor, expose the
authorizationCode (and amount) as accessible properties, and implement a be()
method that invokes the stored capture operation to perform the deferred
capture; ensure the constructor parameter names match those used when new
PaymentCapture(...) is called in PaymentGateway::authorize so the example
compiles and the behavior is clear.

@koriym
koriym merged commit f8d6bbf into master Mar 24, 2026
7 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.

2 participants