@behaghel/pi-domain-tree 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,103 @@
1
+ ---
2
+ name: domain-navigator
3
+ description: |
4
+ Navigate and enforce domain-driven codebase structure. Use when the user references a domain, asks where code or specs live, wants to understand project structure, asks about domain boundaries, or when you need to locate the right spec or code for a given feature area. Also use when creating new files to ensure they land in the correct domain namespace.
5
+ ---
6
+
7
+ # Domain Navigator
8
+
9
+ Provides domain-aware navigation and enforcement for codebases structured around `domains.yaml`.
10
+
11
+ Load `references/manifest-schema.md` when working with `domains.yaml`.
12
+ Load `references/conventions.md` when making decisions about file placement or domain boundaries.
13
+
14
+ ## When to activate
15
+
16
+ - User references a domain or feature area ("the issuance flow", "wallet onboarding")
17
+ - User creates a new file and you need to decide where it belongs
18
+ - User asks "where does X live?" or "what domain owns Y?"
19
+ - Before starting spec collection (to scope which domain the spec belongs to)
20
+ - Before planning TDD iterations (to scope which domain boundaries apply)
21
+
22
+ ## Core behavior
23
+
24
+ ### 1. Load the domain tree
25
+
26
+ 1. Read `domains.yaml` at the project root.
27
+ 2. If it doesn't exist, tell the user: "No domain tree found. Run `/domain-tree:init` to create one."
28
+ 3. Parse explicit `kind: group` entries as structural namespaces, then build a model of bounded-context domains, subdomains, code paths, and spec paths. Groups are not domains and own no code or specifications.
29
+
30
+ ### 2. Resolve domain from context
31
+
32
+ When the user describes work or you're about to modify code:
33
+
34
+ 1. Match the target file(s) against `code` paths in the manifest; the most-specific child path wins.
35
+ 2. Identify the governing domain, subdomain, and **domain type** (core/supporting/generic/shared-kernel).
36
+ 3. Locate the corresponding colocated spec path (by default, the first `code` path; `spec` may override it).
37
+ 4. Report: "This is in the **[domain] > [subdomain]** namespace (type: **[type]**). Spec at `[code path]/README.md`. Code at `[code paths]`."
38
+
39
+ If a file doesn't match any domain:
40
+ - Flag it: "This file isn't covered by any domain in `domains.yaml`. Should we add it to an existing domain or create a new one?"
41
+
42
+ ### 3. Enforce placement on new files
43
+
44
+ When creating new files:
45
+
46
+ 1. Determine which domain the file belongs to based on its purpose.
47
+ 2. Check that the target path is within that domain's `code` paths.
48
+ 3. If it isn't, suggest the correct location: "This looks like it belongs in **[domain]**. The convention is `[correct path]`."
49
+ 4. If a new subdomain is needed, propose updating `domains.yaml` first.
50
+
51
+ ### 4. Spec-on-touch (classification-aware)
52
+
53
+ Default to a domain specification containing durable, present-tense domain truth. Define each concept, invariant, or contract once at its narrowest owner and link to it elsewhere. Use standard relative Markdown links and resolve canonical terms or aliases with `domain_tree_resolve_term`; link meaningful first occurrences to the one repository-wide owner. Use a declared system spec only for a stable RFC 2119 requirement that cannot belong to one domain. Keep temporary scope, acceptance criteria, sequencing, rollout, migration, progress, and verification plans in non-normative iteration artifacts outside both corpora.
54
+
55
+ When editing production code:
56
+
57
+ 1. Resolve the governing domain and its `type`.
58
+ 2. Check for the domain's normative `README.md`; sibling Markdown is normative only when it declares `domain` and `status` frontmatter.
59
+ 3. Apply rigor based on domain type:
60
+ - **core** — Hard block. "No spec exists for **[domain]** (core). This domain requires a spec before any code change."
61
+ - **supporting** — Warning. "No spec exists for **[domain]** yet. Consider writing one before this change."
62
+ - **generic** — Soft note. "No spec for **[domain]**. Only needed if you're changing the integration boundary."
63
+ - **shared-kernel** — Hard block. "This is shared kernel — changes affect all consumers. Spec required, and consumers must be notified."
64
+ 4. If a spec exists, check its `status` field:
65
+ - `draft` — "This spec is a draft. Verify it's accurate before implementing against it."
66
+ - `approved` — proceed normally.
67
+ - `stale` — "This spec may be outdated. Review it before implementation."
68
+
69
+ ### 5. Cross-domain awareness (context-map-driven)
70
+
71
+ When work spans multiple domains:
72
+
73
+ 1. Identify all affected domains.
74
+ 2. Consult semantic `context-map` entries (`provider`, `consumers`, `pattern`, and canonical `contract`) for the declared relationship.
75
+ 3. If a relationship exists:
76
+ - Report the pattern: "This crosses **[domain A]** → **[domain B]** (pattern: **[pattern]**)."
77
+ - Guide based on pattern:
78
+ - **shared-kernel**: "Both domains consume this. Update the kernel spec and notify all consumers."
79
+ - **customer-supplier**: "**[upstream]** owns the contract. Check if the change is compatible."
80
+ - **anti-corruption-layer**: "Changes should go through the ACL at `[via path]`, not bypass it."
81
+ - **conformist**: "**[downstream]** conforms to **[upstream]**'s model. Update the downstream's mapping."
82
+ 4. If no relationship is declared:
83
+ - Flag it: "This crosses **[domain A]** and **[domain B]** but no relationship is declared in the context map. Add one before proceeding."
84
+ 5. Note which specs need updating in each affected domain.
85
+
86
+ ### 6. Shared kernel awareness
87
+
88
+ When editing code in a `shared-kernel` domain:
89
+
90
+ 1. Identify all consumers from the `context-map` (domains with `pattern: shared-kernel` pointing to this domain).
91
+ 2. Warn: "This is shared kernel. Changes affect: **[list of consuming domains]**."
92
+ 3. Check for contract tests in each consuming domain.
93
+ 4. Recommend: "Run contract tests for [consumers] after this change."
94
+
95
+ ## Guardrails
96
+
97
+ - Do NOT create files outside the domain tree without flagging it.
98
+ - Do NOT let domain boundaries drift silently — every new code path should map to a domain.
99
+ - Allow parent/child overlap under subsidiarity; reject unrelated domains claiming the same path.
100
+ - Do NOT treat `domains.yaml` as documentation — it is a structural contract.
101
+ - Do NOT enforce domains on non-production files (tests, scripts, CI) unless they have their own technical domain.
102
+ - Do NOT allow cross-domain changes without consulting the context map.
103
+ - Do NOT allow shared-kernel changes without notifying all consumers.
@@ -0,0 +1,228 @@
1
+ # Domain Tree Conventions
2
+
3
+ Rules for maintaining the 1:1 mirror between colocated domain specs and code namespaces, informed by Domain-Driven Design.
4
+
5
+ ## The colocation principle
6
+
7
+ `domains.yaml` lives at the project root. Domain specs live beside the code they govern: the first `code` path is the default spec directory, `README.md` is the main domain spec, and additional behavior specs are sibling `*.md` files. If specs cannot live in the first `code` path, an explicit `spec:` override may point to the colocated spec directory.
8
+
9
+ For a project that uses `src/`, the common shape is:
10
+
11
+ ```
12
+ .
13
+ ├── domains.yaml (the manifest)
14
+ └── src/
15
+ ├── verification/
16
+ │ ├── README.md (main domain spec)
17
+ │ ├── presentation.md (specific behavior spec)
18
+ │ └── ...code...
19
+ ├── issuance/
20
+ │ ├── README.md
21
+ │ └── ...code...
22
+ └── shared-kernel/
23
+ ├── README.md
24
+ └── ...code...
25
+ ```
26
+
27
+ The domain tree SHOULD mirror the code's module/package structure. When they diverge, make the drift visible in `/domain-tree:check` and decide whether to refactor code or update `domains.yaml`.
28
+
29
+ ## Ubiquitous language
30
+
31
+ Each domain has its own vocabulary. The same word can mean different things in different domains — that's expected and healthy. What matters is consistency WITHIN a domain.
32
+
33
+ - Define key terms in the domain's `language` field in `domains.yaml` or in `<domain code path>/README.md`
34
+ - Code names (types, functions, variables) MUST use the domain's vocabulary
35
+ - Spec text MUST use the domain's vocabulary
36
+ - When two domains need to communicate, the context map defines how terms translate
37
+
38
+ Example: "Credential" means an SD-JWT VC in the issuance domain, but a displayable card in the wallet domain. The ACL between them handles the translation.
39
+
40
+ ## Domain classification and spec rigor
41
+
42
+ Not all domains deserve equal investment. Classification drives how thoroughly you spec:
43
+
44
+ ### Core domains (`type: core`)
45
+
46
+ The competitive advantage. Invest the most here.
47
+
48
+ - **Spec rigor:** Full spec-driven collection (all 6 phases). Every behavioral change specced before code.
49
+ - **TDD rigor:** Thorough iteration plans, small slices, careful red-green-refactor.
50
+ - **Review:** Specs need human approval before implementation.
51
+ - **Spec-on-touch:** Hard requirement — no code changes without a spec.
52
+ - **Modeling:** Rich domain models with explicit aggregates, value objects, domain events.
53
+
54
+ ### Supporting domains (`type: supporting`)
55
+
56
+ Necessary, custom-built, not differentiating.
57
+
58
+ - **Spec rigor:** Good specs but lighter process. Can skip some collection phases.
59
+ - **TDD rigor:** Standard TDD. Larger slices acceptable.
60
+ - **Review:** Self-approval OK for straightforward specs.
61
+ - **Spec-on-touch:** Warning when missing, not blocking.
62
+ - **Modeling:** Simpler models. CRUD-like patterns are fine.
63
+
64
+ ### Generic domains (`type: generic`)
65
+
66
+ Solved problems. Use existing libraries, standards, infrastructure.
67
+
68
+ - **Spec rigor:** Spec the integration boundary only. Don't spec the internals of something you didn't build.
69
+ - **TDD rigor:** Contract tests at the boundary. Don't unit-test the library.
70
+ - **Review:** Minimal — the standard/library IS the spec.
71
+ - **Spec-on-touch:** Only when the integration surface changes.
72
+ - **Modeling:** Thin wrappers. Anti-corruption layers where the external model leaks.
73
+
74
+ ### Shared kernel (`type: shared-kernel`)
75
+
76
+ Shared types and contracts across domains. Treated with the rigor of core, because changes ripple everywhere.
77
+
78
+ - **Spec rigor:** High. Every shared type must be explicitly specced.
79
+ - **TDD rigor:** High. Contract tests from every consumer.
80
+ - **Review:** Joint approval from all consuming domains.
81
+ - **Spec-on-touch:** Always — any change to shared kernel needs spec update.
82
+ - **Modeling:** Value objects and immutable types preferred. Minimize the kernel surface.
83
+
84
+ ## Context map conventions
85
+
86
+ The context map in `domains.yaml` declares cross-domain relationships. These relationships are architectural decisions, not just documentation.
87
+
88
+ ### Integration patterns and what to spec
89
+
90
+ | Pattern | Spec location | What the spec covers |
91
+ |---------|--------------|---------------------|
92
+ | shared-kernel | The kernel domain's colocated spec directory | The shared types, their invariants, and which domains consume them |
93
+ | customer-supplier | Upstream domain's spec | The contract — what the upstream promises and what can change |
94
+ | conformist | Downstream domain's spec | How the downstream maps upstream concepts to its own model |
95
+ | anti-corruption-layer | Downstream domain's spec | The ACL: what comes in, what comes out, where it lives in code |
96
+ | open-host-service | Upstream domain's spec | The protocol or API definition (often a published standard) |
97
+ | published-language | `<domain code path>/` of the publisher | The schema or interchange format |
98
+
99
+ ### Cross-domain changes with context map awareness
100
+
101
+ When a change spans domains, the context map tells you how to handle it:
102
+
103
+ 1. **shared-kernel change** → Update the kernel spec. Notify ALL consuming domains. Run contract tests from each consumer.
104
+ 2. **customer-supplier change** → Upstream changes its contract → downstream must update its conformance. Check the downstream's ACL or conformist layer.
105
+ 3. **anti-corruption-layer change** → Only the downstream's ACL needs updating. The upstream is unaware.
106
+ 4. **partnership change** → Both domains update together. Coordinate specs.
107
+
108
+ If a cross-domain change doesn't fit any declared relationship, the context map is incomplete — add the relationship before proceeding.
109
+
110
+ ## Spec file conventions
111
+
112
+ ### Naming
113
+
114
+ - One spec per bounded concern: `src/issuance/credential-flow.md`
115
+ - Use the behavior name, not the implementation name: `verification-request.md` not `verify-handler.md`
116
+ - Keep iteration plans outside domain and system corpora; delete them when no longer operationally useful.
117
+
118
+ ### Frontmatter
119
+
120
+ Every spec file should have YAML frontmatter:
121
+
122
+ ```yaml
123
+ ---
124
+ domain: issuance
125
+ status: draft | approved | stale
126
+ ---
127
+ ```
128
+
129
+ - `domain` — must match a domain in `domains.yaml`
130
+ - `status` — lifecycle state (`draft` → `approved` → `stale` when code outpaces spec)
131
+ - canonical term pages additionally declare `term` and may declare `aliases`
132
+
133
+ Keep normative metadata minimal. Do NOT use `last-reviewed`, delivery state, or `governs:`. Code ownership is already declared in `domains.yaml`; Git preserves review and delivery history.
134
+
135
+ ### Domain-level spec
136
+
137
+ A domain MAY have a `README.md` at its code root:
138
+
139
+ ```
140
+ src/issuance/
141
+ ├── README.md ← main domain spec: ubiquitous language, invariants, domain events
142
+ ├── credential-flow.md ← specific behavior spec
143
+ ├── webhook-handling.md
144
+ └── ...code...
145
+ ```
146
+
147
+ `README.md` is the required domain overview. Keep it concise and substantive: ubiquitous language, responsibilities, invariants, boundaries, or domain events. Do not create an overview that only repeats manifest metadata.
148
+
149
+ `README.md` does NOT duplicate information already in `domains.yaml`:
150
+ - Description
151
+ - Domain type/classification
152
+ - Code paths
153
+ - Context map relationships
154
+ - Consumer lists
155
+
156
+ ### Specification DRY
157
+
158
+ Define each concept, invariant, or contract once at its narrowest semantic owner. Other specifications link to that canonical definition and describe only their local use, constraints, or consequences. Domain specifications are the default normative artifact.
159
+
160
+ Use a declared system spec only for a durable RFC 2119 requirement that cannot be assigned to one domain by subsidiarity. Keep temporary acceptance criteria, implementation scope, sequencing, rollout, migration, progress, and verification plans in non-normative iteration artifacts outside both corpora. Normative specs describe current durable behavior in the present tense; they do not preserve legacy or transitional commentary.
161
+
162
+ ### Specification wiki links
163
+
164
+ Use standard relative Markdown links, never a separate wikilink syntax. Canonical term pages declare `term` and optional `aliases`; canonical terms and aliases form one case-insensitive repository-wide namespace with one semantic owner per label. A term-labelled link must target that owner. Link meaningful first occurrences, not every repetition. Relative targets must exist, and fragments on Markdown targets must resolve to real heading anchors. External URLs are allowed but are outside repository-integrity checks.
165
+
166
+ ## Code-paths rules
167
+
168
+ `code-paths` in `domains.yaml` should be **directories, not individual files**. A code-path means "everything under this directory belongs to this domain."
169
+
170
+ ### Signals that code-paths need attention
171
+
172
+ 1. **Individual files listed**: If a domain lists `ui/FooScreen.kt`, `ui/BarScreen.kt` instead of `ui/foo/`, the code likely needs refactoring into subdirectories that match the domain boundary.
173
+ 2. **Many subdirectories of the same parent**: If a domain lists `ui/mapper/`, `ui/model/`, `ui/components/` — the parent `ui/` probably belongs to the domain. List the parent, not each child.
174
+ 3. **Overlapping paths**: Parent/child overlap is valid and the most-specific matching child owns the file. If unrelated domains claim the same path, establish one semantic owner or refactor into distinct directories.
175
+
176
+ When `/domain-tree:check` detects these patterns, it should recommend the refactoring rather than silently accepting the file-level mappings.
177
+
178
+ ### Spec files live next to code, not in docs/
179
+
180
+ All behavioral specifications must live under the domain's colocated spec directory (normally the first `code` path). `README.md` and sibling Markdown with `domain`/`status` frontmatter form the normative corpus. Prompts, agent instructions, guides, plans, and historical documents without that frontmatter are non-normative. If a spec-like document exists in `docs/`, move it next to the owning domain's code; keep only non-normative material in `docs/`.
181
+
182
+ ## When to create a new domain
183
+
184
+ Create a new domain when:
185
+ - New code doesn't fit any existing domain's description
186
+ - An existing domain has grown to cover two distinct responsibilities
187
+ - A technical concern (monitoring, deployment) becomes complex enough to spec
188
+
189
+ Do NOT create a new domain when:
190
+ - The code is a utility used by exactly one domain (put it in that domain)
191
+ - The code is shared across domains (add it to the shared kernel)
192
+ - The work is a one-off script (not everything needs a domain)
193
+
194
+ ## When to split a domain into subdomains
195
+
196
+ Split when:
197
+ - The domain has more than 5 spec files
198
+ - Two parts of the domain can change independently
199
+ - Different people/teams own different parts
200
+ - The code already has natural package boundaries
201
+ - The ubiquitous language has started to diverge within the domain (same word, different meanings)
202
+
203
+ ## Shared kernel rules
204
+
205
+ The shared kernel is the most constrained domain:
206
+
207
+ 1. **Minimize the surface.** The less you share, the less coupling.
208
+ 2. **Prefer value objects.** Immutable, identity-less types are safe to share. Entities with lifecycles are not.
209
+ 3. **No business logic.** The kernel is types and contracts, not behavior.
210
+ 4. **Explicit consumers.** The context map must list every domain that depends on the kernel.
211
+ 5. **Joint approval.** No unilateral changes — all consumers must agree.
212
+ 6. **Contract tests.** Every consumer maintains tests that verify the kernel's contracts.
213
+
214
+ ## Technical domains vs business domains
215
+
216
+ Technical domains follow the same rules but spec different things:
217
+
218
+ | Domain type | Spec contains |
219
+ |------------|---------------|
220
+ | Business | Acceptance criteria, user behavior, data flow |
221
+ | Security | Threat model, cryptographic requirements, invariants |
222
+ | UX | Design tokens, component behavior, accessibility rules |
223
+ | Infra | Deployment topology, scaling rules, network policies |
224
+ | CI/CD | Pipeline stages, quality gates, release process |
225
+
226
+ The common thread: if it has behavior or constraints worth verifying, it gets a spec.
227
+
228
+ Technical domains CAN be `type: core` — security in a trust provider is absolutely core, even though it's not "business logic" in the traditional DDD sense.
@@ -0,0 +1,277 @@
1
+ # Domain Manifest Schema
2
+
3
+ The domain manifest lives at `domains.yaml` and is the structural contract between specs and code. It encodes the domain tree, subdomain classifications, and the context map.
4
+
5
+ ## Structure
6
+
7
+ ```yaml
8
+ # domains.yaml
9
+
10
+ # Optional project-level metadata
11
+ project:
12
+ name: my-project
13
+ description: One-line project description
14
+
15
+ # Optional project-level normative corpus for requirements that cannot
16
+ # be assigned to one domain by subsidiarity.
17
+ system-specs: [doc/system/]
18
+
19
+ # Structural groups and domains
20
+ domains:
21
+ <group-name>:
22
+ kind: group
23
+ description: Optional navigation context
24
+ domains:
25
+ <domain-name>:
26
+ description: What this domain is responsible for
27
+ type: core | supporting | generic | shared-kernel # default: supporting
28
+ status: active | deprecated | planned # default: active
29
+ owners: [team-or-person] # optional
30
+ language: # optional: ubiquitous language
31
+ - term: Cachet
32
+ meaning: A privacy-preserving trust badge issued after credential verification
33
+
34
+ # Specs live in the first code path by default.
35
+ code: [path/to/code/, another/path/]
36
+ # Optional override when specs cannot live in the first code path:
37
+ spec: path/to/code/
38
+
39
+ # Bounded contexts may contain narrower bounded contexts.
40
+ subdomains:
41
+ <subdomain-name>:
42
+ description: ...
43
+ type: core | supporting | generic # inherits from parent if omitted
44
+ code: [path/to/code/]
45
+ # Optional override; otherwise specs live in path/to/code/.
46
+ # subdomains can nest further
47
+
48
+ # Cross-context relationships
49
+ context-map:
50
+ - provider: <fully-qualified/domain-name>
51
+ consumers: [<fully-qualified/consumer-name>]
52
+ pattern: <relationship-pattern>
53
+ contract: <canonical spec path>
54
+ ```
55
+
56
+ ## Structural groups
57
+
58
+ A `kind: group` entry provides namespace and presentation structure only. Its `domains` may contain domains or nested groups. Groups are not bounded contexts: they have no classification, lifecycle, owners, language, code ownership, specification, subdomains, or context-map relationships. The only allowed group fields are `kind`, `description`, and `domains`. Fully qualified domain names retain their group path, such as `business/time-management`.
59
+
60
+ Entries without `kind: group` remain domains. Domain nesting uses `subdomains`, not `domains`. A domain must declare `code` or an explicit `spec`; a node with only children is invalid and should normally become a group.
61
+
62
+ ## Normative corpora
63
+
64
+ Domain specifications are the default. They contain durable, present-tense behavior, ubiquitous language, boundaries, invariants, and semantic contracts owned by one domain.
65
+
66
+ `system-specs` may declare Markdown files or directories. Directories are scanned recursively. Every included file is normative and must use only this frontmatter:
67
+
68
+ ```yaml
69
+ ---
70
+ system: my-project
71
+ status: draft | approved | stale
72
+ ---
73
+ ```
74
+
75
+ The `system` value must equal `project.name`, and every system spec must contain at least one uppercase RFC 2119 keyword: `MUST`, `MUST NOT`, `SHOULD`, `SHOULD NOT`, or `MAY`. System specs cannot own ubiquitous terms; they link to domain-owned canonical pages. Use system specs only for stable requirements that subsidiarity cannot assign to one domain.
76
+
77
+ Iteration specs are temporary delivery artifacts. They remain outside domain spec directories and declared `system-specs`, carry no normative frontmatter, and are deleted when no longer useful.
78
+
79
+ Together, normative files form a standard relative-Markdown wiki. Canonical term pages declare `term` and optional `aliases`. Every case-insensitive canonical term or alias has one repository-wide owner. Relative targets and Markdown heading anchors must resolve; term-labelled links must target the canonical owner. Meaningful first-occurrence linking remains a semantic authoring rule rather than a noisy lexical hard check.
80
+
81
+ Normative domain and system specs reject project-management sections such as roadmaps, rollout or migration plans, progress, delivery status, milestones, and verification plans. They state durable behavior rather than legacy comparisons or temporary implementation concerns.
82
+
83
+ ## Domain classification
84
+
85
+ Every domain has a `type` that determines how much modeling rigor it deserves. This comes from DDD's subdomain classification:
86
+
87
+ | Type | What it means | Spec rigor | Example |
88
+ |------|--------------|------------|---------|
89
+ | **core** | Competitive advantage. The reason the project exists. | High — thorough specs, careful TDD, deep modeling | verification, issuance |
90
+ | **supporting** | Necessary, custom-built, but not differentiating. | Moderate — good specs, standard TDD | registry, receipts |
91
+ | **generic** | Solved problem. Use existing solutions where possible. | Light — spec the integration, not the internals | auth, email, payment |
92
+ | **shared-kernel** | Shared types and contracts across domains. Joint ownership. | High — changes affect all consumers, must be explicit | common types, shared events |
93
+
94
+ ### How classification drives behavior
95
+
96
+ - **spec-on-touch**: Core domains require a spec before any code change. Supporting domains get a warning. Generic domains only need an integration spec.
97
+ - **spec-driven collection**: Core domains get the full 6-phase treatment. Supporting domains can use a lighter format. Generic domains spec only the boundary.
98
+ - **spec-tdd planning**: Core domains get thorough iteration plans. Supporting domains can take larger slices. Generic domains focus on contract tests.
99
+ - **code review**: Core domain specs need human approval before implementation. Supporting specs can be self-approved.
100
+
101
+ ## Context map
102
+
103
+ The `context-map` section declares semantic contracts between domains. Each entry names one provider, one or more consumers, an integration pattern, and the canonical contract. Ordinary imports do not require context-map entries.
104
+
105
+ ### Relationship patterns
106
+
107
+ | Pattern | Meaning | What to spec |
108
+ |---------|---------|-------------|
109
+ | **shared-kernel** | Both domains share a small, explicit set of types. Changes require agreement from both. | The shared types themselves — what's in the kernel and what's not |
110
+ | **customer-supplier** | Upstream domain provides what downstream needs. Downstream can negotiate. | The API contract between them — what's promised, what can change |
111
+ | **conformist** | Downstream accepts upstream's model as-is. No negotiation. | Only the downstream's usage — how it maps upstream concepts to its own |
112
+ | **anti-corruption-layer** | Downstream translates upstream's model to protect its own. | The translation layer — what comes in, what comes out, where the ACL lives |
113
+ | **open-host-service** | Upstream exposes a general-purpose protocol for many consumers. | The protocol spec (often an existing standard like OpenID4VCI) |
114
+ | **published-language** | A shared, documented interchange format. Often paired with open-host-service. | The schema or format definition |
115
+ | **separate-ways** | No integration. Domains are independent. | Nothing — but document WHY they're separate |
116
+ | **partnership** | Two domains evolve together with coordinated planning. | Joint specs that cover the shared evolution |
117
+
118
+ ### How the context map drives behavior
119
+
120
+ - **boundary-enforcer**: When a cross-domain change is detected, consult the context map. The provider owns the canonical `contract`; consumers follow the declared pattern.
121
+ - **domain-tree:check**: Validate that providers and consumers exist, patterns are supported, and canonical contract paths resolve.
122
+ - **spec-driven collection**: When speccing a domain that consumes another, the context map tells you which integration pattern to follow — and therefore what to spec.
123
+
124
+ ## Manifest integrity
125
+
126
+ The manifest is validated strictly. Unknown fields, malformed value types, unsupported classifications or lifecycle states, incomplete context relationships, and group references in the context map are errors. When any error exists, ownership resolution, maps, and spec coverage fail closed rather than using a partial tree. `/domain-tree:check` reports all diagnostics; malformed YAML includes line and column when available.
127
+
128
+ Legacy structural-only nodes are never rewritten automatically. Convert them explicitly to `kind: group` with `domains`, or give a real bounded context a `code` or `spec` anchor.
129
+
130
+ ## Path rules
131
+
132
+ - `code` paths are relative to project root, always end with `/`.
133
+ - The most-specific matching child path owns a file. Parent/child overlap is valid; unrelated domains cannot claim the same path.
134
+ - Specs live next to code. The first `code` path is the default spec directory; `README.md` is the required main domain spec.
135
+ - `spec` is optional and only overrides the inferred spec directory when specs cannot live in the first `code` path.
136
+ - Groups use `domains`; bounded contexts use `subdomains`.
137
+ - Groups never own code or specifications and are excluded from domain coverage counts.
138
+ - A domain is either a **leaf** (has `code`) or a **branch** (has `subdomains`).
139
+ - Branch domains may also have `code` + `spec` for domain-level concerns (shared types, domain events).
140
+
141
+ ## Domain types
142
+
143
+ Domains are not limited to business logic. The tree covers everything with behavior worth specifying:
144
+
145
+ | Category | Examples | What gets specced |
146
+ |----------|----------|------------------|
147
+ | **Business** | verification, issuance, registry | User-facing behavior, acceptance criteria |
148
+ | **Technical** | security, crypto, infra | Architectural constraints, invariants |
149
+ | **Platform** | ux, cicd, observability | Conventions, patterns, tooling behavior |
150
+ | **Integration** | webhooks, external-apis | Contract specs, error handling |
151
+
152
+ Domain category is about WHAT it covers. Domain type (core/supporting/generic) is about HOW MUCH rigor it deserves. They're orthogonal — a technical domain like security can be `core`.
153
+
154
+ ## Naming conventions
155
+
156
+ - Domain names: lowercase, hyphenated (`issuance-gateway`, `receipts-log`)
157
+ - Match existing module/package names where possible
158
+ - Prefer domain language over implementation language ("verification" not "verifier-service")
159
+
160
+ ## Coverage
161
+
162
+ Not every file needs to be in a domain. Exclude:
163
+ - Generated files (build output, lock files)
164
+ - Configuration that doesn't encode behavior (.editorconfig, .gitignore)
165
+ - Third-party code (vendor/, node_modules/)
166
+
167
+ Everything else should map to a domain. Unmapped production code is a smell.
168
+
169
+ ## Example
170
+
171
+ ```yaml
172
+ project:
173
+ name: cachet
174
+ description: Privacy-preserving trust provider
175
+
176
+ domains:
177
+ verification:
178
+ description: Credential presentation and cach'pack verification
179
+ type: core
180
+ language:
181
+ - term: Cach'Pack
182
+ meaning: Reusable, privacy-preserving credential template
183
+ - term: Presentation
184
+ meaning: Verifiable credential bundle verified against a policy
185
+ subdomains:
186
+ presentation:
187
+ description: Verify credential presentations against policies
188
+ code: [services/verifier/presentation/]
189
+ packs:
190
+ description: Cach'pack list management and definitions
191
+ code: [services/verifier/packs/]
192
+
193
+ issuance:
194
+ description: OpenID4VCI credential issuance via Veriff
195
+ type: core
196
+ code: [services/issuance-gateway/]
197
+
198
+ registry:
199
+ description: Policy and pack registry with DID-signed manifests
200
+ type: supporting
201
+ code: [services/registry/]
202
+
203
+ receipts:
204
+ description: Consent receipts and transparency logging
205
+ type: supporting
206
+ code: [services/receipts-log/]
207
+
208
+ wallet:
209
+ description: Mobile wallet application
210
+ type: core
211
+ subdomains:
212
+ onboarding:
213
+ description: First-run experience and identity verification
214
+ code: [mobile/shared/.../onboarding/, mobile/androidApp/.../onboarding/]
215
+ credentials:
216
+ description: Credential storage, display, and management
217
+ code: [mobile/shared/.../credentials/, mobile/androidApp/.../credentials/]
218
+ verification-flow:
219
+ description: QR scan, consent, presentation flow
220
+ code: [mobile/shared/.../verification/, mobile/androidApp/.../verification/]
221
+
222
+ common:
223
+ description: Shared types, value objects, and contracts across services
224
+ type: shared-kernel
225
+ code: [services/common/]
226
+
227
+ security:
228
+ description: Cryptographic operations, key management, threat model
229
+ type: core
230
+ code: [services/common/crypto/]
231
+
232
+ ux:
233
+ description: Design system, theming, shared UI components
234
+ type: supporting
235
+ code: [mobile/androidApp/.../ui/theme/, mobile/androidApp/.../ui/components/]
236
+
237
+ infra:
238
+ description: Deployment, Cloud Run, networking, service mesh
239
+ type: generic
240
+ code: [deploy/, terraform/]
241
+
242
+ cicd:
243
+ description: CI/CD pipelines, pre-commit hooks, release automation
244
+ type: generic
245
+ code: [.github/workflows/, scripts/]
246
+
247
+ context-map:
248
+ - provider: issuance
249
+ consumers: [wallet]
250
+ pattern: open-host-service
251
+ contract: services/issuance-gateway/README.md
252
+
253
+ - provider: verification
254
+ consumers: [wallet]
255
+ pattern: anti-corruption-layer
256
+ contract: services/verifier/presentation/README.md
257
+
258
+ - provider: registry
259
+ consumers: [verification]
260
+ pattern: customer-supplier
261
+ contract: services/registry/README.md
262
+
263
+ - provider: common
264
+ consumers: [issuance, verification]
265
+ pattern: shared-kernel
266
+ contract: services/common/README.md
267
+ ```
268
+
269
+ ## Lifecycle
270
+
271
+ 1. **Init** — `/domain-tree:init` proposes the initial tree from codebase analysis
272
+ 2. **Classify** — Assign core/supporting/generic to each domain based on business value
273
+ 3. **Map** — Declare cross-context relationships in `context-map`
274
+ 4. **Grow** — Add domains/subdomains as the project evolves
275
+ 5. **Split** — When a domain gets too large, split into subdomains
276
+ 6. **Deprecate** — Mark domains `status: deprecated` before removing
277
+ 7. **Validate** — `/domain-tree:check` verifies the tree matches reality