Skip to content

Commit 8fa741b

Browse files
committed
docs(readme): 영문 README에 협업 수명 주기 및 관측성 시각적 증명 추가
직전 커밋 09fbb3b6의 한글판 개선을 영문판에 동기화한다. - When Requirements Change — Order.Cancel() 정책 확장 시나리오로 사람/AI/프레임워크 역할 분담 구체화 - At 2 AM, What Actually Appears on Your Screen — InvalidOrderStatusTransition 실패를 JSON 로그 + Mermaid 시퀀스 다이어그램으로 시각화, 3-Pillar trace_id 전파 증명
1 parent 09fbb3b commit 8fa741b

1 file changed

Lines changed: 103 additions & 0 deletions

File tree

README.md

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,43 @@ This is how AI generates exception-free, safe code structures automatically.
125125
>
126126
> The framework's **automatic error classification + structured context logs + dashboards** — built into every Command/Query — translate code state into human language.
127127
128+
### When Requirements Change — Humans Update Text, AI Rebuilds the Plumbing
129+
130+
> The CS team urgently requests **"Allow change-of-mind cancellation within 24h after delivery"** to match a competitor's policy. The current rule permits cancellation only in `Pending/Confirmed` states ([`Order.Cancel()` in the ecommerce-ddd sample](./Docs.Site/src/content/docs/samples/ecommerce-ddd/index.md)).
131+
132+
| Aspect | Before | After |
133+
|--------|--------|-------|
134+
| Allowed state transitions | `Pending/Confirmed → Cancelled` | The above + `Delivered → Cancelled` (only when `DeliveredAt + 24h > now` & `reason = ChangeOfMind`) |
135+
| `Cancel` method signature | `Cancel() : Fin<Unit>` | `Cancel(CancellationReason reason) : Fin<Unit>` |
136+
| Domain Event | `CancelledEvent(OrderId, OrderLines)` | The above + `CancellationReason Reason` field |
137+
| New Union type || `CancellationReason = ChangeOfMind \| CustomerIssue \| Fraud` |
138+
139+
**The 3-step collaboration flow**:
140+
141+
1. **Human (architect)** — adds one line to PRD `§Order.Cancellation`:
142+
> "Also allow `Delivered` orders to be cancelled for change-of-mind within 24h of delivery"
143+
144+
2. **AI (`domain-develop` skill)** — auto-generates/updates five artifacts:
145+
- Add `("Delivered", Seq("Cancelled"))` to `OrderStatus.AllowedTransitions`
146+
- Create a new `CancellationReason` Union (3-variant sealed records)
147+
- Inject the time-window Specification into `Order.Cancel()`
148+
- Extend `CancelledEvent` with a `CancellationReason` field
149+
- Auto-add boundary-value unit tests (`23h59m` / `24h00m` / `24h01m`)
150+
151+
3. **Framework (triple verification gates)** — blocks regressions at build time:
152+
- Architecture rule tests: verify `sealed`, record immutability, `Fin<T>` return types on the Union
153+
- Contract regression tests: confirm the `Pending/Confirmed → Cancelled` path still holds
154+
- Type system: enforce the new `Cancel()` signature at every call site at compile time
155+
156+
> **Developers never open the `Fin<Unit>` pipeline inside `Order.Cancel()`.**
157+
> Just edit the text requirement. AI rebuilds state-transition rules, Unions, events, and tests; architectural integrity is guaranteed by [21+ rule tests](#gate-1-architecture-rule-tests--structural-integrity).
158+
159+
| Role | Responsibility | In this scenario |
160+
|------|---------------|------------------|
161+
| **Developer** | Architect — defines business rules and boundaries | Specify the "24h post-delivery cancellation" policy in text |
162+
| **AI Agent** | Plumber — regenerates state machines, Unions, events, tests | Extend `OrderStatus`, create `CancellationReason`, add tests automatically |
163+
| **Framework** | Safety net — blocks structural regression | Validates architecture, types, and existing contracts automatically |
164+
128165
## How AI Breaks Through the Problems
129166

130167
### From Problem to Code — Structure Connected by AI
@@ -443,6 +480,72 @@ Functorium provides unified observability (Logging, Metrics, Tracing) based on O
443480

444481
The Application layer (EventId 1001–1004) and Adapter layer (EventId 2001–2004) use **identical `request.*` / `response.*` / `error.*` naming**, enabling end-to-end request flow tracking with a single dashboard query.
445482

483+
### At 2 AM, What Actually Appears on Your Screen
484+
485+
Here we visualize how the "24h post-delivery cancellation" policy from the [requirements-change scenario](#when-requirements-change--humans-update-text-ai-rebuilds-the-plumbing) fails at its boundary in production.
486+
487+
> `POST /orders/{id}/cancel` (reason=`ChangeOfMind`). The order was delivered **25 hours ago** — past the 24h window. No exception is thrown; instead, a structured failure response classified as `error.type = "expected"` is returned.
488+
489+
**What actually lands in the log** (this is literally what Seq or Grafana Loki displays):
490+
491+
```json
492+
{
493+
"@t": "2026-04-20T02:14:33.0421Z",
494+
"EventId": 1002,
495+
"request.category": "OrderManagement",
496+
"request.name": "CancelOrderCommand",
497+
"request_id": "01HXK8Z6Q3N9V7B4M2C1D5E8F0",
498+
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
499+
"ctx.order_id": "01HXK5M2P8X7...",
500+
"ctx.customer_id": "01HXK5M2P8Y1...",
501+
"ctx.order_status_from": "Delivered",
502+
"ctx.order_status_to": "Cancelled",
503+
"ctx.cancellation_reason": "ChangeOfMind",
504+
"ctx.hours_since_delivery": 25,
505+
"error.type": "expected",
506+
"error.codes": ["DomainErrors.Order.InvalidOrderStatusTransition"],
507+
"error.message": "Cancel window (24h) exceeded for ChangeOfMind",
508+
"elapsed_ms": 7,
509+
"status": "Failed"
510+
}
511+
```
512+
513+
**How the same `trace_id` / `request_id` propagate across the three pillars**:
514+
515+
```mermaid
516+
sequenceDiagram
517+
participant C as Client
518+
participant EP as FastEndpoint
519+
participant PL as UsecasePipeline
520+
participant AG as Order Aggregate
521+
participant OT as OpenTelemetry SDK
522+
523+
C->>EP: POST /orders/{id}/cancel
524+
EP->>PL: trace_id=4bf9... + request_id=01HXK...
525+
PL->>AG: Cancel(reason=ChangeOfMind)
526+
AG-->>PL: Fin.Fail(InvalidOrderStatusTransition)
527+
PL->>OT: Log (EventId=1002, error.type="expected")
528+
PL->>OT: Metric (usecase_failed{error_type="expected"}+1)
529+
PL->>OT: Trace span(status=ERROR, tags: ctx.order_id, ctx.hours_since_delivery=25)
530+
PL-->>EP: FinResponse.Fail (HTTP 409)
531+
EP-->>C: error_code="DomainErrors.Order.InvalidOrderStatusTransition"
532+
533+
Note over OT: All three pillars share the same trace_id/request_id<br/>→ one filter correlates Logs, Metrics, and Traces
534+
```
535+
536+
**Traditional exception model vs. Functorium `Fin` model**:
537+
538+
| Traditional exception model (OOP) | Functorium `Fin` model |
539+
|---|---|
540+
| `throw new InvalidOperationException(...)` | `Fin.Fail<Unit>(DomainError.For<Order>(...))` |
541+
| Stack trace (noise) | `error.codes[]` + `ctx.*` (signal) |
542+
| Risk of broken process flow | Type-safe failure value — flow is preserved |
543+
| Manual log re-assembly required | `request_id` / `trace_id` auto-propagated |
544+
| Business errors and system failures mixed | `error.type ∈ {expected, exceptional, aggregate}` — dashboard-filterable |
545+
546+
> **"No stack trace = undebuggable" is false.**
547+
> Instead of a stack trace, the framework records **which domain rule was broken, in which state, and why** through the `error.codes` array and `ctx.*` business context. A single glance at `ctx.hours_since_delivery=25` reveals the root cause. The same `request_id` lets you cross-filter Logs, Metrics, and Traces for the same event.
548+
446549
For detailed specifications and guides, see the documentation site:
447550
- [Observability Specification](./Docs.Site/src/content/docs/spec/08-observability.md) — Field/Tag structure, ctx.* 3-Pillar Enrichment, Meter/Instrument specification
448551
- [Logging Guide](./Docs.Site/src/content/docs/guides/observability/19-observability-logging.md) — Structured logging detailed guide

0 commit comments

Comments
 (0)