Initial commit
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
---
|
||||
name: effect-review
|
||||
description: Review code against Effect Patterns best practices
|
||||
severity-default: medium
|
||||
tools: [Read, Grep, glob, get_diagnostics, Bash, oracle]
|
||||
---
|
||||
|
||||
# Effect Patterns Code Review
|
||||
|
||||
Review the changed files to ensure they follow Effect Patterns best practices according to the canonical `@docs/Effect-Patterns-Rules.md`.
|
||||
|
||||
## Instructions for the agent
|
||||
1. **Run the AST Analyzer**: You MUST use `Bash` to run `bun run scripts/effect-analyzer/bin/check.ts <filepath>` on each modified TypeScript file. Report any warnings or errors it finds.
|
||||
2. Read the relevant parts of `@docs/Effect-Patterns-Rules.md` if you are unsure.
|
||||
3. Focus exclusively on Effect-TS usage. Do not comment on general formatting unless it obscures Effect best practices.
|
||||
4. Point out any code that uses `Promise.then` or `try/catch` incorrectly instead of `Effect.tryPromise` or `Effect.try`.
|
||||
5. Flag usage of unstructured errors (`throw new Error()`) instead of typed errors (`Effect.fail`).
|
||||
|
||||
## Key aspects to check manually
|
||||
|
||||
If there are any violations, report them and suggest the Effect-native alternative.
|
||||
@@ -0,0 +1,36 @@
|
||||
# Design Mode: Coder
|
||||
|
||||
You are now in **Coder Mode** for the Type-Driven Functional Domain-Driven Design (TDFDDD) process.
|
||||
|
||||
## Your Role
|
||||
You are the **Implementer/Coder**. The user is the **Domain Expert**.
|
||||
|
||||
## Your Behavior
|
||||
1. **Drive the technical process.** You will walk through the phases (Event Storming -> Domain Modeling -> Contract -> Implementation).
|
||||
2. **Ask clarifying questions about the business domain.** Do not assume. Ask things like:
|
||||
* "What happens if the truck is already sealed?"
|
||||
* "Can a package ever be partially loaded?"
|
||||
* "What are all the reasons a load could fail?"
|
||||
3. **Produce artifacts.** After each phase, output the F# pseudo-code types and signatures.
|
||||
4. **Pause for review.** After Phase 3 (Domain Modeling), stop and ask the user to validate the types before proceeding to implementation.
|
||||
|
||||
## The Process
|
||||
Follow the protocol in `docs/core-rules/topics/domain-modeling.md`.
|
||||
|
||||
## Output Location
|
||||
Save all design artifacts to `design/<feature-name>/`:
|
||||
- `01-event-storming.md` — Phase 1 output
|
||||
- `02-domain-model.md` — Phase 2-3 output (F# types)
|
||||
- `03-contract.md` — Phase 4 output (Final signatures)
|
||||
|
||||
## Output Format
|
||||
For each phase, produce a Markdown code block with F# pseudo-code. Example:
|
||||
```fsharp
|
||||
type PackageLoaded = {
|
||||
TruckId: TruckId
|
||||
Package: Package
|
||||
}
|
||||
```
|
||||
|
||||
## Start
|
||||
Begin by asking: **"What feature or workflow are we designing today? I'll create a folder in `design/` for it."**
|
||||
@@ -0,0 +1,33 @@
|
||||
# Design Mode: Mentor
|
||||
|
||||
You are now in **Mentor Mode** for the Type-Driven Functional Domain-Driven Design (TDFDDD) process.
|
||||
|
||||
## Your Role
|
||||
You are the **Mentor/Reviewer**. The user is the **Learner** (practicing the design process).
|
||||
|
||||
## Your Behavior
|
||||
1. **Guide, don't drive.** Let the user produce the artifacts. Your job is to critique and refine.
|
||||
2. **Ask Socratic questions.** When you see a gap, ask:
|
||||
* "What happens if the input is invalid?"
|
||||
* "Is there another state the entity could be in?"
|
||||
* "How would you handle this edge case?"
|
||||
3. **Point out violations.** If the user's design violates the rules (e.g., impure logic in a Policy, primitive obsession), call it out explicitly.
|
||||
4. **Validate progress.** After each phase, confirm what is correct and suggest improvements.
|
||||
|
||||
## The Process
|
||||
The user should follow the protocol in `docs/core-rules/topics/domain-modeling.md`. Remind them of the current phase if they get lost.
|
||||
|
||||
## Feedback Format
|
||||
Use this structure for feedback:
|
||||
* ✅ **Correct:** [What they did well]
|
||||
* ⚠️ **Consider:** [Suggestions or missing pieces]
|
||||
* ❌ **Issue:** [Violations of the rules]
|
||||
|
||||
## Output Location
|
||||
Remind the user to save artifacts to `design/<feature-name>/`:
|
||||
- `01-event-storming.md` — Phase 1 output
|
||||
- `02-domain-model.md` — Phase 2-3 output (F# types)
|
||||
- `03-contract.md` — Phase 4 output (Final signatures)
|
||||
|
||||
## Start
|
||||
Begin by saying: **"Let's practice the design process. What feature are you working on? Create a folder in `design/<feature-name>/` and start with Phase 1: Event Storming — describe the user story and identify the Command and Events."**
|
||||
@@ -0,0 +1,28 @@
|
||||
# Agent Core Rules
|
||||
|
||||
This directory contains the compressed rule set for agents.
|
||||
The human-facing explanations live in `docs/` and should be treated as the canonical rationale and teaching material.
|
||||
|
||||
## 1. [Global Context](./global-context.md)
|
||||
Read this first for the project-wide operating constraints.
|
||||
|
||||
## 2. Topics
|
||||
|
||||
- **[Architecture](./topics/architecture.md)**: Layer boundaries and purity rules.
|
||||
- **[Data Modeling](./topics/data-modeling.md)**: Schema, rich types, and immutability.
|
||||
- **[Workflows](./topics/workflows.md)**: Effect orchestration and workflow constraints.
|
||||
- **[Testing](./topics/testing.md)**: Testing heuristics and layer-based testing.
|
||||
- **[Naming](./topics/naming.md)**: Naming rules for code and design artifacts.
|
||||
- **[Design Process](./topics/design-process.md)**: The agent-facing overlay for TDFDDD artifact generation.
|
||||
|
||||
## Canonical human docs
|
||||
|
||||
When you need the explanation behind a rule, prefer these pages:
|
||||
|
||||
- `docs/README.md`
|
||||
- `docs/explanation/tdfddd-manifesto.md`
|
||||
- `docs/explanation/tdfddd-protocol.md`
|
||||
- `docs/explanation/architecture/index.md`
|
||||
- `docs/tutorials/worked-example-truck-loading.md`
|
||||
- `docs/reference/review-checklist.md`
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
# Global Context & Core Philosophy
|
||||
|
||||
**Root Philosophy**: Functional Domain-Driven Design (Scott Wlaschin).
|
||||
*Make illegal states unrepresentable. Use types as documentation.*
|
||||
|
||||
## Guiding Preference
|
||||
- Prefer correctness, simplicity, and elegance over backwards compatibility.
|
||||
- Do not preserve awkward APIs or structures unless there is a clear, explicit requirement to do so.
|
||||
|
||||
## 1. The Golden Rule: Purity vs. IO
|
||||
- **Domain (Pure)**: `src/domain/models` and `src/policies` MUST be 100% pure. Deterministic, no side effects, no service dependency.
|
||||
- **Workflows (Impure)**: `src/workflows` orchestrate logic. They verify policies and call Services.
|
||||
- **Services (IO)**: `src/services` handle all I/O (DB, API). They are called *only* by Workflows.
|
||||
|
||||
## 2. Data & Composition
|
||||
- **Immutable**: Never mutate. Return new copies.
|
||||
- **Data-Last**: Functions take data as the last argument to support `pipe`.
|
||||
- **Schema First**: Use `@effect/schema` for all domain objects. No Classes.
|
||||
- **Branded Types**: Use `Brand<"USD">` instead of raw primitives.
|
||||
|
||||
## 3. Error Handling
|
||||
- **Typed Errors**: Use discriminated unions for errors. No generic `throw`.
|
||||
- **Fail Fast**: Validate inputs at the edge (Workflows/Controllers).
|
||||
|
||||
## 4. Structure
|
||||
- `domain/models/`: Schema + Pure Ops (one file per entity or folder with index).
|
||||
- `policies/`: Cross-entity business rules (Pure). Returns Decision objects.
|
||||
- `workflows/`: The "glue". `Effect.gen`, Service wiring.
|
||||
- `services/`: Interfaces (Ports) and Implementations (Adapters).
|
||||
|
||||
## 5. The Design Protocol (TDFDDD)
|
||||
1. **Flow**: Define `Command` (Input) → `Event` (Output).
|
||||
2. **Contract**: Write `(Input) => Effect<Success, Error>` signatures.
|
||||
3. **Partition**: Isolate pure rules (Policies) from side-effects (Services).
|
||||
4. **Model**: Bridge Input to Output with specific types (Success & Failure, `TrustedInput`/`TaintedInput` Wrappers).
|
||||
5. **Assembly**: Implement logic only after types verify.
|
||||
@@ -0,0 +1,37 @@
|
||||
---
|
||||
globs:
|
||||
- "src/**/*.ts"
|
||||
---
|
||||
# Architecture & Purity Rules
|
||||
|
||||
1. **Strict Separation of Concerns**:
|
||||
- **Domain Models**: `src/domain/models`. Pure data + Ops. (Zero dependencies).
|
||||
- **Policies**: `src/policies`. Pure business rules. (Zero dependencies).
|
||||
- **Workflows**: `src/workflows`. Orchestration & I/O. (Depends on Services/Policies).
|
||||
- **Services**: `src/services`. I/O interfaces & adapters.
|
||||
|
||||
2. **The Purity Mandate**:
|
||||
- **Domain & Policies MUST be 100% Pure**. No `Effect.gen`, no `Promise`, no external imports.
|
||||
- **Why**: Guarantees testability and deterministic behavior for complex rules.
|
||||
|
||||
3. **Policies Return Decisions**:
|
||||
- Policies should return rich objects (Discriminated Unions), not booleans.
|
||||
- `const canAccess = (u: User): AccessDecision => ({ allowed: false, reason: "Expired" })`
|
||||
- A pure decision should usually still be a function, but it does **not** always need a top-level `src/policies/` module.
|
||||
- Promote a decision to `src/policies/` only when extraction materially improves **nameability, testability, reuse, or boundary clarity**.
|
||||
- Prefer a local pure function when extraction would only add indirection.
|
||||
|
||||
4. **No Orphaned Logic (Strict Boundaries)**:
|
||||
- **Policies** define *Decisions* (business rules).
|
||||
- **Effect.Schema** defines *Shape* (validation). If a payload fails schema check, it's an infrastructure error (Parse, Don't Validate).
|
||||
- **Workflows** orchestrate logic but MUST NOT contain `if` statements for business rules. Use `Match.value` to branch on a Policy's decision.
|
||||
- **Models** apply pure mathematical state changes without deciding business rules.
|
||||
|
||||
5. **Cross-Module Imports Use Public APIs**:
|
||||
- When code in one module imports from another module, import through that module's public API (`index.ts` or other documented entrypoint).
|
||||
- Do not reach into another module's private internal files from the outside.
|
||||
|
||||
6. **No Business Logic in Services**:
|
||||
- Services are for *capabilities* (Store DB, Send Email), not *decisions*.
|
||||
- ❌ `UserService.createIfAllowed()`
|
||||
- ✅ `Workflow: if (Policy.isAllowed(user)) yield* UserService.create()`
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
globs:
|
||||
- "src/domain/models/**/*.ts"
|
||||
- "src/domain/data/**/*.ts"
|
||||
---
|
||||
# Data Modeling & Schema Rules
|
||||
|
||||
1. **Use Schema.Struct (Not Classes)**: Define data as plain objects with `Schema.Struct` for serializability. Logic goes in separate `Ops` modules.
|
||||
`const Cart = Schema.Struct({ items: Schema.Array(Item) })`
|
||||
|
||||
2. **Branded Primitives**: Always brand IDs and units (Money, Email) to prevent type collisions.
|
||||
`type USD = number & Brand.Brand<"USD">; const price = Brand.nominally(Schema.Number, "USD")(19.99)`
|
||||
|
||||
3. **Schema Validation**: Enforce invariants (regex, range) via `pipe(Schema.filter/pattern)`.
|
||||
`const Email = Schema.String.pipe(Schema.pattern(/^@/), Schema.brand("Email"))`
|
||||
|
||||
4. **Immutability**: Never mutate state. Return new copies using spread syntax.
|
||||
`const add = (c: Cart, i: Item): Cart => ({ ...c, items: [...c.items, i] })`
|
||||
|
||||
5. **Rich Types**: Encode state in types (e.g., `PendingOrder` vs `PaidOrder`) rather than using optional flags.
|
||||
`type Order = PendingOrder | PaidOrder` (Discriminated Union)
|
||||
@@ -0,0 +1,48 @@
|
||||
---
|
||||
globs:
|
||||
- "design/**/*.md"
|
||||
---
|
||||
# Design Process Rules
|
||||
|
||||
This file is the agent-facing overlay for the TDFDDD design process.
|
||||
Use the human docs as the canonical explanation:
|
||||
|
||||
- `docs/explanation/tdfddd-manifesto.md`
|
||||
- `docs/explanation/tdfddd-protocol.md`
|
||||
- `docs/tutorials/worked-example-truck-loading.md`
|
||||
- `docs/reference/design-artifact-template.md`
|
||||
- `docs/reference/review-checklist.md`
|
||||
|
||||
## Required artifact shape
|
||||
|
||||
For each feature design in `design/`, produce artifacts that make these phases explicit:
|
||||
|
||||
1. Story in domain language
|
||||
2. Command and outcomes
|
||||
3. Policy sketch
|
||||
4. Domain model
|
||||
5. Final contract
|
||||
6. Reviewer notes or open questions
|
||||
|
||||
## Design constraints
|
||||
|
||||
- Keep framework and infrastructure terms out of the early design phases.
|
||||
- Prefer explicit state variants over generic objects with broad `status` fields.
|
||||
- Return events or rich decisions, not booleans, when business meaning matters.
|
||||
- Freeze the design before translating it into TypeScript and Effect.
|
||||
- Make the artifact easy for a human reviewer to compare against the truck-loading example and checklist.
|
||||
- When proposing a refactor, require an explicit reason if preserving backwards compatibility would keep a worse design. Otherwise prefer the direct change over compatibility-preserving cruft.
|
||||
|
||||
## Output standard
|
||||
|
||||
A design artifact is only ready when a human reviewer can inspect each phase without inventing missing domain meaning.
|
||||
|
||||
## Security verification expectation
|
||||
|
||||
Security review is a verification gate around the design and implementation work.
|
||||
When the user asks for security review, use the dedicated review-only skills:
|
||||
|
||||
- `tdfddd-design-security-verification` for requirements, domain models, contracts, ADRs, and workflow design
|
||||
- `tdfddd-implementation-security-verification` for changed code and adjacent seams, with optional expanded-surface review
|
||||
|
||||
Treat missing security design information as reviewable findings rather than silently assuming it away.
|
||||
@@ -0,0 +1,186 @@
|
||||
# Domain Modeling
|
||||
|
||||
> **Also known as:** Type-Driven Functional Domain-Driven Design (TDFDDD).
|
||||
> In casual contexts, we call this **Functional Domain Modeling**.
|
||||
|
||||
## Design Artifacts Location
|
||||
All design specs go in the `design/` directory:
|
||||
```
|
||||
design/
|
||||
├── <feature-name>/
|
||||
│ ├── 01-requirements.md # Phase 1: Commands, Events, Story
|
||||
│ ├── 02-domain-model.md # Phase 2-3: Types in F# pseudo-code
|
||||
│ ├── 03-contract.md # Phase 4: Final signatures
|
||||
│ └── notes.md # Optional: Domain expert Q&A, decisions
|
||||
```
|
||||
|
||||
## Philosophy
|
||||
**"Make Illegal States Unrepresentable."**
|
||||
|
||||
Use types to encode business rules. If invalid data cannot be constructed, it cannot cause bugs.
|
||||
|
||||
## The Design Protocol (TDFDDD)
|
||||
|
||||
### Phase 1: Event Storming
|
||||
1. Identify the **Command** (User Intent).
|
||||
2. Identify the **Events** (What Happened: Success/Failure).
|
||||
3. Gather domain context from the expert.
|
||||
|
||||
### Phase 2: Core Sketch
|
||||
1. Draft the Policy signature: `decide : Input -> State -> Result<SuccessEvent, FailureEvent>`
|
||||
2. List the information required to make the decision.
|
||||
|
||||
### Phase 3: Domain Modeling
|
||||
1. **Primitives:** Branded types for units (`Weight`, `Volume`).
|
||||
2. **Compounds:** Group primitives into Structs (`Package`, `TruckCapacity`).
|
||||
3. **Aggregates:** Define State variants (`LoadingTruck | SealedTruck`).
|
||||
4. **Events:** Define Outcomes (`PackageLoaded`, `LoadFailure`).
|
||||
|
||||
### Phase 4: The Contract
|
||||
1. **Policy:** `decide : Input -> State -> Result<SuccessEvent, FailureEvent>` (Pure)
|
||||
2. **Model:** `apply : State -> SuccessEvent -> State` (Pure)
|
||||
3. **Workflow:** `workflow : InputId -> Effect<Response>` (Impure)
|
||||
|
||||
### Phase 5: Implementation
|
||||
1. Translate F# types to Effect Schemas.
|
||||
2. Implement Policy (Pure).
|
||||
3. Implement Workflow: Decide -> Match -> Apply.
|
||||
|
||||
## The Orchestration Pattern
|
||||
|
||||
```typescript
|
||||
const workflow = (id) => Effect.gen(function*(_) {
|
||||
// 1. Gather (IO)
|
||||
const state = yield* _(Repo.get(id));
|
||||
|
||||
// 2. Decide (Pure)
|
||||
const decision = Policy.decide(input, state);
|
||||
|
||||
// 3. Match & Apply
|
||||
return yield* _(Match.value(decision).pipe(
|
||||
Match.when({ _tag: "Success" }, (event) => Effect.gen(function*(_) {
|
||||
const newState = Model.apply(state, event);
|
||||
yield* _(Repo.save(newState));
|
||||
return { success: true };
|
||||
})),
|
||||
Match.when({ _tag: "Failure" }, (err) => Effect.fail(err)),
|
||||
Match.exhaustive
|
||||
));
|
||||
});
|
||||
```
|
||||
|
||||
## Rules
|
||||
1. **Policies are Pure:** No IO, no services, only data in -> decision out.
|
||||
2. **Models are Pure:** State transitions are deterministic.
|
||||
3. **Workflows are Impure:** They orchestrate IO and call Policies/Models.
|
||||
4. **Events are Data:** They describe "What Happened," not "What To Do."
|
||||
5. **Domain Events vs Audit Logs:** Events must be *business facts* (Domain), not system operations (CRUD/Audit).
|
||||
- ❌ BAD (Audit/CRUD): `UserUpdated`, `CheckoutButtonClicked`, `DatabaseSaved`
|
||||
- ✅ GOOD (Domain): `AddressChanged`, `OrderPriced`, `PaymentAuthorized`
|
||||
- **Design Backwards:** Start by defining the terminal Event you want to achieve, then define the State required to validate that Event, and finally the Command that initiates it.
|
||||
6. **Trust Boundaries (Input Security):** Untrusted input (e.g. from users or external systems) must never use raw strings at sensitive boundaries. Define strict wrapper boundaries (`TrustedInput`, `TaintedInput`) to ensure tracking and strict parsing before reaching pure logic or safe adapters. (See `docs/explanation/architecture/input-security.md`)
|
||||
|
||||
## When To Split: Policy vs Model vs Service vs Task vs Module
|
||||
|
||||
Use the smallest abstraction that matches the job. Start simple, then split only when the seam becomes meaningful.
|
||||
|
||||
### Policy
|
||||
Choose a **Policy** when the code answers a business question from data alone.
|
||||
- Pure decision
|
||||
- No IO
|
||||
- Returns a rich success/failure fact
|
||||
- Reusable across workflows or tasks
|
||||
|
||||
Ask:
|
||||
- "Is this deciding whether something is allowed, valid, eligible, or complete?"
|
||||
- "Could I test this with plain values and no mocks?"
|
||||
|
||||
### Model
|
||||
Choose a **Model** operation when the code performs a deterministic state transition.
|
||||
- Pure transformation
|
||||
- No IO
|
||||
- No business authority lookup
|
||||
- Usually runs after a successful policy decision
|
||||
|
||||
Ask:
|
||||
- "Is this just applying a known event or computing a new state?"
|
||||
- "If the event is already approved, can this be a pure function?"
|
||||
|
||||
### Service
|
||||
Choose a **Service** when the code represents a capability or integration.
|
||||
- Database, API, queue, filesystem, clock, email, payment, AI call
|
||||
- May fail for infrastructure reasons
|
||||
- Must not hide business decisions
|
||||
|
||||
Ask:
|
||||
- "Is this about what the system can do, not what the business allows?"
|
||||
- "Would changing vendors or infrastructure affect this code?"
|
||||
|
||||
### Task
|
||||
Choose a **Task** when a workflow grows and a chunk of orchestration becomes a named step with its own contract.
|
||||
- Still orchestration
|
||||
- May call policies, models, and services
|
||||
- May gather data, perform checks, and return a domain-meaningful result to a parent workflow
|
||||
- Smaller than a top-level workflow; extracted for clarity, reuse, or easier refactoring
|
||||
|
||||
A Task is appropriate when:
|
||||
- the parent workflow has become hard to read end-to-end
|
||||
- the step has a clear intent name (`priceOrder`, `reserveInventory`, `chooseNextLesson`)
|
||||
- the step can be tested independently with its own scenarios
|
||||
- the step may later become a separate workflow or module
|
||||
|
||||
A Task is not appropriate when:
|
||||
- it is only a thin wrapper around one policy or one service call
|
||||
- it exists only to create extra layers
|
||||
- it cannot be understood without the full caller context
|
||||
|
||||
### Module
|
||||
Choose a **Module** when a cluster of policies, models, tasks, and services forms a bounded capability.
|
||||
- Has a coherent language and responsibility
|
||||
- Has a small public API
|
||||
- Hides internal helpers and internal orchestration
|
||||
- May internally contain its own workflow-like structure
|
||||
|
||||
Ask:
|
||||
- "Would another part of the system use this as a capability boundary?"
|
||||
- "Can I expose intention-based entrypoints and keep the internals private?"
|
||||
|
||||
## Refactoring Guidance
|
||||
|
||||
Do not try to predict the final tree up front. Prefer this progression:
|
||||
1. Start with one workflow.
|
||||
2. As it grows, extract a **Task** when a step gains a stable intent and scenario surface.
|
||||
3. Extract **Policies** and **Models** aggressively when pure logic appears.
|
||||
4. Promote a group of related tasks/policies/models into a **Module** only when the boundary is repeatedly useful.
|
||||
|
||||
This keeps the codebase refactorable:
|
||||
- avoid premature indirection
|
||||
- keep boundaries intention-based
|
||||
- allow deeper structure to emerge from real pressure
|
||||
- preserve strong seams so future LLM or human refactors stay local
|
||||
|
||||
## Split Heuristics
|
||||
|
||||
A new seam is justified when at least one of these is true:
|
||||
- the name of the step is clearer than its implementation
|
||||
- the caller should care about the result, not the mechanics
|
||||
- three or more scenario variations are emerging
|
||||
- the code needs independent tests to stay reviewable
|
||||
- the step has narrower dependencies than its parent
|
||||
|
||||
Keep it inline when:
|
||||
- the logic is still trivial
|
||||
- the step has no stable domain meaning yet
|
||||
- extraction would force awkward pass-through parameters
|
||||
- the new abstraction would only have one obvious implementation and no simplification benefit
|
||||
|
||||
## Composition Rule
|
||||
|
||||
Prefer this direction of composition:
|
||||
- workflows coordinate tasks
|
||||
- tasks call policies, models, and services
|
||||
- modules expose intention-based entrypoints
|
||||
|
||||
A workflow may call another workflow, but treat that as a higher-cost move. Do it only when the callee is truly a reusable business capability with its own command/result contract, lifecycle concerns, and test surface. Otherwise, extract a Task or Module instead.
|
||||
|
||||
The goal is not a perfect static hierarchy. The goal is a codebase that can be safely reshaped as the workflow graph changes over time.
|
||||
@@ -0,0 +1,75 @@
|
||||
---
|
||||
globs:
|
||||
- "src/**/*.ts"
|
||||
- "design/**/*.md"
|
||||
---
|
||||
# Naming Conventions
|
||||
|
||||
## 1. Ubiquitous Language & CONTEXT.md
|
||||
|
||||
When a domain term stabilizes, it must be documented in a `CONTEXT.md` file located at the root of the Bounded Context under `src/<bounded-context-slug>/CONTEXT.md` (or at the repo root for single contexts). If dealing with a multi-context repo, a root `CONTEXT-MAP.md` should link to these.
|
||||
|
||||
The `CONTEXT.md` file MUST be a pure glossary of domain language, completely devoid of implementation details.
|
||||
|
||||
- **Format**: Define concepts using `**Term**: definition`, followed by an `_Avoid_: <conflicting terms>` line.
|
||||
- **Example dialogue**: Include a short mock conversation between a Developer and a Domain Expert to show how terms interact naturally.
|
||||
- **Flag conflicts explicitly**: If a term is contested or overloaded, use a "Flagged ambiguities" section to explicitly resolve it.
|
||||
|
||||
*Note: This dictionary format only applies to entries in `CONTEXT.md` files; it does not alter the naming heuristics for variables, types, or services below.*
|
||||
|
||||
## 2. Structural Naming (File & Module Level)
|
||||
|
||||
1. **Workflows**: Use `Verb-Noun` or `Scenario` names.
|
||||
- They represent *actions* or *processes*.
|
||||
- ✅ `checkout`, `fulfillOrder`, `registerUser`
|
||||
- ❌ `userOrder` (Ambiguous), `orders.ts` (Too generic)
|
||||
|
||||
2. **Policies**: Use `Verb` with `decide`, `validate`, or `calculate`.
|
||||
- They represent *decisions*.
|
||||
- ✅ `decideDiscount`, `validateCart`, `calculateShipping`
|
||||
- ❌ `discountRules`, `cartLogic`
|
||||
|
||||
3. **Ops Modules**: Use `Entity` + `Ops`.
|
||||
- ✅ `MoneyOps`, `CartOps`
|
||||
- ❌ `MoneyUtils`, `CartHelper`
|
||||
|
||||
4. **Variables**:
|
||||
- **Services**: PascalCase when used as a Tag/dependency. `yield* DatabaseService`.
|
||||
- **Data**: camelCase. `const user = ...`
|
||||
|
||||
## 2. Semantic Heuristics (Domain Modeling)
|
||||
|
||||
1. **State-First Types**: Avoid generic containers with status fields.
|
||||
- ❌ `Item` (with `status: 'sold'`)
|
||||
- ✅ `DraftItem` → `OpenItem` → `SoldItem`
|
||||
|
||||
2. **Intent-First Names**: Name by caller intent and stable business meaning, not current implementation shape.
|
||||
- ❌ `nextLesson`
|
||||
- ✅ `getNextTask`
|
||||
- Ask: would this name still be correct if the implementation changed but the user goal stayed the same?
|
||||
|
||||
3. **Capability-Based Boundaries**: Name authority and role explicitly when the boundary is about what a caller may do.
|
||||
- ✅ `ReadCurriculum`, `WriteCurriculum`
|
||||
- ✅ `BiddableItem`, `BidHistory`
|
||||
- ❌ `ItemWithBids` (data description when role/capability matters)
|
||||
|
||||
4. **Bounded Seams Need Strong Names**: At reviewable boundaries, names should expose intent, authority, and protected invariants.
|
||||
- Prefer seam names that tell the reviewer what the caller is trying to achieve.
|
||||
- Be suspicious of implementation-shaped names at public seams.
|
||||
|
||||
5. **Three-Alternatives Rule**: For important names, seams, types, and workflows, compare three plausible alternatives before choosing.
|
||||
- Ask what each alternative implies about caller intent, domain model, and future change pressure.
|
||||
- Prefer the name that preserves domain intent across likely model evolution.
|
||||
|
||||
6. **The Domain Grammar**:
|
||||
- **Objects** = Nouns (`ActiveItem`)
|
||||
- **Events** = Past Verbs (`BidPlaced`)
|
||||
- **Commands** = Imperative Verbs (`PlaceBid`)
|
||||
|
||||
## 3. Review Smells
|
||||
|
||||
Be suspicious when you see:
|
||||
|
||||
- `Manager`, `Handler`, `Processor`, `Data`, `Info`
|
||||
- one concept stretched to cover future cases because the name is too narrow
|
||||
- names that describe storage shape or current implementation instead of domain meaning
|
||||
@@ -0,0 +1,27 @@
|
||||
---
|
||||
globs:
|
||||
- "**/*.test.ts"
|
||||
- "**/test/**"
|
||||
---
|
||||
# Testing Strategy
|
||||
|
||||
## 1. The "Triad" Rule (Coverage Heuristic)
|
||||
For every feature/workflow, you must write at least three specs:
|
||||
1. **Happy Path**: The standard success case.
|
||||
2. **Sad Path**: The expected failure mode (Typed Errors).
|
||||
3. **Edge Case**: Boundary conditions or empty states.
|
||||
|
||||
## 2. Unit Tests for Pure Logic
|
||||
- Test `domain/ops` and `policies` using standard `vitest` assertions. No mocks needed.
|
||||
- `expect(MoneyOps.add(a, b)).toEqual(c)`
|
||||
|
||||
## 3. Test Layers for Workflows
|
||||
- Test Workflows by providing *Test Layers* (in-memory implementations) for Services.
|
||||
- `const result = await program.pipe(Effect.provide(TestDatabaseLayer), Effect.runPromise)`
|
||||
|
||||
## 4. Integration Tests for Adapters
|
||||
- Test `src/adapters/adapters` against real infrastructure (Docker/TestContainers).
|
||||
- Do not mock the database in an adapter test; that defeats the purpose.
|
||||
|
||||
## 5. No Mocks
|
||||
- Avoid `jest.fn()` or traditional spies. Use `Effect` layers to swap implementations.
|
||||
@@ -0,0 +1,30 @@
|
||||
---
|
||||
globs:
|
||||
- "src/workflows/**/*.ts"
|
||||
---
|
||||
# Workflows & Effects Rules
|
||||
|
||||
1. **Use Effect.gen**: Prefer `Effect.gen` generators over chained combinators for readability.
|
||||
`Effect.gen(function*() { const user = yield* UserService.get(id); ... })`
|
||||
|
||||
2. **Data-Last Signatures**: Functions should accept data as the last argument to support `pipe`.
|
||||
`const multiply = (factor: number) => (value: number) => value * factor`
|
||||
|
||||
3. **Typed Errors**: Use Discriminated Unions for errors. Avoid generic `Error`.
|
||||
`class UserNotFound extends Data.TaggedError("UserNotFound")<{ id: string }> {}`
|
||||
|
||||
4. **Explicit Service Dependencies**: Workflows must consume Services via Context/Tag, never direct import of implementations.
|
||||
`const program = Effect.gen(function*() { const db = yield* DatabaseService; ... })`
|
||||
|
||||
5. **Safe Ordering**: Perform irreversible effects (Emails, Charges) *last* in the workflow.
|
||||
`yield* Database.save(); yield* Email.send();` (Retrying DB is safe; retrying Email is spam).
|
||||
|
||||
6. **Error Handling Philosophy**:
|
||||
- Workflows must handle failures (`Either.Left` / `Result.fail`) from Policies.
|
||||
- A Policy failing is simply a domain fact (e.g., "Truck is full"). The Workflow decides what to do with that fact based on its context (e.g., return HTTP 400, trigger a compensating action, or send an alert).
|
||||
- Do not throw raw Exceptions for domain errors. Use typed errors and `Effect.fail` or `Effect.catchAll`.
|
||||
|
||||
7. **Idempotency**: All Workflows should be designed to be retried. Accept `idempotencyKey` where applicable.
|
||||
|
||||
7. **State Persistence**: If a workflow is critical (money, data), persist state transitions (e.g., "OrderCreated" event) *before* performing external effects. This enables replay/recovery.
|
||||
`yield* EventStore.append("OrderCreated"); yield* Payment.charge();`
|
||||
@@ -0,0 +1,54 @@
|
||||
# Effect Patterns Skills
|
||||
|
||||
This directory contains 24 auto-generated Claude Code skills for Effect-TS patterns.
|
||||
|
||||
## Skills Included
|
||||
|
||||
All skills are organized by category and include beginner, intermediate, and advanced patterns:
|
||||
|
||||
- `effect-patterns-error-handling` - Error handling and recovery patterns
|
||||
- `effect-patterns-concurrency` - Concurrent and parallel execution patterns
|
||||
- `effect-patterns-core-concepts` - Fundamental Effect-TS concepts
|
||||
- `effect-patterns-streams` - Stream processing patterns
|
||||
- `effect-patterns-domain-modeling` - Domain modeling with branded types
|
||||
- `effect-patterns-building-apis` - HTTP API development patterns
|
||||
- `effect-patterns-resource-management` - Resource lifecycle management
|
||||
- `effect-patterns-testing` - Testing Effect applications
|
||||
- `effect-patterns-observability` - Logging, tracing, and metrics
|
||||
- `effect-patterns-platform` - Platform operations (filesystem, commands, etc.)
|
||||
- And 14 more categories...
|
||||
|
||||
## For Developers
|
||||
|
||||
### Regenerating Skills
|
||||
|
||||
When patterns in `content/published/patterns/` are updated:
|
||||
|
||||
```bash
|
||||
bun run generate:skills
|
||||
```
|
||||
|
||||
This regenerates all skills in both:
|
||||
- `content/published/skills/claude/` (gitignored dev artifacts)
|
||||
- `.claude-plugin/plugins/effect-patterns/skills/` (committed for plugin distribution)
|
||||
|
||||
### Skill Structure
|
||||
|
||||
Each skill follows the format:
|
||||
```
|
||||
effect-patterns-{category}/
|
||||
└── SKILL.md # YAML frontmatter + pattern content
|
||||
```
|
||||
|
||||
Skills are auto-discovered by Claude Code from this directory.
|
||||
|
||||
### Skill Content
|
||||
|
||||
Each SKILL.md file contains:
|
||||
- **YAML frontmatter**: name, description
|
||||
- **Pattern sections**: Organized by skill level (beginner → intermediate → advanced)
|
||||
- **For each pattern**:
|
||||
- Rule/guideline
|
||||
- Good example
|
||||
- Anti-pattern
|
||||
- Rationale/explanation
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,25 @@
|
||||
---
|
||||
name: effect-ast-analyzer
|
||||
description: Run the Effect-TS AST analyzer to check for anti-patterns in local files.
|
||||
---
|
||||
|
||||
# Effect AST Analyzer
|
||||
|
||||
You can use the local Effect AST Analyzer to check any TypeScript file for Effect anti-patterns.
|
||||
This is highly recommended before finalizing any complex changes to ensure you haven't introduced things like floating promises, bad error handling, or generic try/catch blocks.
|
||||
|
||||
To run the analyzer on a file, use the Bash tool:
|
||||
|
||||
```bash
|
||||
./node_modules/.bin/effect-patterns-check path/to/your/file.ts
|
||||
```
|
||||
|
||||
If it returns warnings or errors, you MUST fix them before considering your task complete.
|
||||
|
||||
## How it works
|
||||
It parses the local TypeScript AST and checks against over 50 specific Effect-TS rules, like:
|
||||
- `try-catch-in-effect`: Ensure `Effect.try` is used instead of `try/catch`
|
||||
- `async-await`: Ensure `Effect.gen` is used instead of `async`/`await`
|
||||
- `missing-error-channel`: Ensure typed errors are propagated
|
||||
|
||||
Always run this when refactoring or creating new Effect code!
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
name: effect-expert
|
||||
description: Teaches the AI agent about Effect best practices using the Effect MCP server
|
||||
---
|
||||
|
||||
# Effect Expert
|
||||
|
||||
This skill activates the Effect MCP Server. It provides live, contextual information about the application's structure directly to AI coding agents.
|
||||
|
||||
Use this skill when you need deep context about the application's services, layers, and their types in order to use Effect properly.
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"effect": {
|
||||
"command": "npx",
|
||||
"args": [
|
||||
"-y",
|
||||
"@effect/mcp-server",
|
||||
"--layer",
|
||||
"src/layers.ts:AppLayer"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
---
|
||||
name: tdfddd-assembly
|
||||
description: "Phase 4: Implementation Assembly. Translates F# models into TypeScript/Effect code. Triggers on: Implement the code, Phase 4, Start assembly, Generate TypeScript, Write Effect code."
|
||||
---
|
||||
|
||||
# Assembly Agent: The Implementer
|
||||
|
||||
## Description
|
||||
|
||||
Phase 4: Implementation Assembly. Translates F# models into TypeScript/Effect code.
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
Activate when the user:
|
||||
|
||||
- Says "Implement the code".
|
||||
- Says "Phase 4" or "Start assembly".
|
||||
- Says "Generate TypeScript" or "Write Effect code".
|
||||
- Has already completed Blueprint for one workflow slice.
|
||||
|
||||
## Core Function: The Translator
|
||||
|
||||
**Goal:** Mechanically translate the F# Domain Model into idiomatic TypeScript/Effect code.
|
||||
|
||||
F# is the primary design language and contract artifact for this phase. Assembly is a translation step from the frozen F# blueprint, not a redesign step.
|
||||
|
||||
Use TDD during assembly, but only after the design is frozen. The contract from the blueprint determines the test surface.
|
||||
|
||||
**Constraints:**
|
||||
|
||||
- Read `design/workflows/<bounded-context-slug>/shared-model.fs` when present and `design/workflows/<bounded-context-slug>/<workflow-slug>/04-blueprint.fs` as input.
|
||||
- Generate valid, **type-safe** TypeScript code using the Effect library.
|
||||
- **Do not** deviate from the blueprint.
|
||||
- **Do not** invent new business rules.
|
||||
- Implement exactly one workflow slice at a time.
|
||||
|
||||
**Instructions:**
|
||||
|
||||
1. Read `design/workflows/<bounded-context-slug>/shared-model.fs` when present and `design/workflows/<bounded-context-slug>/<workflow-slug>/04-blueprint.fs`.
|
||||
2. Read `design/feature/<feature-slug>/status.md` and confirm this workflow slice is selected for implementation.
|
||||
3. Confirm the design/security gate is approved before writing implementation code.
|
||||
4. Treat the selected `04-blueprint.fs` as the complete contract for exactly one workflow slice. Do not look for or assume additional slice blueprints in the same artifact.
|
||||
5. Defer all other workflow slices to their own blueprint and assembly passes.
|
||||
6. **Follow Strict Project Structure:**
|
||||
7. Derive tests from the frozen contract before or alongside code:
|
||||
- workflow scenarios from commands and events
|
||||
- policy examples from decision points
|
||||
- model properties from invariants and state transitions
|
||||
8. Implement in vertical **RED -> GREEN -> REFACTOR** cycles.
|
||||
- **RED:** pick one behavior from the frozen contract, write one test through the public seam, and confirm it fails for the expected reason.
|
||||
- **GREEN:** write the minimum production code needed to make that single test pass. Do not implement extra behaviors early.
|
||||
- **REFACTOR:** once green, improve names, duplication, and module depth without changing behavior. Re-run tests after each refactor.
|
||||
- Avoid premature indirection during refactor: keep logic combined by default, and extract only when the green code shows a real gain in nameability, testability, reuse, boundary clarity, or duplicated complexity.
|
||||
- Good names help reveal useful extractions, but they do not justify an unnecessary layer by themselves.
|
||||
- Start with one **tracer bullet** test that proves the end-to-end path, then add one behavior at a time.
|
||||
- Never refactor while red.
|
||||
9. **Follow Strict Project Structure:**
|
||||
- **`src/domain/models/`** (Pure Domain Knowledge):
|
||||
- Place `Effect.Schema` definitions here.
|
||||
- Place `Brand` types here.
|
||||
- Place Pure Logic (e.g., `Money.add`, `Cart.isEmpty`).
|
||||
- **NO** external dependencies, **NO** `Effect<...>`, **NO** Side Effects.
|
||||
- **`src/domain/interfaces/`** (Service Contracts):
|
||||
- Define interfaces for repositories and services (e.g., `interface PaymentRepo`).
|
||||
- Use `Context.Tag` for dependency injection.
|
||||
- **`src/policies/`** (Business Decisions):
|
||||
- Pure functions that make decisions based on multi-entity context.
|
||||
- Returns `Result` or `Strategy Decision`.
|
||||
- **NO** Side Effects.
|
||||
- Example: `determinePaymentStrategy(amount)`, `canAccessResource(user, resource)`.
|
||||
- **`src/workflows/`** (Orchestration):
|
||||
- The "Impure Shell". Connects pieces, manages transaction flow.
|
||||
- Uses `Effect.gen(function*(_) { ... })`.
|
||||
- Orchestrates: 1. Fetch State (Repo) -> 2. Policy Decision (Policy) -> 3. Apply Change (Model) -> 4. Save (Repo).
|
||||
- **`src/registries/`** (Dynamic Wiring):
|
||||
- Strategy Pattern implementation (e.g., selecting Stripe vs PayPal based on Policy).
|
||||
- **`src/adapters/`** (Infrastructure):
|
||||
- Concrete implementations of interfaces (e.g., `Stripe.service.ts`).
|
||||
- Place adapters here.
|
||||
- **`src/layers/`** (Dependency Injection):
|
||||
- `Main.layer.ts` for wiring production dependencies.
|
||||
10. Integrate **Input Security** (See docs/explanation/architecture/input-security.md):
|
||||
- **Wrappers:** Never pass raw strings to sensitive sinks. Translate raw string inputs into strongly typed wrappers (e.g., `TrustedInput`, `TaintedInput`) at the boundary.
|
||||
- **Provenance:** Ensure the type explicitly states the source and trust level.
|
||||
- **Strict Ingestion:** Implement strict filtering (length, type, format) at the ingestion point (e.g., in the Controller or the very beginning of the Workflow).
|
||||
- **Late Sanitization:** Apply encoding or context-specific escaping right before the string is consumed (e.g., in an Adapter right before a DB call or API request).
|
||||
- **Structural Safety:** Use parameterized queries or structural objects instead of string concatenation.
|
||||
11. Translate **Primitives**:
|
||||
- `type Weight = int<kg>` -> `const Weight = Schema.Number.pipe(Schema.brand("Kg"))`
|
||||
- Always export the type: `export type Weight = typeof Weight.Type`
|
||||
12. Translate **Structures (Records)**:
|
||||
- `type User = { Name: string }` -> `const User = Schema.Struct({ name: Schema.String })`
|
||||
13. Translate **Unions (Aggregates/Events)**:
|
||||
- `type State = A | B` -> `Schema.Union(A, B)` (Discriminated Union)
|
||||
14. Implement the **Contract**:
|
||||
- `decide : State -> Command -> Result` -> `export const decide = (state: State, cmd: Command): Either<Error, Event> => ...`
|
||||
- `apply : State -> Event -> State` -> `export const apply = (state: State, event: Event): State => ...`
|
||||
- `workflow : Command -> Effect<Result>` -> `export const workflow = (cmd: Command) => Effect.gen(...)`
|
||||
15. **Action:** Write the implementation files to `src/` and the tests to `test/`, then update `design/feature/<feature-slug>/status.md` for the current workflow slice.
|
||||
- `src/domain/models/`: Types & Schemas
|
||||
- `src/policies/`: Pure Logic (`decide`)
|
||||
- `src/workflows/`: Effect Orchestration (`workflow`)
|
||||
16. **Format:** Use strict TypeScript with Effect.
|
||||
17. **Test style by layer:**
|
||||
- `src/domain/models/` and `src/policies/`: example tests plus property-based tests for invariants.
|
||||
- `src/workflows/`: scenario tests with Effect test layers / in-memory adapters.
|
||||
- `src/adapters/`: contract tests and integration tests where appropriate.
|
||||
18. **Per-cycle checklist:**
|
||||
- test describes behavior, not implementation
|
||||
- test uses the public interface only
|
||||
- code change is minimal for the current failing test
|
||||
- no speculative features or extra cases are added
|
||||
19. **Verification before completion:**
|
||||
- Run `pnpm verify` before declaring the implementation complete.
|
||||
- Run `pnpm effect:check <filepath>` for each modified Effect file.
|
||||
- Report verification results faithfully, including any failing command output.
|
||||
|
||||
## Translation Table
|
||||
|
||||
| F# Concept | TypeScript / Effect Implementation |
|
||||
| :-------------------- | :---------------------------------------------------- | -------------------- |
|
||||
| `type T = int<brand>` | `const T = Schema.Number.pipe(Schema.brand("Brand"))` |
|
||||
| `type R = { f: T }` | `const R = Schema.Struct({ f: T })` |
|
||||
| `type U = A | B` | `Schema.Union(A, B)` |
|
||||
| `Result<T, E>` | `Either<E, T>` |
|
||||
| `Async<Result<T, E>>` | `Effect<T, E>` |
|
||||
|
||||
## Usage Examples
|
||||
|
||||
**User:** "Implement it."
|
||||
**Agent (Implementer):** [Reads `design/workflows/loading/load-truck/04-blueprint.fs` and `design/feature/truck-loading/status.md`]
|
||||
[Generates `src/domain/models/Truck.ts`]
|
||||
[Generates `src/policies/LoadPolicy.ts`]
|
||||
[Generates `src/workflows/LoadWorkflow.ts`]
|
||||
"Implementation complete for the selected workflow slice based on the blueprint."
|
||||
@@ -0,0 +1,93 @@
|
||||
---
|
||||
name: tdfddd-blueprint
|
||||
description: "Phase 5: Domain Modeling & Contract. Generates F# domain models from core sketches one workflow slice at a time. Use after core sketch and before assembly. Triggers on: blueprint the model, phase 5, start modeling, generate domain model."
|
||||
---
|
||||
|
||||
# Blueprint Agent: The Architect
|
||||
|
||||
## Description
|
||||
|
||||
Phase 5: Domain Modeling & Contract. Generates F# domain models from one workflow slice's core sketch plus the bounded context shared language. F# remains the primary design language and the frozen contract that assembly translates from.
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
Activate when the user:
|
||||
|
||||
- Says "Blueprint the model" or "Blueprint workflow X".
|
||||
- Says "Phase 5" or "Start modeling".
|
||||
- Says "Generate domain model".
|
||||
- Has already completed Core Sketch for one workflow slice and wants to formalize the design for that specific workflow.
|
||||
|
||||
## Core Function: The F# Architect
|
||||
|
||||
**Goal:** Create a strict, type-driven F# domain model that captures the requirements.
|
||||
|
||||
**Constraints:**
|
||||
|
||||
- Read `design/workflows/<bounded-context-slug>/shared-language.md` and `design/workflows/<bounded-context-slug>/<workflow-slug>/03-core-sketch.md`.
|
||||
- Generate **valid F# pseudo-code** that captures the types, invariants, and function signatures.
|
||||
- Treat the F# blueprint as the authoritative contract for the slice.
|
||||
- **Do not** generate implementation code (TypeScript/Effect) yet.
|
||||
- **Do not** skip the domain modeling phase.
|
||||
- Model exactly one workflow slice at a time.
|
||||
|
||||
**Instructions:**
|
||||
|
||||
1. Read the bounded context shared language and the workflow slice core sketch.
|
||||
2. **Check Shared Domain:** If there is an existing `design/workflows/<bounded-context-slug>/shared-model.fs`, read it to ensure you reuse existing primitives and aggregates owned by that context.
|
||||
3. **Apply Core Rules (from docs/core-rules/):**
|
||||
- **Make Illegal States Unrepresentable:**
|
||||
- Avoid primitive obsession
|
||||
- Never use `string` for an ID; use `type OrderId = OrderId of string`.
|
||||
- Never use `int` for a quantity; use `type Quantity = Quantity of int`.
|
||||
- If a Truck cannot be loaded while Sealed, the `Load` command must strictly require `LoadingTruck` state.
|
||||
- **Input Security (Wrappers):**
|
||||
- Avoid raw strings at boundaries. Define specific wrapper types for untrusted data (e.g., `type TrustedInput = TrustedInput of string`, `type TaintedInput = TaintedInput of string`) to represent provenance and trust boundaries. (See docs/explanation/architecture/input-security.md)
|
||||
- **Parse, Don't Validate:**
|
||||
- The model should enforce invariants at the type level where possible.
|
||||
- **Pure Policy:**
|
||||
- The `decide` function **MUST** be pure. No `Async`, no `Task`, no Side Effects.
|
||||
- Signature: `decide : State -> Command -> Result<Event, Error>`
|
||||
4. Identify:
|
||||
- **Primitives:** (Weight, Volume, ID, etc.) -> Use distinct types (e.g., `type Weight = int<kg>`).
|
||||
- **Compounds:** (Package, TruckCapacity) -> Use Records.
|
||||
- **Aggregates:** (LoadingTruck vs SealedTruck) -> Use Discriminated Unions for states.
|
||||
- **Events:** (PackageLoaded, LoadFailure) -> Use Discriminated Unions for outcomes.
|
||||
5. Define the **Contract Signatures**:
|
||||
- **Policy:** `decide : State -> Command -> Result<Event, Error>`
|
||||
- **Reducer:** `apply : State -> Event -> State`
|
||||
- **Workflow:** `workflow : Command -> Effect<Result>`
|
||||
6. **Action:** Write the model to `design/workflows/<bounded-context-slug>/<workflow-slug>/04-blueprint.fs`. If the slice introduces stable shared context primitives, update `design/workflows/<bounded-context-slug>/shared-model.fs`.
|
||||
7. **Format:**
|
||||
|
||||
```fsharp
|
||||
// in 04-blueprint.fs
|
||||
module WorkflowName
|
||||
|
||||
// 1. Primitives
|
||||
type ...
|
||||
|
||||
// 2. Commands (Inputs)
|
||||
type ...
|
||||
|
||||
// 3. Events (Facts)
|
||||
type ...
|
||||
|
||||
// 4. State (Aggregates)
|
||||
type State =
|
||||
| Case1 of ...
|
||||
| Case2 of ...
|
||||
|
||||
// 5. Signatures (Contract)
|
||||
val decide : State -> Command -> Result<Event, Error>
|
||||
val apply : State -> Event -> State
|
||||
```
|
||||
|
||||
8. **Final Output:** "Domain Model generated at `design/workflows/<bounded-context-slug>/<workflow-slug>/04-blueprint.fs`. Review the types, workflow boundaries, and slice plan. If approved, update `design/feature/<feature-slug>/status.md`."
|
||||
|
||||
## Usage Examples
|
||||
|
||||
**User:** "Blueprint the checkout workflow."
|
||||
**Agent (Architect):** [Reads `design/workflows/orders/shared-language.md` and `design/workflows/orders/checkout/03-core-sketch.md`]
|
||||
[Generates `design/workflows/orders/checkout/04-blueprint.fs` and updates `design/workflows/orders/shared-model.fs` if needed]
|
||||
"Domain Model generated. Ready for design security review or assembly for this workflow slice."
|
||||
@@ -0,0 +1,157 @@
|
||||
---
|
||||
name: tdfddd-context-workflow-decomposition
|
||||
description: "Phase 2: Context and workflow decomposition. Maps a discovered feature into bounded contexts, workflow slices, shared-language artifacts, handoffs, and a slice-first execution order. Use after feature discovery and before slice discovery/core sketching. Triggers on: context decomposition, workflow decomposition, decompose feature, identify bounded contexts, map workflows."
|
||||
---
|
||||
|
||||
# Context & Workflow Decomposition Agent: The Mapper
|
||||
|
||||
## Description
|
||||
|
||||
Phase 2: Context & Workflow Decomposition.
|
||||
Turns a feature-level discovery artifact into bounded contexts, per-context workflow slices, shared-language artifacts, and a feature-to-slice execution map.
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
Activate when the user:
|
||||
|
||||
- Says "decompose the feature".
|
||||
- Says "identify bounded contexts" or "map workflows".
|
||||
- Says "Phase 2" after feature discovery is frozen.
|
||||
- Wants to break a feature into workflow slices before deeper design.
|
||||
|
||||
## Core Function: The Mapper
|
||||
|
||||
**Goal:** Convert a feature-level discovery into a slice-first design map so downstream work happens one workflow inside one bounded context at a time.
|
||||
|
||||
**Constraints:**
|
||||
|
||||
- Read `design/feature/<feature-slug>/discovery.md` as primary input.
|
||||
- The unit of decomposition is **one workflow slice inside one bounded context**.
|
||||
- Default rule: **no cross-context decision logic inside a workflow slice**.
|
||||
- Cross-context behavior belongs in feature-level handoff/orchestration notes, not in a slice contract.
|
||||
- Do not do deep per-slice interrogation here; that belongs to Slice Discovery.
|
||||
|
||||
## Instructions
|
||||
|
||||
1. Read `design/feature/<feature-slug>/discovery.md`.
|
||||
2. Identify the bounded contexts touched by the feature.
|
||||
3. For each bounded context, identify the workflows that are truly owned by that context.
|
||||
4. Create or update `design/feature/<feature-slug>/design.md` with:
|
||||
- bounded context inventory
|
||||
- feature steps mapped to workflow slices
|
||||
- cross-context handoffs
|
||||
- recommended implementation order
|
||||
- unresolved dependency notes
|
||||
5. For each bounded context, create or update `design/workflows/<bounded-context-slug>/shared-language.md`.
|
||||
- Record context-local ubiquitous language.
|
||||
- Reuse global terms from `docs/reference/shared-language.md` when appropriate.
|
||||
- Prefer short domain definitions and preferred/rejected synonyms.
|
||||
6. For each workflow slice, create `design/workflows/<bounded-context-slug>/<workflow-slug>/01-decomposition.md` containing:
|
||||
- workflow name and owning bounded context
|
||||
- trigger / command summary
|
||||
- purpose and success outcome
|
||||
- upstream inputs / snapshots
|
||||
- downstream handoffs / emitted events
|
||||
- dependencies on other slices
|
||||
- explicit statement that decision logic stays inside the owning context only
|
||||
7. Create or update `design/feature/<feature-slug>/status.md` so it tracks:
|
||||
- discovery status
|
||||
- decomposition status
|
||||
- bounded contexts
|
||||
- workflow slices
|
||||
- current slice in progress
|
||||
- per-slice gate progression
|
||||
8. Final output should tell the user which workflow slice is the best next candidate for Slice Discovery.
|
||||
|
||||
## Required Artifacts
|
||||
|
||||
### `design/feature/<feature-slug>/design.md`
|
||||
|
||||
```markdown
|
||||
# Feature Design Map: <Feature Name>
|
||||
|
||||
## Bounded Contexts
|
||||
|
||||
- `<ContextName>` — `<responsibility>`
|
||||
|
||||
## Feature Step to Workflow Slice Map
|
||||
|
||||
| Feature Step | Bounded Context | Workflow Slice | Notes |
|
||||
| :----------- | :-------------- | :------------- | :--------------- |
|
||||
| `<step>` | `<context>` | `<workflow>` | `<handoff note>` |
|
||||
|
||||
## Cross-Context Handoffs
|
||||
|
||||
- `<ContextA>` -> `<ContextB>` via `<event|handoff>` because `<reason>`
|
||||
|
||||
## Recommended Slice Order
|
||||
|
||||
1. `<context>/<workflow>` — `<why first>`
|
||||
2. `<context>/<workflow>` — `<why next>`
|
||||
|
||||
## Orchestration Notes
|
||||
|
||||
- `<feature-level sequencing or saga note>`
|
||||
|
||||
## Open Questions
|
||||
|
||||
- `<question>`
|
||||
```
|
||||
|
||||
### `design/workflows/<bounded-context-slug>/shared-language.md`
|
||||
|
||||
```markdown
|
||||
# Shared Language: <Bounded Context Name>
|
||||
|
||||
## Context Meaning
|
||||
|
||||
- `<what this context owns>`
|
||||
|
||||
## Preferred Terms
|
||||
|
||||
| Term | Meaning | Use this, not that | Notes |
|
||||
| :---------------- | :---------- | :---------------------------------------- | :------- |
|
||||
| `<PreferredTerm>` | `<Meaning>` | `<PreferredTerm>` not `<RejectedSynonym>` | `<Note>` |
|
||||
```
|
||||
|
||||
### `design/workflows/<bounded-context-slug>/<workflow-slug>/01-decomposition.md`
|
||||
|
||||
```markdown
|
||||
# Workflow Decomposition: <Workflow Name>
|
||||
|
||||
- Bounded context: `<ContextName>`
|
||||
- Workflow slug: `<workflow-slug>`
|
||||
- Trigger: `<command or external event>`
|
||||
- Success outcome: `<primary domain result>`
|
||||
|
||||
## Inputs Owned by This Context
|
||||
|
||||
- `<owned state>`
|
||||
|
||||
## Inputs Observed from Other Contexts
|
||||
|
||||
- `<snapshot or handoff only>`
|
||||
|
||||
## Downstream Handoffs
|
||||
|
||||
- `<event or request to other context>`
|
||||
|
||||
## Slice Boundaries
|
||||
|
||||
- Decision logic is owned only by `<ContextName>`.
|
||||
- Cross-context orchestration belongs in feature-level notes.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Requires `<other slice>` before/after because `<reason>`
|
||||
```
|
||||
|
||||
## Success Criteria
|
||||
|
||||
A good decomposition leaves behind:
|
||||
|
||||
- a stable feature-to-slice map
|
||||
- per-context shared-language artifacts
|
||||
- workflow folders with clear ownership
|
||||
- a recommended next slice for deep discovery
|
||||
- no ambiguity that downstream phases operate on one slice at a time
|
||||
@@ -0,0 +1,50 @@
|
||||
---
|
||||
name: tdfddd-core-sketch
|
||||
description: "Phase 4: Core sketch. Translates one workflow slice inside one bounded context into required state, commands, events, and pure policy signatures. Use after slice discovery and before blueprinting. Triggers on: core sketch, identify state, draft policies, sketch this workflow."
|
||||
---
|
||||
|
||||
# Core Sketch Agent: The Systems Analyst
|
||||
|
||||
## Description
|
||||
|
||||
Phase 4: Core Sketch. Bridges slice discovery and blueprinting by turning one workflow slice inside one bounded context into explicit required state, commands, events, and pure policy signatures.
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
Activate when the user:
|
||||
|
||||
- Says "Create core sketch" or "Draft policies".
|
||||
- Says "Phase 4" or "Identify state".
|
||||
- Has completed slice discovery for one workflow slice and wants to figure out the data needed before blueprinting.
|
||||
|
||||
## Core Function: The Analyst
|
||||
|
||||
**Goal:** Translate one workflow slice into a reviewable sketch, preventing monolithic designs later while reusing the bounded context's shared language.
|
||||
|
||||
**Constraints:**
|
||||
|
||||
- Read `design/workflows/<bounded-context-slug>/shared-language.md`, `design/workflows/<bounded-context-slug>/<workflow-slug>/01-decomposition.md`, and `design/workflows/<bounded-context-slug>/<workflow-slug>/02-discovery.md` as input.
|
||||
- **Do not** write F# code. Use plain English and basic pseudo-signatures to identify data needs.
|
||||
- **Do not** combine multiple workflows into a single file.
|
||||
- Keep decision logic inside the owning bounded context.
|
||||
|
||||
**Instructions:**
|
||||
|
||||
1. Read the selected workflow slice artifacts.
|
||||
2. **Identify the Command:** What user action or trigger starts this workflow?
|
||||
3. **Extract Shared Concepts:** Reuse domain primitives and entities already named in the bounded context shared language.
|
||||
4. **Sketch the Workflow:** Output `design/workflows/<bounded-context-slug>/<workflow-slug>/03-core-sketch.md`.
|
||||
- **Command:** What triggers it?
|
||||
- **Required State:** What state owned by this context is required to decide it?
|
||||
- **Observed Inputs:** What snapshots or handoffs from other contexts are read, if any?
|
||||
- **Policy Signature (Pseudo):** `decide : Command -> State -> Result<SuccessEvent, FailureEvent>`
|
||||
- **Events:** What does it output?
|
||||
- **Boundary Notes:** What must remain feature-level orchestration rather than slice logic?
|
||||
5. **Final Output:** Inform the user: "Core Sketch completed for `design/workflows/<bounded-context-slug>/<workflow-slug>/03-core-sketch.md`. Ready for Blueprint for this workflow slice."
|
||||
|
||||
## Usage Examples
|
||||
|
||||
**User:** "Create core sketch for the checkout workflow slice."
|
||||
**Agent (Analyst):** [Reads `design/workflows/orders/shared-language.md`, `design/workflows/orders/checkout/01-decomposition.md`, and `design/workflows/orders/checkout/02-discovery.md`]
|
||||
[Generates `design/workflows/orders/checkout/03-core-sketch.md`]
|
||||
"Core Sketch completed for the checkout workflow slice. Ready for Blueprint."
|
||||
@@ -0,0 +1,113 @@
|
||||
---
|
||||
name: tdfddd-discovery
|
||||
description: "Phase 1: Feature discovery. Interrogates the user to uncover edge cases, candidate bounded contexts, candidate workflow slices, and shared language, then generates the feature discovery artifact. Triggers on: start discovery phase, interrogate me, phase 1, requirements gathering."
|
||||
---
|
||||
|
||||
# Discovery Agent: Feature Detective
|
||||
|
||||
## Description
|
||||
|
||||
Phase 1: Feature Discovery & Consolidation. Interrogates the user to understand the full feature, uncover edge cases, identify candidate bounded contexts and workflows, and generate the feature discovery artifact.
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
Activate when the user:
|
||||
|
||||
- Starts a new feature or design process.
|
||||
- Says "Start discovery phase".
|
||||
- Says "Interrogate me about [feature]".
|
||||
- Mentions "Phase 1" or "Requirements gathering".
|
||||
|
||||
## Core Function: The Interrogation Protocol
|
||||
|
||||
You operate in two strict modes. You start in **Detective Mode**.
|
||||
|
||||
### Mode 1: Detective Mode (Default)
|
||||
|
||||
**Goal:** Understand the feature as a whole: edge cases, missing requirements, ambiguous business rules, candidate bounded contexts, candidate workflows, and the feature-level shared language.
|
||||
**Constraint:** You are **FORBIDDEN** from writing the discovery artifact in this mode.
|
||||
|
||||
**Instructions:**
|
||||
|
||||
1. Analyze the user's request.
|
||||
2. Identify the "Happy Path" (what happens when everything goes right).
|
||||
3. Identify the "Unhappy Paths" (what happens when things go wrong).
|
||||
4. Identify potential "Race Conditions" or "State Conflicts".
|
||||
5. Walk the decision tree one branch at a time. Resolve one ambiguity before opening several new branches.
|
||||
6. Ask clarifying questions one at a time when possible.
|
||||
7. Periodically restate the current shared understanding in plain domain language so the user can confirm or correct it.
|
||||
8. When terminology becomes stable, document domain terms in `src/<bounded-context>/CONTEXT.md` (or repo root for single contexts) using the strict Glossary Format. Update this file *inline* during the session rather than waiting.
|
||||
9. **Active Grilling**: Challenge fuzzy language actively ("Your glossary defines *cancellation* as X, but you seem to mean Y—which is it?"). Cross-reference definitions with the codebase and demand concrete scenarios to stress-test boundaries. Flag ambiguities explicitly.
|
||||
10. Identify candidate bounded contexts and candidate workflow slices, but do **not** deeply interrogate each slice yet.
|
||||
11. **Output:** A response that _must_ end with clarifying question(s).
|
||||
- Do _not_ propose a solution yet.
|
||||
- Do _not_ write code.
|
||||
- Ask questions like: "What happens if X fails?", "Can Y happen before Z?", "Is this operation idempotent?"
|
||||
|
||||
**Transition Trigger:**
|
||||
When the user says **"Consolidate"**, **"Ready to spec"**, or **"Freeze discovery"**, switch to **Scribe Mode**.
|
||||
|
||||
### Mode 2: Scribe Mode
|
||||
|
||||
**Goal:** Freeze the feature discovery into a formal artifact.
|
||||
**Constraint:** Do not ask new questions UNLESS a critical ambiguity blocks the specification.
|
||||
|
||||
**Instructions:**
|
||||
|
||||
1. Review the entire conversation history for this feature.
|
||||
2. Synthesize the findings into a structured Markdown file.
|
||||
3. **Critical Check:** If you find a logical contradiction or missing core requirement during synthesis:
|
||||
- **STOP.**
|
||||
- Do not write the file.
|
||||
- Report the issue to the user: "I cannot consolidate yet because [Reason]. What should happen in this case?"
|
||||
- Return to **Detective Mode**.
|
||||
4. **Action:** If all is clear, create `design/feature/<feature-slug>/` if needed, write the file to `design/feature/<feature-slug>/discovery.md`, and create or update `design/feature/<feature-slug>/status.md` from `docs/reference/design-status-template.md`.
|
||||
5. **Format:**
|
||||
|
||||
```markdown
|
||||
# Feature Discovery: [Feature Name]
|
||||
|
||||
## 1. Commands (User Intents)
|
||||
|
||||
- [Actor] wants to [Action] because [Reason].
|
||||
|
||||
## 2. Events (Domain Facts)
|
||||
|
||||
- [EventName] happened (payload: ...).
|
||||
|
||||
## 3. Business Rules & Invariants
|
||||
|
||||
- Rule: [Description]
|
||||
- Invariant: [Description]
|
||||
|
||||
## 4. Edge Cases Handled
|
||||
|
||||
- Case: [Description] -> [Resolution]
|
||||
|
||||
## 5. Candidate Bounded Contexts
|
||||
|
||||
- [ContextName]: [What it appears to own]
|
||||
|
||||
## 6. Candidate Workflow Slices
|
||||
|
||||
- [ContextName]/[workflow-slug]: [Purpose]
|
||||
|
||||
## 7. Shared Language Notes
|
||||
|
||||
- Preferred term: [Term] = [Meaning]
|
||||
- Avoid: [Synonym] when you mean [Preferred term]
|
||||
```
|
||||
|
||||
6. If stable terminology emerged, explicitly define it in the relevant `src/<bounded-context>/CONTEXT.md` using the domain-specific dictionary format (with `_Avoid_` aliases, Example dialogues, etc.).
|
||||
7. **Final Output:** "Feature discovery frozen at `design/feature/<feature-slug>/discovery.md`. Ready for Phase 2 (Context & Workflow Decomposition)."
|
||||
|
||||
## Usage Examples
|
||||
|
||||
**User:** "I want a truck loading system."
|
||||
**Agent (Detective):** "Okay. When a truck arrives, do we know its capacity beforehand? What happens if a package is scanned but doesn't fit?"
|
||||
|
||||
**User:** "Capacity is known. If it doesn't fit, reject it."
|
||||
**Agent (Detective):** "Understood. What if the truck is already sealed? Can we unseal it? Or is that a strict error?"
|
||||
|
||||
**User:** "Strict error. Consolidate."
|
||||
**Agent (Scribe):** [Writes `design/feature/<feature-slug>/discovery.md`] "Feature discovery frozen."
|
||||
@@ -0,0 +1,110 @@
|
||||
---
|
||||
name: tdfddd-refactor-diagnosis
|
||||
description: "Refactor phase: scope, change-pressure, and seam diagnosis. Reviews existing code to explain what should be split, merged, renamed, or kept inline before refactoring. Use when planning a refactor, diagnosing seam problems, or deciding whether code should become a policy, model, service, task, or module."
|
||||
---
|
||||
|
||||
# Refactor Diagnosis Agent: The Seam Analyst
|
||||
|
||||
## Description
|
||||
|
||||
Refactor phase: scope, change-pressure, and seam diagnosis.
|
||||
Use this skill to inspect existing code and explain what shape problem actually exists before changing structure.
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
Activate when the user:
|
||||
|
||||
- Says "diagnose this refactor".
|
||||
- Wants to know whether to split, merge, rename, or leave code alone.
|
||||
- Wants help identifying weak seams, tangled responsibilities, or top-level workflow sprawl.
|
||||
- Wants to know whether logic should be a policy, model, service, task, or module.
|
||||
- Wants a refactor plan before execution.
|
||||
|
||||
## Core Function: The Refactor Diagnosis Protocol
|
||||
|
||||
**Goal:** Produce a reviewable diagnosis of current shape problems and a clear target seam before code moves begin.
|
||||
|
||||
**Required input:**
|
||||
|
||||
- a declared scope: `micro`, `meso`, or `macro`
|
||||
- target code or files
|
||||
- the current pain or trigger for the refactor
|
||||
|
||||
If the user does not provide scope, infer a provisional scope and state it explicitly.
|
||||
|
||||
## Instructions
|
||||
|
||||
1. Read the relevant code before making any structural claim.
|
||||
2. Start by restating the refactor scope:
|
||||
- **micro:** function, type, parameter list, local extraction
|
||||
- **meso:** task, workflow, module seam
|
||||
- **macro:** cross-module or bounded-context reshaping
|
||||
3. State the preserved behavior and non-goals if they are known.
|
||||
- If missing and critical, ask for them.
|
||||
4. Perform a lightweight **change-pressure scan** using current evidence:
|
||||
- what is changing together?
|
||||
- what should change independently?
|
||||
- where are there pass-through parameters?
|
||||
- where is repeated branching happening?
|
||||
- where is top-level coordination growing into a pile?
|
||||
5. Diagnose candidate seams using these questions:
|
||||
- What is the real purpose of this code?
|
||||
- Is the name intention-based or mechanical?
|
||||
- What should the caller know, and what should stay hidden?
|
||||
- Is this really a policy, model operation, service, task, or module?
|
||||
- Does it require too much authority?
|
||||
- Does it force too much caller knowledge?
|
||||
- Would three likely variations still fit naturally?
|
||||
6. Distinguish between:
|
||||
- a real abstraction
|
||||
- a temporary extraction for readability
|
||||
- a false seam that only renames plumbing
|
||||
7. Recommend the smallest justified shape change.
|
||||
- prefer inline code if the seam is not real yet
|
||||
- prefer task extraction before workflow-to-workflow calls when possible
|
||||
- prefer module extraction only when a bounded capability is repeatedly useful
|
||||
8. Output a compact diagnosis report with these sections:
|
||||
|
||||
```markdown
|
||||
## Refactor Scope
|
||||
|
||||
- Scope: micro|meso|macro
|
||||
- Preserved behavior: ...
|
||||
- Non-goals: ...
|
||||
|
||||
## Change Pressure
|
||||
|
||||
- Changes together: ...
|
||||
- Should change independently: ...
|
||||
- Evidence: ...
|
||||
|
||||
## Seam Diagnosis
|
||||
|
||||
- Current seam/problem: ...
|
||||
- Why it is weak or overloaded: ...
|
||||
- Correct shape: policy|model|service|task|module|keep inline
|
||||
- 3-variation check: ...
|
||||
|
||||
## Target Shape
|
||||
|
||||
- Proposed boundary name: ...
|
||||
- Public contract: ...
|
||||
- What stays hidden: ...
|
||||
- Why this reduces review load: ...
|
||||
```
|
||||
|
||||
## Constraints
|
||||
|
||||
- Do not write implementation code unless the user explicitly asks to proceed.
|
||||
- Do not recommend extra layers without clear pressure.
|
||||
- Do not confuse services with business decisions.
|
||||
- Do not assume the top level must stay monolithic; top-level coordination seams are valid refactor targets.
|
||||
|
||||
## Success Criteria
|
||||
|
||||
A good diagnosis should let a human reviewer answer:
|
||||
|
||||
- what problem is being fixed
|
||||
- why this seam is real
|
||||
- why the proposed shape is smaller or clearer
|
||||
- what should be preserved during execution
|
||||
@@ -0,0 +1,103 @@
|
||||
---
|
||||
name: tdfddd-refactor-execution
|
||||
description: "Refactor phase: safety net, small-step reshape, and proof. Executes a scoped refactor while preserving behavior, tightening seams, and verifying that the new shape is easier to review. Use when a refactor diagnosis or target seam is already clear and code should be changed."
|
||||
---
|
||||
|
||||
# Refactor Execution Agent: The Reshaper
|
||||
|
||||
## Description
|
||||
|
||||
Refactor phase: safety net, small-step reshape, and proof.
|
||||
Use this skill when the target seam is already clear enough to change code safely.
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
Activate when the user:
|
||||
|
||||
- Says "execute this refactor".
|
||||
- Has already identified a seam problem and wants code changed.
|
||||
- Wants to extract a policy, model operation, task, or module.
|
||||
- Wants to simplify a workflow without changing behavior.
|
||||
|
||||
## Core Function: The Refactor Execution Protocol
|
||||
|
||||
**Goal:** Reshape existing code in small verified moves while preserving behavior and improving seam quality.
|
||||
|
||||
**Required input:**
|
||||
|
||||
- a declared scope: `micro`, `meso`, or `macro`
|
||||
- target code or files
|
||||
- preserved behavior
|
||||
- target seam or intended new shape
|
||||
|
||||
If a diagnosis is missing, do a minimal inline diagnosis before changing code.
|
||||
|
||||
## Instructions
|
||||
|
||||
1. Read the current code and restate:
|
||||
- scope
|
||||
- preserved behavior
|
||||
- non-goals
|
||||
- target seam
|
||||
2. Create or tighten a **safety net** before structural moves:
|
||||
- add or improve tests at the public seam when needed
|
||||
- rely on types where they already give strong guarantees
|
||||
- stop and clarify if preserved behavior is ambiguous
|
||||
3. Reshape in small steps:
|
||||
- move one responsibility at a time
|
||||
- keep the system runnable after each move
|
||||
- extract policies for pure business decisions
|
||||
- extract model operations for deterministic state transitions
|
||||
- extract tasks for meaningful orchestration steps
|
||||
- extract modules only when a bounded capability is truly emerging
|
||||
4. Keep boundaries intention-based:
|
||||
- prefer APIs named by caller intent
|
||||
- hide mechanics and helper sequencing inside the seam
|
||||
5. Avoid false progress:
|
||||
- do not create wrappers that only rename plumbing
|
||||
- do not widen interfaces for convenience
|
||||
- do not move business logic into services
|
||||
- do not expand scope into unrelated cleanup
|
||||
6. Verify after each meaningful move and again at the end.
|
||||
7. Report proof, not vibes.
|
||||
|
||||
## Output Format
|
||||
|
||||
```markdown
|
||||
## Refactor Outcome
|
||||
|
||||
- Scope: micro|meso|macro
|
||||
- Preserved behavior: ...
|
||||
- Target seam: ...
|
||||
|
||||
## Changes Made
|
||||
|
||||
- ...
|
||||
|
||||
## Verification
|
||||
|
||||
- Tests/types/checks run: ...
|
||||
- Result: ...
|
||||
|
||||
## Seam Improvement
|
||||
|
||||
- Caller knows less about: ...
|
||||
- Hidden internally now: ...
|
||||
- Authority/dependency surface now: ...
|
||||
```
|
||||
|
||||
## Constraints
|
||||
|
||||
- Preserve behavior unless the user explicitly approves a behavior change.
|
||||
- Prefer the smallest correct refactor.
|
||||
- Use public module APIs for cross-module calls when available.
|
||||
- Stop if the refactor reveals a design contradiction that requires user input.
|
||||
|
||||
## Success Criteria
|
||||
|
||||
A good execution leaves behind:
|
||||
|
||||
- preserved behavior
|
||||
- a seam that is easier to explain
|
||||
- smaller or clearer dependency authority
|
||||
- lower review load for future human or LLM work
|
||||
@@ -0,0 +1,121 @@
|
||||
---
|
||||
name: tdfddd-security-verification
|
||||
description: "Reviews TDFDDD design artifacts or implemented code for security risks. Use when manually asked to review requirements, domain models, workflow designs, ADRs, or changed code for trust boundaries, least privilege, zero trust, blast radius, and related security concerns."
|
||||
---
|
||||
|
||||
# TDFDDD Security Verification
|
||||
|
||||
Reviews design artifacts or implemented code for security risks.
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
Activate only when manually requested for a security review.
|
||||
|
||||
This skill handles both **Design** and **Implementation** reviews depending on what the user asks you to look at.
|
||||
|
||||
Do **not** implement fixes. This skill is **review-only**.
|
||||
|
||||
## Security Philosophy
|
||||
|
||||
The mechanical checks in this skill serve to enforce the following guiding principles:
|
||||
|
||||
- **Assume Breach**: Understand that perimeters fail; assume malicious input and compromised components already exist inside the system.
|
||||
- **Zero Trust**: Never grant implicit trust based on network location or component origin. Verify identity, context, and input explicitly at every bounded seam.
|
||||
- **Least Privilege**: Ensure components, workflows, and services only possess the exact authority (capabilities, data access) required for the current slice, and nothing more.
|
||||
- **Defense in Depth**: Require multiple layers of security controls so that if one fails, others mitigate the impact.
|
||||
- **Blast Radius Reduction**: Ensure isolation boundaries prevent a compromise in one workflow or dependency from spreading across the rest of the system.
|
||||
|
||||
## Core Rules
|
||||
|
||||
1. **Grill the human first**: If scope is ambiguous, ask what to review before starting.
|
||||
2. **Review Target**: Default to reviewing the listed artifacts or the changed files plus adjacent seams. Check dependencies/versions *only* if the user requests "Expanded Surface Mode."
|
||||
3. **Findings Only**: Do not pad the report with positive confirmations.
|
||||
4. **Cite Evidence**: Every concrete finding must cite the exact file/line/section it comes from.
|
||||
5. **Categorize Risk**:
|
||||
- If you suspect a problem but cannot prove it, label it **Possible Concern**.
|
||||
- If you cannot assess a category from the provided materials, label it **Insufficient Evidence**.
|
||||
6. Reference relevant external standards when useful, especially OWASP ASVS and OWASP cheat sheets.
|
||||
|
||||
## Master Review Categories
|
||||
|
||||
Review every category below. If a category is not visible in the provided scope, mark it accordingly rather than skipping it.
|
||||
|
||||
1. Trust Boundaries & Data Flow
|
||||
2. Input Parsing & Validation (See `docs/explanation/architecture/input-security.md` for specific tainted string wrappers)
|
||||
3. Sink Handling & Contextual Sanitization
|
||||
4. Capabilities & Least Privilege
|
||||
5. Secrets & Sensitive Config
|
||||
6. Isolation & Blast Radius
|
||||
7. Dependency & Supply Chain Assumptions
|
||||
8. AuthN/AuthZ if applicable
|
||||
9. Logging, Telemetry & Detection
|
||||
10. Recovery & Failure Modes
|
||||
11. Unsafe Dynamic Behavior
|
||||
12. Security Testing Coverage
|
||||
|
||||
## Phase-Specific Heuristics
|
||||
|
||||
### If reviewing DESIGN artifacts:
|
||||
- Do not demand code-level proof from design artifacts.
|
||||
- Do demand that risky areas are named and bounded.
|
||||
- Missing security design information is itself a valid finding.
|
||||
- Treat “we will sanitize later” as weak unless the sink categories and ownership are explicit.
|
||||
- Prefer structural security reasoning:
|
||||
- where untrusted data enters
|
||||
- how it is parsed into trusted types
|
||||
- what authority the workflow slice requires
|
||||
|
||||
### If reviewing IMPLEMENTATION:
|
||||
- Look for raw untrusted data crossing into trusted domain types without parsing.
|
||||
- Look for sink misuse: SQL building, shell execution, HTML rendering, URLs, file paths, template rendering, logging, dynamic code loading.
|
||||
- Prefer parameterized APIs and framework safe sinks over handwritten escaping.
|
||||
- Look for over-broad injected capabilities, especially services that grant more authority than the workflow needs.
|
||||
- Distinguish purity from privilege: pure code can still orchestrate overly powerful services.
|
||||
- Treat missing tests at risky seams as a security finding.
|
||||
|
||||
## Required Output Format
|
||||
|
||||
```markdown
|
||||
# Security Verification Report
|
||||
|
||||
## Phase: [Design / Implementation]
|
||||
|
||||
## Scope Reviewed
|
||||
|
||||
- ...
|
||||
|
||||
## Artifacts Read
|
||||
|
||||
- ...
|
||||
|
||||
## Security Assumptions
|
||||
|
||||
- ...
|
||||
|
||||
## Overall Risk Summary
|
||||
|
||||
- ...
|
||||
|
||||
## 1. Trust Boundaries & Data Flow
|
||||
|
||||
- [Finding|Possible Concern|Insufficient Evidence] Severity: X/10
|
||||
- Evidence: file/section/line
|
||||
- Why it matters: ...
|
||||
- Suggested fix: ...
|
||||
|
||||
## 2. Input Parsing & Validation
|
||||
|
||||
...
|
||||
|
||||
## 3. Sink Handling & Contextual Sanitization
|
||||
|
||||
... (continue for all 12 categories) ...
|
||||
|
||||
## Cross-Cutting Questions
|
||||
|
||||
- ...
|
||||
|
||||
## Suggested Next Actions
|
||||
|
||||
- ...
|
||||
```
|
||||
@@ -0,0 +1,88 @@
|
||||
---
|
||||
name: tdfddd-slice-discovery
|
||||
description: "Phase 3: Slice discovery. Interrogates a single workflow slice inside one bounded context to tighten requirements, edge cases, invariants, and handoff assumptions before core sketching. Use after context/workflow decomposition and before core sketch. Triggers on: slice discovery, workflow discovery, interrogate this workflow, refine workflow slice."
|
||||
---
|
||||
|
||||
# Slice Discovery Agent: The Slice Detective
|
||||
|
||||
## Description
|
||||
|
||||
Phase 3: Slice Discovery.
|
||||
Deepens discovery for one workflow slice so Core Sketch starts from a well-bounded, well-questioned contract.
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
Activate when the user:
|
||||
|
||||
- Says "discover this workflow".
|
||||
- Says "interrogate this slice".
|
||||
- Says "workflow discovery" after decomposition is complete.
|
||||
- Wants to prepare one workflow slice for core sketching.
|
||||
|
||||
## Core Function: The Slice Interrogation Protocol
|
||||
|
||||
**Goal:** Clarify one workflow slice deeply enough that Core Sketch can identify state and policy shape without guessing.
|
||||
|
||||
**Constraints:**
|
||||
|
||||
- Operate on exactly one workflow at a time.
|
||||
- Read `design/feature/<feature-slug>/discovery.md`, `design/feature/<feature-slug>/design.md`, the relevant `src/<bounded-context-slug>/CONTEXT.md`, and `design/workflows/<bounded-context-slug>/<workflow-slug>/01-decomposition.md`.
|
||||
- Do not reopen the whole feature unless a contradiction forces it.
|
||||
- Default rule: no cross-context decision logic inside the slice.
|
||||
- Record feature-level handoff assumptions, but keep slice decisions local.
|
||||
|
||||
## Instructions
|
||||
|
||||
1. Read the feature and workflow decomposition artifacts for the selected slice.
|
||||
2. Identify the happy path, unhappy paths, invariant checks, timing issues, ownership boundaries, and handoff assumptions for this slice only.
|
||||
3. Ask clarifying questions one branch at a time when needed. Actively "grill" the user if definitions clash or if terms are ambiguous (`"You say 'Account', but earlier we defined that as 'Customer'. Which is it?"`).
|
||||
4. Restate the slice in plain domain language as understanding stabilizes.
|
||||
5. Capture stable naming decisions in `src/<bounded-context-slug>/CONTEXT.md` inline during the session. Use the strict Glossary format (`**Term**`, `_Avoid_`, Example dialogues) and do not include implementation details.
|
||||
6. When the user says `Consolidate`, `Ready to sketch`, or `Freeze slice`, write `design/workflows/<bounded-context-slug>/<workflow-slug>/02-discovery.md`.
|
||||
7. If a contradiction or missing prerequisite slice blocks progress, stop and report it rather than inventing an answer.
|
||||
8. Final output should state that the slice is ready for Core Sketch.
|
||||
|
||||
## Required Artifact
|
||||
|
||||
### `design/workflows/<bounded-context-slug>/<workflow-slug>/02-discovery.md`
|
||||
|
||||
```markdown
|
||||
# Slice Discovery: <Workflow Name>
|
||||
|
||||
- Bounded context: `<ContextName>`
|
||||
- Workflow slug: `<workflow-slug>`
|
||||
|
||||
## Happy Path
|
||||
|
||||
- `<step>`
|
||||
|
||||
## Edge Cases
|
||||
|
||||
- `<case>` -> `<resolution>`
|
||||
|
||||
## Business Rules & Invariants
|
||||
|
||||
- Rule: `<description>`
|
||||
- Invariant: `<description>`
|
||||
|
||||
## Required Decisions Owned by This Context
|
||||
|
||||
- `<decision>`
|
||||
|
||||
## Handoff Assumptions
|
||||
|
||||
- `<upstream or downstream assumption>`
|
||||
|
||||
## Open Questions
|
||||
|
||||
- `<question or none>`
|
||||
```
|
||||
|
||||
## Success Criteria
|
||||
|
||||
A good slice discovery leaves behind:
|
||||
|
||||
- one workflow slice clarified deeply enough for sketching
|
||||
- edge cases and invariants captured
|
||||
- context language tightened
|
||||
- cross-context assumptions made explicit without moving decision logic out of the owning context
|
||||
Reference in New Issue
Block a user