Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .flowr/flows/develop-flow.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ exits:
states:
- id: feature-selection
attrs:
description: "PO selects the next feature — by delivery order for first feature, by WSJF for subsequent features"
description: "PO selects the next feature — by dependency count then WSJF"
owner: PO
git: dev
skills:
Expand Down
1 change: 0 additions & 1 deletion .flowr/flows/discovery-flow.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ states:
- why
- users
- out_of_scope
- delivery_order
- quality_attributes
- domain_spec.md:
- context_map
Expand Down
20 changes: 10 additions & 10 deletions .opencode/knowledge/requirements/feature-boundaries.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
---
domain: requirements
tags: [feature-boundaries, story-mapping, delivery-order, bounded-contexts, feature-naming]
tags: [feature-boundaries, bounded-contexts, feature-naming]
last-updated: 2026-05-08
---

# Feature Boundaries

## Key Takeaways

- Feature boundaries are derived from simulation-created .feature files, validated against the delivery order in product_definition.md, the context map, and aggregate boundaries from the domain spec. Each .feature file from simulation is a feature candidate; candidates may be split, renamed, or merged.
- A feature should belong to primarily one bounded context. If a delivery step spans two or more contexts, split it along context boundaries.
- Feature boundaries are derived from simulation-created .feature files, validated against the context map and aggregate boundaries from the domain spec. Each .feature file from simulation is a feature candidate; candidates may be split, renamed, or merged.
- A feature should belong to primarily one bounded context. If a feature spans two or more contexts, split it along context boundaries.
- A feature should not span multiple aggregate transactional consistency boundaries. If it does, split along aggregate lines.
- Feature names follow the `[Capability]` pattern from the delivery step. Descriptions answer: what it provides, which context it serves, why it exists, and key entities.
- Feature names follow the `[Capability]` pattern. Descriptions answer: what it provides, which context it serves, why it exists, and key entities.
- Cross-cutting concerns (risk management, error handling, observability) are not separate features — they appear as Constraints in the features that implement them.

## Concepts

**Delivery Order as Backbone**: Patton (2014) recommends mapping the user's narrative flow as a backbone, then slicing vertically into releasable increments. The .feature files created during simulation capture the discovered behavior — the delivery order in product_definition.md validates the dependency graph. .feature files are refined into independently deliverable features that follow the validated delivery order.
**Context Map as Backbone**: Patton (2014) recommends mapping the user's narrative flow as a backbone, then slicing vertically into releasable increments. The .feature files created during simulation capture the discovered behavior — the context map from domain_spec.md validates the dependency graph. .feature files are refined into independently deliverable features whose delivery order is derived at selection time via dependency count and WSJF.

**Context Alignment Validation**: Each feature candidate must be checked against the domain spec's bounded context table. A feature that touches entities from two or more contexts has a boundary problem. Split it: each context gets its own feature. The domain spec's "Why Separate" column explains why the contexts were split — the feature split must respect the same reasoning.

**Aggregate Boundary Validation**: Aggregates define transactional consistency boundaries. A feature that modifies data across two aggregates in one transaction violates aggregate design. If a delivery step spans multiple aggregates, split the feature so each aggregate's invariants are tested within one feature.
**Aggregate Boundary Validation**: Aggregates define transactional consistency boundaries. A feature that modifies data across two aggregates in one transaction violates aggregate design. If a feature spans multiple aggregates, split the feature so each aggregate's invariants are tested within one feature.

**Naming and Description Convention**: Feature names come from the delivery step name, validated for clarity. Good names are specific enough that a developer knows what to build and a tester knows what to verify. Descriptions follow a four-part pattern: (1) what the feature provides, (2) which bounded context it serves, (3) why it exists — the business need, (4) key entities from the domain spec that belong to this feature.
**Naming and Description Convention**: Feature names are noun phrases validated for clarity. Good names are specific enough that a developer knows what to build and a tester knows what to verify. Descriptions follow a four-part pattern: (1) what the feature provides, (2) which bounded context it serves, (3) why it exists — the business need, (4) key entities from the domain spec that belong to this feature.

**Cross-Cutting Concerns**: Risk management, error handling, logging, and observability span multiple contexts. These are not separate features. Instead, they appear as Constraints in the features where they are implemented. The domain spec's context map shows which contexts have safety or error-handling responsibilities. Map those responsibilities to Constraints, not to separate features.

Expand All @@ -32,7 +32,7 @@ last-updated: 2026-05-08

### Feature Boundary Derivation Process

1. **List delivery steps as feature candidates**: Read product_definition.md delivery order. Each numbered step is a feature candidate. Record: step number, name, module, and summary.
1. **List feature candidates**: Each bounded context's simulation-created .feature file is a feature candidate. Record: context name, entities, and summary.

2. **Map each candidate to bounded contexts**: For each candidate, identify which bounded contexts its entities belong to using the domain spec's entity table. If a candidate spans multiple contexts, split it.

Expand All @@ -44,13 +44,13 @@ last-updated: 2026-05-08

### Splitting Criteria

When a delivery step spans multiple contexts or aggregates:
When a feature spans multiple contexts or aggregates:

| Signal | Split | Keep together |
|--------|-------|---------------|
| Spans 2+ bounded contexts | Split along context boundaries | Shared-kernel types (Domain shared), Orchestrator, Tightly coupled co-deployed |
| Spans 2+ aggregates | Split along aggregate boundaries | If aggregates must be transactionally consistent |
| Delivery step name contains "and" | Likely two features | If "and" joins inseparable aspects |
| Feature name contains "and" | Likely two features | If "and" joins inseparable aspects |

### Cross-Cutting Concern Mapping

Expand Down
7 changes: 4 additions & 3 deletions .opencode/knowledge/requirements/feature-discovery.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ last-updated: 2026-05-14
- Rules are written directly to .feature files during simulation. Refine-features (in define-flow) splits, renames, adds descriptions, and validates rules. After define-flow, Feature titles, Rule titles, and Constraints are FROZEN.
- Gaps discovered during feature refinement (a bounded context with no feature, a quality attribute with no enforcing feature) are flagged, not silently filled.
- Features progress through a lifecycle: Rule blocks from simulation → feature boundaries and descriptions from refine-features → Example blocks from feature-examples.
- Feature selection order is derived at selection time from the context map dependency graph and WSJF scoring — not from a pre-authored delivery order.

## Concepts

Expand All @@ -27,7 +28,7 @@ last-updated: 2026-05-14

**Feature Lifecycle**: Features follow a lifecycle of increasing specificity across phases:
1. **Simulation** (define-flow): Rules written directly to .feature files during simulation, grouped by bounded context. Technology constraints written as `# Constraints:`.
2. **Refinement** (define-flow, refine-features): Feature boundaries identified from simulation-created .feature files. Features are split/renamed based on Delivery Order and context map. Rule blocks redistributed (content unchanged). Quality attributes mapped to `# Constraints:`. Rule titles validated for INVEST. Feature titles and descriptions finalized.
2. **Refinement** (define-flow, refine-features): Feature boundaries identified from simulation-created .feature files. Features are split/renamed based on context map and aggregate boundaries. Rule blocks redistributed (content unchanged). Quality attributes mapped to `# Constraints:`. Rule titles validated for INVEST. Feature titles and descriptions finalized.
3. **Example Writing** (develop-flow, feature-examples): Rules converted to Gherkin Example/Scenario Outline blocks with pre-mortem analysis.

## Content
Expand All @@ -36,7 +37,7 @@ last-updated: 2026-05-14

Feature discovery is two sequential activities:

1. **Boundary identification** (refine-features skill): Use the delivery order from product_definition.md as backbone. Map each step to bounded contexts and aggregates from the domain spec. Split candidates that span contexts or aggregates. Name features and write descriptions per [[requirements/feature-boundaries]].
1. **Boundary identification** (refine-features skill): Use the context map from domain_spec.md as backbone. Map each bounded context to feature candidates from simulation-created .feature files. Split candidates that span contexts or aggregates. Name features and write descriptions per [[requirements/feature-boundaries]].

2. **Rule organization** (refine-features skill): For each feature, organize the Rule blocks already written to .feature files during simulation. Split/rename Rules per context boundaries. Map quality attributes to constraints. Write `# Constraints:` into each .feature file. Validate INVEST criteria.

Expand All @@ -53,7 +54,7 @@ Gaps are recorded in the relevant interview notes. Do NOT silently fill gaps wit

## Related

- [[requirements/feature-boundaries]]: deriving feature boundaries from delivery order and domain spec
- [[requirements/feature-boundaries]]: deriving feature boundaries from context map and domain spec
- [[requirements/spec-simulation]]: how rules are discovered during simulation
- [[requirements/invest]]: INVEST criteria applied to Rule blocks
- [[requirements/wsjf]]: feature prioritization applied to BASELINED features
Expand Down
4 changes: 2 additions & 2 deletions .opencode/skills/create-domain-spec/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Available knowledge: [[domain-modeling/event-storming#concepts]], [[domain-model

1. Read all interview notes from `in` artifacts.
2. Identify bounded contexts from interview data: scan for clusters of related terminology, distinct lifecycles, and independent business capabilities per [[domain-modeling/event-storming#concepts]]. Record each context with a name, responsibility, and rough boundary.
3. Write `product_definition.md` from the trimmed template: What IS/IS NOT, Why, Users, Quality Attributes, Out of Scope, Delivery Order. Use the interview data to fill every section. The delivery order drives which context gets specified and simulated first.
3. Write `product_definition.md` from the trimmed template: What IS/IS NOT, Why, Users, Quality Attributes, Out of Scope. Use the interview data to fill every section.
4. Write `domain_spec.md` from the template at `.templates/docs/spec/domain_spec.md.template`. This is a single monolithic file — one `## <Context Name>` section per bounded context. Fill in iteration-0 content for each context:
- **Context Map**: leave the top-level section empty — architecture-flow context-mapping state refines it.
- **Context**: 2-3 sentences about what this context does and why it exists.
Expand All @@ -21,4 +21,4 @@ Available knowledge: [[domain-modeling/event-storming#concepts]], [[domain-model
- **External Contracts**: actor, trigger, input shape, output shape, known error conditions, side effects, and preconditions. Details may have `?` for unknowns.
- Leave **State Machines**, **Error Handling**, and **Invariants** empty — simulation discovers these.
5. Write `glossary.md` from the template at `.templates/docs/spec/glossary.md.template`. Extract domain terms from interview notes per [[requirements/ubiquitous-language#key-takeaways]]. Define each in genus-differentia format. Cross-reference against domain spec.
6. Verify: every bounded context has a `## <Context Name>` section in domain_spec.md. Every delivery order entry maps to at least one context. Every quality attribute is noted for simulation targeting. Every external contract has at least one input/output pair defined.
6. Verify: every bounded context has a `## <Context Name>` section in domain_spec.md. Every quality attribute is noted for simulation targeting. Every external contract has at least one input/output pair defined.
7 changes: 3 additions & 4 deletions .opencode/skills/refine-features/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,11 @@ Available knowledge: [[requirements/feature-boundaries]], [[requirements/feature
This state transforms the output of spec-validation (context-level .feature files) into the final feature-level structure that develop-flow will use. After this state, .feature file structure (Feature titles, Rule titles, Constraints) is FROZEN. Only Examples/Outlines may be added during develop-flow.

1. Read `product_definition.md`, `domain_spec.md`, `glossary.md`, and `features/*.feature` from `in` artifacts. The .feature files are simulation-created (one per bounded context, named by context).
2. Read `product_definition.md` delivery order. This determines feature priority and grouping.
3. For each bounded context in `domain_spec.md`, identify feature candidates per [[requirements/feature-boundaries#key-takeaways]]:
2. For each bounded context in `domain_spec.md`, identify feature candidates per [[requirements/feature-boundaries#key-takeaways]]:
- Map candidates to bounded contexts. IF a candidate spans multiple contexts → flag for splitting.
- Map candidates to entities and aggregate boundaries. IF a candidate requires cross-aggregate transactions → flag for splitting.
4. Create feature-level .feature files by splitting context-level files per [[requirements/feature-discovery#concepts]]:
- Name each feature per [[requirements/feature-boundaries#content]]: use the delivery step name, validated for clarity and specificity.
3. Create feature-level .feature files by splitting context-level files per [[requirements/feature-discovery#concepts]]:
- Name each feature per [[requirements/feature-boundaries#content]]: use a noun phrase that names a cohesive capability, validated for clarity and specificity.
- The Feature title slug MUST match the .feature filename stem per [[requirements/gherkin#concepts]].
- Redistribute Rule blocks across split features. When a context .feature file is split into multiple features, move Rule blocks to the appropriate feature file. Do NOT edit Rule block content — only redistribute. IF a rule spans multiple features → flag for cross-cutting handling.
- Delete the original context-level .feature files after all their Rules have been redistributed to feature-level files.
Expand Down
39 changes: 20 additions & 19 deletions .opencode/skills/select-feature/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: select-feature
description: "Select the next feature to develop by detecting delivery status from disk evidence, following delivery order"
description: "Select the next feature to develop by detecting delivery status from disk evidence, deriving priority from dependency count and WSJF"
---

# Select Feature
Expand All @@ -9,27 +9,28 @@ Available knowledge: [[requirements/wsjf#key-takeaways]]. `in` artifacts: read a

1. List available feature files in `docs/features/`.
2. IF no feature files exist → exit via `no-features`; features need discovery first.
3. Read `product_definition.md` to obtain the delivery order (ordered list of feature slugs). Validate against `domain_spec.md` context map to ensure dependency order is respected.
4. For each feature slug in delivery order, determine delivery status with a single pipeline
— do NOT open or read individual feature or test files:
3. For each feature, determine delivery status — do NOT open or read individual feature or test files:

a. Check if the feature file has Example blocks (any line starting with `Example:`).
If none, the feature has not been broken down into BDD examples yet → feature is incomplete (select it).
a. Check if the feature file has Example blocks (any line starting with `Example:`).
If none, the feature has not been broken down into BDD examples yet → feature is incomplete.

b. Run `beehave check <slug>` to verify structural traceability:
- Any output (errors) → some Examples lack matching test functions or there are orphan tests → feature is incomplete (select it).
- No output (clean) → all Examples have matching test functions.
b. Run `beehave check <slug>` to verify structural traceability:
- Any output (errors) → some Examples lack matching test functions or there are orphan tests → feature is incomplete.
- No output (clean) → all Examples have matching test functions.

c. If beehave check is clean, run the tests scoped to that feature's test directory
using the project's test runner (see Project Commands table).
- Any failures → feature is incomplete (select it).
c. If beehave check is clean, run `task test-fast` scoped to that feature's test directory.
- Any failures → feature is incomplete.
- All pass → feature is delivered (skip).

d. If the test directory does not exist, beehave check will report errors
→ feature is incomplete (select it).

5. Collect all incomplete features. IF this is the first feature (no features have been delivered yet) → select the first incomplete feature by delivery order. Skip to step 7.
6. IF subsequent features: score each incomplete feature per [[requirements/wsjf#key-takeaways]]. For each, estimate Value (1-5, mapped to Kano categories) and Effort (1-5, mapped to complexity). Compute WSJF = Value / Effort. Eliminate Dependency=1 features. Select the highest WSJF score; ties broken by Value.
7. IF every feature in the delivery order is delivered (diff clean + tests pass for all) →
exit via `no-features`.
d. If the test directory does not exist, beehave check will report errors → feature is incomplete.

4. IF every feature is delivered → exit via `no-features`.
5. Collect all incomplete features. Derive dependency count for each from `domain_spec.md` context map:
- Count how many other incomplete features this feature depends on (via integration points and entity relationships in the context map).
- Filter: select features with the **lowest dependency count** first (0 = no dependencies).
6. IF only one feature has the lowest dependency count → select it. Skip to step 8.
7. IF multiple features tie on dependency count → score each tied feature per [[requirements/wsjf#key-takeaways]]:
- Estimate Value (1-5, mapped to Kano categories) and Effort (1-5, mapped to complexity).
- Compute WSJF = Value / Effort.
- Select the highest WSJF score; ties broken by Value.
8. Set the `feature_id` session param to the selected feature's filename stem (without `.feature` extension).
2 changes: 1 addition & 1 deletion .templates/docs/features/<feature_name>.feature.template
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ Feature: <Feature title>

Discovered rules are written as Rule blocks during simulation, then
refined into feature boundaries by refine-features. Examples and
Scenario Outline blocks are added during feature-examples.>
Scenario Outline blocks are added later during feature-examples flow.>
12 changes: 0 additions & 12 deletions .templates/docs/spec/domain_spec.md.template
Original file line number Diff line number Diff line change
@@ -1,17 +1,5 @@
# Domain Specification

> **Status:** DRAFT | VALIDATED (YYYY-MM-DD)
> Monolithic: all bounded contexts in one file.
> Each `## <Context Name>` section is a context boundary.
> Contains structural domain information: entities, relationships, aggregates,
> context map, data shapes, integration points, and external contracts.
> Behavioral content (walkthroughs, rules, pain points) is discovered during
> simulation and written to `.feature` files.
> State Machines, Error Handling, and Invariants are derived summaries that
> reference `.feature` file rules — the `.feature` files are the authoritative
> source for behavioral specification.
> NO Given/When/Then here — that belongs in `.feature` files.

---

## Context Map
Expand Down
Loading
Loading