Initial commit

This commit is contained in:
ada
2026-05-25 05:47:28 +00:00
commit 4d6495ffda
97 changed files with 13403 additions and 0 deletions
+267
View File
@@ -0,0 +1,267 @@
# 2. The Design Protocol (TDFDDD)
**Type-Driven Functional Domain-Driven Design**
This is the rigorous process we use to discover, design, and implement features.
Do not skip steps.
Do not write implementation code until the design is frozen.
## How to read this page
This page is the **current protocol** for real work in this repository.
It keeps the explanatory logic from the original 5-phase method, but rearranges that logic to fit the new **feature-first, slice-first** process.
- The old 5-phase design logic still exists as the conceptual backbone.
- The repository workflow now applies that logic across **feature artifacts** and then **one workflow slice at a time**.
- The simpler human practice flow is preserved in [../by-hand/README.md](../by-hand/README.md).
## The governing idea
The key shift is:
1. **Discover the feature broadly first** so bounded contexts, handoffs, and workflow inventory are visible.
2. **Then design and implement one workflow slice at a time** inside one bounded context.
This keeps the rich domain reasoning from TDFDDD while avoiding monolithic feature-wide blueprints and bloated implementation passes.
## Phase 1: Feature Discovery
_Goal: Understand the feature as a whole before designing any single slice._
This phase inherits the old **event storming / discovery** logic, but applies it at the **feature level**.
The job is to identify **what happens** in the business story without worrying about code yet.
### What to do
1. Identify the feature story, actors, commands, and outcomes.
2. Identify the main business process and major domain facts.
3. Capture feature-level business rules, invariants, and edge cases.
4. Resolve the decision tree one branch at a time instead of jumping across many ambiguities at once.
5. Ask clarifying questions one at a time, and periodically restate the current shared understanding before moving on.
6. Identify candidate bounded contexts.
7. Identify candidate workflow slices.
8. When terminology stabilizes, record:
- project-wide terms in `docs/reference/shared-language.md`
- feature-level terms in `design/feature/<feature-slug>/discovery.md`
9. Write `design/feature/<feature-slug>/discovery.md`.
10. Create or update `design/feature/<feature-slug>/status.md`.
### Why this phase exists
If the feature story itself is muddy, everything downstream will be muddy too.
A weak feature discovery causes false bounded contexts, confused workflow ownership, and shallow slice design later.
### Output
- `design/feature/<feature-slug>/discovery.md`
- `design/feature/<feature-slug>/status.md`
## Phase 2: Context & Workflow Decomposition
_Goal: Map the feature into bounded contexts, workflow slices, and handoffs._
This is the major addition to the protocol.
It sits between broad feature discovery and deep single-slice design.
It exists so we do not accidentally core-sketch a workflow without understanding where it lives, what it owns, and what it hands off.
### What to do
1. Confirm the bounded contexts touched by the feature.
2. Map feature steps to workflow slices.
3. Record cross-context handoffs and orchestration notes in `design/feature/<feature-slug>/design.md`.
4. Create or update `design/workflows/<bounded-context-slug>/shared-language.md` for each context involved.
5. Create `design/workflows/<bounded-context-slug>/<workflow-slug>/01-decomposition.md` for each slice.
6. Choose a recommended slice implementation order.
7. Update the feature status file so the decomposition and slice inventory are visible.
### Why this phase exists
The old process worked well for a single workflow, but it was easy to over-apply it to a whole feature.
That created large sketches, blurred bounded contexts, and implementation passes that were too big.
Decomposition fixes that by making workflow ownership and handoffs explicit before deep design starts.
### Output
- `design/feature/<feature-slug>/design.md`
- `design/workflows/<bounded-context-slug>/shared-language.md`
- `design/workflows/<bounded-context-slug>/<workflow-slug>/01-decomposition.md`
- updated `design/feature/<feature-slug>/status.md`
## Phase 3: Slice Discovery
_Goal: Interrogate one workflow slice deeply enough to sketch it well._
This phase brings the old discovery questions back, but only for one selected workflow slice.
The point is to prevent the later F# sketch from being shallow or under-informed.
### What to do
1. Select exactly one workflow slice.
2. Clarify the happy path, unhappy paths, invariants, and edge cases for that slice.
3. Clarify what the slice owns versus what it only observes from other contexts.
4. Record handoff assumptions.
5. Restate the slice in plain domain language until the ownership boundary feels crisp.
6. Update bounded-context shared language if terminology stabilizes.
7. Write `design/workflows/<bounded-context-slug>/<workflow-slug>/02-discovery.md`.
### Why this phase exists
Your worry here is the right one: a core sketch is weak if the workflow-specific discovery is weak.
Feature discovery should map the terrain.
Slice discovery should interrogate the one path you are actually about to design.
### Output
- `design/workflows/<bounded-context-slug>/<workflow-slug>/02-discovery.md`
- optional updates to `design/workflows/<bounded-context-slug>/shared-language.md`
## Phase 4: Core Sketch
_Goal: Figure out what information is required to make the decision for one workflow slice._
This is still the old **core sketch / policy signature** phase, now applied to exactly one bounded-context workflow.
At this stage, the emphasis is still on **what information is needed**, not on fully modeled types.
### What to do
1. Draft the slice policy signature in **F# pseudo-code**.
2. Determine the required owned state needed to answer the question.
3. Identify any observed external inputs or handoff data that the slice may read.
4. Record the command, events, and boundary notes.
5. Write `design/workflows/<bounded-context-slug>/<workflow-slug>/03-core-sketch.md`.
### What this phase is not
- It is **not** the full domain model yet.
- It is **not** implementation.
- It is **not** cross-context orchestration design.
The job is to reveal the decision boundary clearly enough that modeling can become precise.
### Output
- `design/workflows/<bounded-context-slug>/<workflow-slug>/03-core-sketch.md`
## Phase 5: Blueprint
_Goal: Freeze the contract in F# for one workflow slice._
This phase combines the old **domain modeling** and **contract finalization** logic for one slice.
F# remains the primary design language and frozen contract before assembly.
### What to do
1. Model the **primitives**.
2. Model the **compounds**.
3. Model the **aggregates / states**.
4. Model the **events**.
5. Finalize the signatures for:
- `decide`
- `apply`
- the workflow boundary
6. Treat the F# blueprint as the authoritative design contract.
7. Write `design/workflows/<bounded-context-slug>/<workflow-slug>/04-blueprint.fs`.
8. Update `design/workflows/<bounded-context-slug>/shared-model.fs` only when the context gains reusable shared F# pieces.
### Design standards in this phase
- Avoid primitive obsession.
- Make illegal states unrepresentable.
- Keep the policy pure.
- Model outputs as domain facts, not booleans.
- Separate:
- policy for pure decisions
- model for pure state transition math
- workflow for impure orchestration
### Why F# matters here
F# is not an optional flavoring step.
It is the design language that makes the contract precise before implementation starts.
If the blueprint is weak, assembly will start inventing domain meaning instead of translating it.
### Output
- `design/workflows/<bounded-context-slug>/<workflow-slug>/04-blueprint.fs`
- optional updates to `design/workflows/<bounded-context-slug>/shared-model.fs`
## Phase 6: Assembly
_Goal: Translate one frozen F# blueprint into code._
This is still the old implementation / assembly phase, but it now runs on **exactly one workflow slice at a time**.
Assembly is a translation step from the frozen F# contract, not a redesign step.
### What to do
1. Read one `04-blueprint.fs` file.
2. Translate F# types to Effect schemas and TypeScript constructs.
3. Derive executable specifications from the frozen contract:
- workflow scenarios from the command and events
- policy examples from the decision rules
- model invariants from the state definitions
4. Implement using vertical **RED -> GREEN -> REFACTOR** cycles:
- write one failing test for one observable behavior at the public seam
- write the minimal code to make it pass
- refactor only while green
5. Keep tests focused on behavior through the contract, not implementation details.
6. Concentrate review rigor at the design and seam level.
7. Update `design/feature/<feature-slug>/status.md` for the current slice.
### Test style by seam
- **Models / Policies (Pure):** example-based tests plus property-based tests for invariants and edge cases.
- **Workflows (Impure):** scenario tests using Effect test layers or in-memory adapters.
- **Services / Adapters:** contract tests and integration tests against real infrastructure when needed.
### Review emphasis
- Review policies and workflows closely because they carry business meaning and orchestration correctness.
- Review service and adapter internals mainly for seam correctness, capability behavior, and absence of misplaced business logic.
- Trust strong domain types and contracts to reduce how much infrastructure code must be re-derived line by line.
## Rules that apply across phases
- One workflow slice belongs to one bounded context.
- No cross-context decision logic belongs inside a workflow slice.
- Cross-context behavior belongs in feature-level handoff and orchestration notes.
- Shared language should exist both globally and per bounded context.
- F# remains the primary design language and frozen contract before assembly.
- Implementation should proceed one workflow slice at a time.
- For the exact artifact layout, see [../reference/design-artifact-structure.md](../reference/design-artifact-structure.md).
## Security Verification
Security review is a required part of the process even though it is not itself a core design phase.
It acts as a verification gate around the design and implementation work.
### Design security verification
Run a security review on the frozen design before or during the transition from blueprint to assembly, when the slice has enough shape to inspect.
Review at least:
- the workflow story and trust boundaries
- the domain model and capability boundaries
- sink categories and sanitization ownership
- secrets handling assumptions
- blast-radius and isolation assumptions
- detection, recovery, and security test expectations
In Amp, use the `tdfddd-security-verification` skill when you want a structured, review-only report.
### Implementation security verification
Run a second security review after implementation on the changed workflow slice and its adjacent seams.
Expand the scope only when needed.
Review at least:
- untrusted input parsing into trusted domain types
- dangerous sinks and context-specific protections
- over-broad capabilities or injected authority
- secret and sensitive-config handling
- unsafe dynamic behavior
- security-focused test coverage at risky seams
In Amp, use the `tdfddd-security-verification` skill for a structured, review-only report over code and nearby surfaces.