@sumrco/cli 0.3.0 → 0.3.2

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.
Files changed (35) hide show
  1. package/ai/modules/kontract/resources/api-generation-standards.rf.md +83 -0
  2. package/ai/modules/kontract/resources/{configuration.rf.md → authoring/configuration.rf.md} +49 -11
  3. package/ai/modules/kontract/resources/authoring/design-profile/api-styles.rf.md +241 -0
  4. package/ai/modules/kontract/resources/authoring/design-profile/async-styles.rf.md +134 -0
  5. package/ai/modules/kontract/resources/authoring/design-profile/overview.md +64 -0
  6. package/ai/modules/kontract/resources/authoring/design-profile/schema-layout-styles.rf.md +356 -0
  7. package/ai/modules/kontract/resources/authoring/overview.md +56 -0
  8. package/ai/modules/kontract/resources/{schema-reuse.rf.md → authoring/schema-reuse.rf.md} +222 -46
  9. package/ai/modules/kontract/resources/{scope-and-splitting.rf.md → authoring/scope-and-splitting.rf.md} +113 -57
  10. package/ai/modules/kontract/resources/authoring/spec-layout.rf.md +492 -0
  11. package/ai/modules/kontract/resources/authoring/team-members/spec-author.tm.md +77 -0
  12. package/ai/modules/kontract/resources/{workflows/contract-change.wf.md → authoring/workflows/spec-change.wf.md} +21 -15
  13. package/ai/modules/kontract/resources/generated-output.rf.md +19 -14
  14. package/ai/modules/kontract/resources/openapi-sdk-generator-research.rf.md +17 -19
  15. package/ai/modules/kontract/resources/overview.md +115 -82
  16. package/ai/modules/kontract/resources/performance.rf.md +7 -7
  17. package/ai/modules/kontract/sumr.module.yaml +3 -0
  18. package/ai/modules/mission/sumr.module.yaml +6 -0
  19. package/ai/modules/playbook/resources/authoring/content-structure.rf.md +1 -1
  20. package/ai/modules/playbook/resources/authoring/cross-referencing.rf.md +1 -1
  21. package/ai/modules/playbook/resources/authoring/descriptions.rf.md +1 -1
  22. package/ai/modules/playbook/resources/authoring/extraction.rf.md +1 -1
  23. package/ai/modules/playbook/resources/authoring/flows.rf.md +1 -1
  24. package/ai/modules/playbook/resources/authoring/folder-structure.rf.md +1 -1
  25. package/ai/modules/playbook/resources/authoring/frontmatter.rf.md +4 -1
  26. package/ai/modules/playbook/resources/authoring/markdown.rf.md +1 -1
  27. package/ai/modules/playbook/resources/authoring/overview.md +1 -1
  28. package/ai/modules/playbook/resources/team-members/{playbook-technical-writer.tm.md → technical-writer.tm.md} +3 -2
  29. package/ai/modules/playbook/sumr.module.yaml +7 -2
  30. package/index.js +332 -276
  31. package/package.json +1 -1
  32. package/ai/modules/kontract/resources/language-sdk-generator-extension.rf.md +0 -62
  33. package/ai/modules/kontract/resources/openapi-generator-lessons.rf.md +0 -61
  34. package/ai/modules/kontract/resources/spec-layout.rf.md +0 -275
  35. package/ai/modules/kontract/resources/team-members/contract-author.tm.md +0 -60
@@ -2,7 +2,7 @@
2
2
  category: reference
3
3
  name: schema-reuse
4
4
  title: Schema Reuse and Shared Components
5
- description: "How to author OpenAPI/AsyncAPI specs with reusable shared components, $ref, and safe composition so Kontract output stays consistent and avoids copy-pasted contract drift."
5
+ description: "How to author API and async schemas with reusable shared components, $ref, Kontract sets, and safe composition so Kontract output stays consistent and avoids duplicated contract shapes."
6
6
  label: Schema Reuse
7
7
  when: Adding repeated fields, response envelopes, pagination, errors, schedules, config objects, or reviewing generated diffs with duplicated DTO/model shapes
8
8
  order: 12
@@ -17,10 +17,25 @@ operations or services, define it once and reference it with `$ref`.
17
17
  This reduces drift in the source specs immediately. It also gives Kontract a
18
18
  clear path to emit more shared generated code as the generator evolves.
19
19
 
20
- Before extracting or naming a shared component, choose a name from the domain
20
+ Before extracting or naming a shared component, choose a name from product
21
21
  language. Shared names should stay specific enough for generated DTO/model/SDK
22
22
  symbols.
23
23
 
24
+ ## Local-first promotion model
25
+
26
+ Keep a schema in the smallest owning place until reuse proves it should move:
27
+
28
+ 1. **Surface-local** — define one-off request, response, and model shapes in the
29
+ root file's `components.schemas`.
30
+ 2. **Capability-local shared** — move the shape into the capability's
31
+ `shared/` folder when two or more surfaces in that capability reuse the same
32
+ concept.
33
+ 3. **Repo-level shared** — move the shape into `schema/shared/` only when two or
34
+ more capabilities share the same semantics, lifecycle, and owner.
35
+
36
+ Do not create shared files only because a shape might become reusable later.
37
+ Shared components are a promotion step, not the default folder for every model.
38
+
24
39
  ## What to share
25
40
 
26
41
  Prefer shared components for concepts that mean the same thing everywhere:
@@ -84,26 +99,107 @@ content:
84
99
  $ref: ../shared/common.yml#/components/schemas/ImageMimeType
85
100
  ```
86
101
 
87
- ## Sharing schemas across OpenAPI and AsyncAPI fragments
102
+ ## Protocol scenarios for reuse
103
+
104
+ Pick the protocol scenario before extracting shared components:
105
+
106
+ 1. **API-only** — share HTTP schemas, parameters, responses, envelopes,
107
+ pagination, errors, and scalar constraints through API schema components.
108
+ 2. **async-only** — share message payload schemas, message enums, scalar
109
+ constraints, and value objects through async schema components or
110
+ capability-local model fragments.
111
+ 3. **API + async** — keep protocol layers separate and share only neutral
112
+ components with identical meaning. The safest cross-protocol sharing is
113
+ usually enums, IDs, slugs, scalar value objects, and simple payload shapes.
114
+
115
+ Do not create cross-protocol shared files only because API schema and async schema
116
+ payloads look similar today. Shared components must have the same product
117
+ meaning and owner.
118
+
119
+ ## API-only reuse
120
+
121
+ If the repo only has API schema sources, keep one-off schemas in the owning
122
+ API schema surface. Use a capability-local `shared/` folder only after multiple
123
+ surfaces in that capability reuse the same concept. Use `schema/shared/` only
124
+ after multiple capabilities share the same concept.
125
+
126
+ ```text
127
+ schema/
128
+ bookstore/
129
+ main.api.yml
130
+ catalog.api.yml
131
+ reviews.api.yml
132
+ shared/
133
+ enums.yml # reused by catalog and reviews
134
+ components.yml
135
+ shared/
136
+ errors.yml # reused by multiple capabilities
137
+ pagination.yml
138
+ ```
139
+
140
+ Use API schema `components` for reusable HTTP shapes:
141
+
142
+ ```yaml
143
+ # schema/bookstore/shared/enums.yml
144
+ components:
145
+ schemas:
146
+ BookFormat:
147
+ type: string
148
+ enum: [hardcover, paperback, ebook]
149
+ ```
150
+
151
+ ## async-only reuse
88
152
 
89
- When one domain has both HTTP and messaging contracts, keep protocol entrypoints
90
- separate and share only neutral business schemas.
153
+ If the repo only has async schema sources, keep reusable message payload schemas and
154
+ enums close to the messaging roots or under `schema/shared/` when several
155
+ message families share the same meaning.
91
156
 
92
157
  ```text
93
158
  schema/
159
+ shared/
160
+ message-enums.yml
94
161
  bookstore/
95
- bookstore.openapi.yml
96
- bookstore.asyncapi.yml
162
+ bookstore.async.yml
163
+ messages/
164
+ book-commands.yml
165
+ book-events.yml
166
+ models/
167
+ books.yml
168
+ enums.yml
169
+ ```
170
+
171
+ ```yaml
172
+ # schema/bookstore/models/enums.yml
173
+ BookFormat:
174
+ type: string
175
+ enum: [hardcover, paperback, ebook]
176
+ ```
177
+
178
+ ## API + async shared components
179
+
180
+ When one product capability has both HTTP and messaging contracts, keep protocol
181
+ entrypoints separate and share only business schemas.
182
+
183
+ ```text
184
+ schema/
185
+ bookstore/
186
+ bookstore.api.yml
187
+ bookstore.async.yml
97
188
  paths/books.yml
98
189
  messages/books.yml
99
- models/shared.yml
190
+ models/enums.yml
100
191
  models/books.yml
101
192
  ```
102
193
 
103
194
  Good shared fragment:
104
195
 
105
196
  ```yaml
106
- # schema/bookstore/models/shared.yml
197
+ # schema/bookstore/models/enums.yml
198
+ BookFormat:
199
+ type: string
200
+ enum: [hardcover, paperback, ebook]
201
+
202
+ # schema/bookstore/models/books.yml
107
203
  BookSlug:
108
204
  type: string
109
205
  minLength: 1
@@ -114,30 +210,28 @@ PaginationMeta:
114
210
  $ref: ../../shared/common.yml#/components/schemas/PaginationMeta
115
211
  ```
116
212
 
117
- OpenAPI can use it through path and response fragments:
213
+ API schema can use it through path and response fragments:
118
214
 
119
215
  ```yaml
120
216
  # schema/bookstore/paths/books.yml
121
- paths:
122
- /books/{bookSlug}:
123
- parameters:
124
- - name: bookSlug
125
- in: path
126
- required: true
127
- schema:
128
- $ref: ../models/shared.yml#/BookSlug
129
- get:
130
- operationId: getBook
131
- responses:
132
- "200":
133
- description: Book detail.
134
- content:
135
- application/json:
136
- schema:
137
- $ref: ../models/books.yml#/Book
217
+ parameters:
218
+ - name: bookSlug
219
+ in: path
220
+ required: true
221
+ schema:
222
+ $ref: ../models/books.yml#/BookSlug
223
+ get:
224
+ operationId: getBook
225
+ responses:
226
+ "200":
227
+ description: Book detail.
228
+ content:
229
+ application/json:
230
+ schema:
231
+ $ref: ../models/books.yml#/Book
138
232
  ```
139
233
 
140
- AsyncAPI can use the same payload schema from a message fragment:
234
+ async schema can use the same payload schema from a message fragment:
141
235
 
142
236
  ```yaml
143
237
  # schema/bookstore/messages/books.yml
@@ -152,15 +246,94 @@ messages:
152
246
 
153
247
  Keep protocol-specific pieces out of `models/`:
154
248
 
155
- - OpenAPI paths, parameters, request bodies, responses → `paths/` or
249
+ - API schema paths, parameters, request bodies, responses → `paths/` or
156
250
  `components/`.
157
- - AsyncAPI channels, operations, messages → `messages/`.
158
- - Payload objects, enums, scalars, pagination, and reusable business shapes →
159
- `models/`.
251
+ - async schema channels, operations, messages → `messages/`.
252
+ - Payload objects, enums, scalars, and reusable business shapes → `models/`.
253
+ - Share enums through `models/enums.yml` when API schema and async schema use the same
254
+ vocabulary and values.
160
255
 
161
- This keeps HTTP DTOs, NATS zod messages, and generated models aligned without
256
+ This keeps API contracts, async messages, and generated models aligned without
162
257
  making either protocol depend on the other's metadata.
163
258
 
259
+ ## Kontract sets for reusable map fragments
260
+
261
+ Use `kontract.sets` when repeated YAML maps make the source noisy but the
262
+ reusable concept is not a standalone schema. `$sets` can apply reusable maps in
263
+ responses, parameters, schema properties, headers, request bodies, async
264
+ operations, messages, payload schemas, or any other mapping.
265
+
266
+ ```yaml
267
+ # schema/bookings/shared/components.yml
268
+ kontract:
269
+ sets:
270
+ StandardErrors:
271
+ "400":
272
+ $ref: '#/components/responses/BadRequest'
273
+ "401":
274
+ $ref: '#/components/responses/Unauthorized'
275
+ "403":
276
+ $ref: '#/components/responses/Forbidden'
277
+ "404":
278
+ $ref: '#/components/responses/NotFound'
279
+ "500":
280
+ $ref: '#/components/responses/InternalServerError'
281
+ AuditedFields:
282
+ createdAt:
283
+ type: string
284
+ format: date-time
285
+ updatedAt:
286
+ type: string
287
+ format: date-time
288
+ components:
289
+ responses:
290
+ BadRequest:
291
+ description: Bad request.
292
+ Unauthorized:
293
+ description: Unauthorized.
294
+ Forbidden:
295
+ description: Forbidden.
296
+ NotFound:
297
+ description: Not found.
298
+ InternalServerError:
299
+ description: Internal server error.
300
+ ```
301
+
302
+ ```yaml
303
+ # schema/bookings/public.api.yml
304
+ api: 3.0.3
305
+ paths:
306
+ /bookings:
307
+ post:
308
+ responses:
309
+ $sets:
310
+ - $ref: ./shared/components.yml#/kontract/sets/StandardErrors
311
+ "201":
312
+ description: Booking created.
313
+ content:
314
+ application/json:
315
+ schema:
316
+ $ref: '#/components/schemas/CreateBookingResponse'
317
+ components:
318
+ schemas:
319
+ Booking:
320
+ type: object
321
+ properties:
322
+ $sets:
323
+ - $ref: ./shared/components.yml#/kontract/sets/AuditedFields
324
+ id:
325
+ type: string
326
+ ```
327
+
328
+ Set rules:
329
+
330
+ - `$sets` merges maps only; it does not concatenate arrays.
331
+ - Local keys override set keys.
332
+ - Multiple sets that define the same key must use identical values.
333
+ - Kontract rebases copied `$ref` values when a set comes from another file.
334
+ - Normalized files passed to validators and generators do not contain
335
+ `kontract` or `$sets`.
336
+
164
337
  ## Response envelopes
165
338
 
166
339
  If every endpoint repeats the same envelope fields, do not retype them in every
@@ -187,7 +360,7 @@ components:
187
360
  ```
188
361
 
189
362
  ```yaml
190
- # schema/recipes/catalog.openapi.yml
363
+ # schema/recipes/catalog.api.yml
191
364
  components:
192
365
  schemas:
193
366
  RecipesFindOneResponse:
@@ -261,7 +434,7 @@ Then service-specific schedules can reference or compose those shared pieces.
261
434
 
262
435
  ## Review checklist
263
436
 
264
- After writing or updating any `*.openapi.yml` or `*.asyncapi.yml` file, review
437
+ After writing or updating any `*.api.yml` or `*.async.yml` file, review
265
438
  the spec before running generation. Actively look for these smells:
266
439
 
267
440
  - the same `success/timestamp/path/message` fields repeated in many response
@@ -276,7 +449,7 @@ the spec before running generation. Actively look for these smells:
276
449
  - repeated day-of-week schedule structures;
277
450
  - error response schemas or problem-details bodies copied instead of referencing
278
451
  shared responses;
279
- - event envelopes or AsyncAPI reply wrappers copied with the same product
452
+ - event envelopes or async schema reply wrappers copied with the same product
280
453
  meaning;
281
454
  - generated diffs adding many near-identical DTO/model files after a small API
282
455
  change.
@@ -293,24 +466,27 @@ components when:
293
466
  - a request DTO and response DTO intentionally differ, even if fields overlap;
294
467
  - names would become vague (`CommonThing`, `BaseData`, `GenericConfig`);
295
468
  - the reusable name would hide a real product term, such as using `Collection`
296
- when collections are a domain concept in the product;
297
- - sharing would force unrelated teams/domains to coordinate every future change.
469
+ when collections are a product concept;
470
+ - sharing would force unrelated teams or product areas to coordinate every
471
+ future change.
298
472
 
299
473
  A good shared component has a clear product meaning and a stable owner.
300
474
 
301
475
  ## Safe workflow
302
476
 
303
- 1. Move the repeated shape into `schema/shared/*.yml` or a domain-level shared
304
- component.
305
- 2. Replace duplicated schemas/parameters/responses with `$ref`.
306
- 3. Use supported `allOf` object composition when a concrete response extends a
477
+ 1. Keep new schemas local to the root or surface that owns them.
478
+ 2. When reuse appears inside one capability, move the repeated shape into that
479
+ capability's `shared/` folder and replace duplicates with `$ref`.
480
+ 3. When reuse appears across capabilities, promote the shape to
481
+ `schema/shared/` and update `$ref` links deliberately.
482
+ 4. Use supported `allOf` object composition when a concrete response extends a
307
483
  shared base.
308
- 4. Run `sumr kontract validate`.
309
- 5. Run a scoped generation first, for example:
484
+ 5. Run `sumr kontract validate`.
485
+ 6. Run a scoped generation first, for example:
310
486
 
311
487
  ```bash
312
488
  sumr kontract generate --source api --target backend --specific recipes/catalog
313
489
  ```
314
490
 
315
- 6. Review both the spec diff and generated diff. If generated output changed in
316
- unrelated domains, stop and investigate before committing.
491
+ 7. Review both the spec diff and generated diff. If generated output changed in
492
+ unrelated product areas, stop and investigate before committing.
@@ -2,18 +2,18 @@
2
2
  category: reference
3
3
  name: scope-and-splitting
4
4
  title: Scope, Size, and Splitting
5
- description: "How to keep Kontract specs and generator code small, domain-aligned, and reviewable with explicit line-count budgets and split triggers."
5
+ description: "How to keep Kontract specs and generator code small, product-aligned, and reviewable with explicit line-count budgets and split triggers."
6
6
  label: Scope and Splitting
7
- when: Reviewing large specs or code files, deciding whether to split a domain/subdomain spec, or optimizing oversized Kontract modules
7
+ when: Reviewing large specs or code files, deciding whether to split a product capability/API surface spec, or optimizing oversized Kontract modules
8
8
  order: 18
9
9
  ---
10
10
 
11
11
  # Scope, Size, and Splitting
12
12
 
13
- Kontract is the next iteration of the AutoSync/AsyncAPI idea: keep the
13
+ Kontract is the next iteration of the AutoSync/async schema idea: keep the
14
14
  documentation-first and DRY discipline, but make the boundaries more explicit.
15
15
  Large files are not automatically bad, but they hide duplicated concepts,
16
- mixed domains, and unstable generated output. Treat size limits as review
16
+ mixed product areas, and unstable generated output. Treat size limits as review
17
17
  triggers first and hard caps second.
18
18
 
19
19
  ## Source-of-truth rule
@@ -29,7 +29,7 @@ Files under `resources/` become public AI guidance. Never use internal SUMR,
29
29
  customer, product, infrastructure, event-subject, route, table, or data-model
30
30
  examples there. Public examples must be sanitized and generic.
31
31
 
32
- Use neutral domains such as:
32
+ Use example areas such as:
33
33
 
34
34
  - kitchen recipes and ingredients;
35
35
  - bookstore inventory;
@@ -48,7 +48,7 @@ explain the module's current behavior.
48
48
  | File kind | Healthy target | Review trigger | Split/optimize trigger | Hard stop |
49
49
  |---|---:|---:|---:|---:|
50
50
  | Kontract TypeScript source | <= 200 lines | > 250 lines | > 400 lines | > 500 lines |
51
- | OpenAPI/AsyncAPI service spec | 150-350 lines | > 400 lines | > 700 lines | > 1000 lines |
51
+ | API/async service spec | 150-350 lines | > 400 lines | > 700 lines | > 1000 lines |
52
52
  | Shared component YAML | 100-300 lines | > 400 lines | > 600 lines | > 900 lines |
53
53
  | Generated TypeScript output | no manual target | review if surprising | fix generator/spec, never hand-split | no hand edits |
54
54
 
@@ -60,7 +60,7 @@ manual splitting, but they can still reveal generator or spec-design problems.
60
60
 
61
61
  Split or optimize before adding more content when a file shows any of these:
62
62
 
63
- - multiple product domains or subdomains in one spec;
63
+ - multiple product capabilities or API surfaces in one spec;
64
64
  - more than roughly 7-10 operations with different lifecycle owners;
65
65
  - request/response schemas for unrelated use cases in one component block;
66
66
  - repeated envelope, pagination, error, scalar, schedule, or config shapes;
@@ -73,92 +73,148 @@ Do not split only by line count. First identify the product or technical
73
73
  boundary that gives the new file a stable name and owner.
74
74
 
75
75
  Visual section comments can help readers navigate a healthy file, but they are
76
- not a substitute for splitting an oversized or mixed-domain spec. If comments
77
- start acting like a table of contents, split by domain/subdomain instead.
76
+ not a substitute for splitting an oversized or mixed-surface spec. If comments
77
+ start acting like a table of contents, split by capability/surface instead.
78
78
 
79
- ## Domain and subdomain spec structure
79
+ ## Product capability and API surface spec structure
80
80
 
81
81
  Use directory nesting to communicate product ownership. The path should answer
82
82
  "who owns this contract?" and the filename should answer "which surface is this?"
83
+ Read `kontract.guidance.profile.schemaLayoutStyle` before proposing a layout and
84
+ use the canonical trees in the schema layout style reference. Do not describe
85
+ resource-area fragments inside a product-capability folder as a repo-wide
86
+ `by-resource-area` layout.
87
+
88
+ For an API-only repo, keep the example API-only:
83
89
 
84
90
  ```text
85
91
  schema/
92
+ recipes/
93
+ main.api.yml # api: 3.0.3; grouped under recipes/http
94
+ catalog.api.yml
95
+ ingredients.api.yml
96
+ shared/ # only promoted reusable recipe concepts
97
+ enums.yml
98
+ components.yml
99
+ kitchen/
100
+ stations.api.yml
86
101
  shared/
87
- scalars.yml
88
- pagination.yml
102
+ pagination.yml # only promoted cross-capability components
89
103
  errors.yml
90
- events.yml
91
- scheduling.yml
104
+ ```
105
+
106
+ For an async-only repo, keep the example async-only:
107
+
108
+ ```text
109
+ schema/
110
+ shared/
111
+ message-enums.yml
92
112
  recipes/
93
- recipes.openapi.yml
94
- ingredients.openapi.yml
95
- publishing.asyncapi.yml
96
- kitchen/
97
- stations.openapi.yml
98
- prep-jobs.asyncapi.yml
99
- inventory.asyncapi.yml
100
- bookstore/
101
- bookstore.openapi.yml # OpenAPI root entrypoint
102
- bookstore.asyncapi.yml # AsyncAPI root entrypoint
103
- paths/
104
- books.yml # HTTP paths by subdomain
105
- authors.yml
113
+ recipes.async.yml
106
114
  messages/
107
- books.yml # NATS channels/messages by subdomain
108
- authors.yml
115
+ recipe-commands.yml
116
+ recipe-events.yml
109
117
  models/
110
- shared.yml # model fragments shared by both roots
111
- books.yml
112
- authors.yml
118
+ recipe.yml
119
+ enums.yml
113
120
  ```
114
121
 
115
- When a folder already carries the domain name, prefer `*.schema.yml` for
116
- subdomain surfaces that should generate as one domain package:
122
+ When a folder already carries the product-capability name, prefer
123
+ `*.api.yml` for focused surfaces that should generate as one package:
117
124
 
118
125
  ```text
119
126
  schema/
120
127
  recipes/
121
- catalog.schema.yml # openapi: 3.0.3
122
- publishing.schema.yml # asyncapi: 3.0.0
123
- inventory.schema.yml # asyncapi: 3.0.0
128
+ catalog.api.yml # api: 3.0.3
129
+ ingredients.api.yml # api: 3.0.3
130
+ shared/
131
+ enums.yml # promoted after both surfaces need it
132
+ components.yml
124
133
  ```
125
134
 
126
135
  Kontract content-detects the protocol marker and groups those files under the
127
- first folder (`recipes` in this example). Use explicit `*.openapi.yml` or
128
- `*.asyncapi.yml` when each nested file should remain an independently generated
136
+ first folder (`recipes` in this example). Use explicit `*.api.yml` or
137
+ `*.async.yml` when each nested file should remain an independently generated
129
138
  service path.
130
139
 
131
- When one domain should keep a single generated package but the contract is too
132
- large for one file, keep the explicit root files and split the internals into
133
- plain `.yml` fragments. This mirrors Redocly-style authoring: roots are the
134
- public entrypoints, fragments are implementation detail, and schemas can be
135
- shared by OpenAPI and AsyncAPI only when the business shape is protocol-neutral.
140
+ Add async schema examples only when messaging contracts exist:
141
+
142
+ ```text
143
+ schema/
144
+ recipes/
145
+ catalog.api.yml # api: 3.0.3
146
+ publishing.async.yml # async: 3.0.0
147
+ inventory.async.yml # async: 3.0.0
148
+ ```
149
+
150
+ When API schema and async schema both exist, keep `paths/` and `messages/` separate.
151
+ Share only schemas, especially enums, scalar value objects, IDs, and
152
+ slugs, through `models/` or `schema/shared/`.
153
+
154
+ If the selected schema layout style is `by-resource-area`, the resource
155
+ areas should be top-level roots under the configured schema input, not nested
156
+ under a product-capability folder. Moving from capability roots to resource-area
157
+ roots changes generated output namespaces/import paths, so call it out as a
158
+ schema and generated-output migration before recommending it.
159
+
160
+ When one product capability should keep a single generated package but the
161
+ contract is too large for one file, keep the explicit root files and split the
162
+ internals into plain `.yml` fragments. This mirrors Redocly-style authoring:
163
+ roots are the public entrypoints, fragments are implementation detail, and
164
+ schemas can be shared by API schema and async schema only when the business shape is
165
+ protocol-neutral.
166
+
167
+ ```text
168
+ schema/
169
+ bookstore/
170
+ bookstore.api.yml # API schema root entrypoint
171
+ paths/
172
+ books.yml # API schema Path Item fragment
173
+ authors.yml # API schema Path Item fragment
174
+ models/
175
+ shared.yml
176
+ books.yml
177
+ authors.yml
178
+ ```
179
+
180
+ Only add `bookstore.async.yml` and `messages/` fragments if the repo has
181
+ async schema contracts or the user asks for messaging. Do not use split fragments as
182
+ the default answer for a small API schema file.
136
183
 
137
184
  Guidelines:
138
185
 
139
- - Keep one entry-point spec per bounded API surface, not one giant file per
140
- repo.
186
+ - Keep one entry-point spec per independently released API surface, not one
187
+ giant file per repo.
141
188
  - Split by product meaning: `recipes`, `ingredients`, `orders`, `jobs`, or
142
189
  `inventory`, not by generic words like `common`, `misc`, or `helpers`.
190
+ - Keep API schema route hierarchies aligned with the selected HTTP style. When a
191
+ child route depends on a parent for authorization, tenancy, lifecycle, or
192
+ meaning, nest it under that parent unless the selected style documents a
193
+ different public pattern.
143
194
  - Use short section markers only as editor landmarks inside a file that is still
144
195
  small enough to review.
145
- - Use `schema/shared/` only for cross-domain concepts with stable semantics and
146
- an obvious owner.
147
- - Prefer domain-local shared components when a concept is reused only inside one
148
- domain.
149
- - Keep `info.title` deliberate because AsyncAPI NATS namespaces derive from it;
196
+ - Use `schema/shared/` only for cross-capability concepts with stable semantics
197
+ and an obvious owner.
198
+ - Prefer capability-local shared components when a concept is reused only inside
199
+ one product capability.
200
+ - Keep one-off schemas inside the surface that owns them. Do not move every
201
+ component into `shared/` to anticipate future reuse.
202
+ - Keep `info.title` deliberate because async schema NATS namespaces derive from it;
150
203
  filenames and titles should not drift semantically.
151
204
  - Keep `$ref` paths repo-relative and validate after moving files.
152
205
 
153
206
  ## Refactor order for oversized specs
154
207
 
155
- 1. Extract repeated cross-domain scalars, pagination, errors, envelopes, events,
156
- schedules, and config objects into `schema/shared/`.
157
- 2. Extract repeated domain-only shapes into a domain-local shared YAML file.
158
- 3. Split operations by subdomain when the file still mixes independently owned
208
+ 1. Keep one-off schemas local to the root or surface that owns them.
209
+ 2. Extract repeated capability-only shapes into a capability-local `shared/`
210
+ folder.
211
+ 3. Promote repeated cross-capability scalars, pagination, errors, envelopes,
212
+ schedules, and config objects into `schema/shared/` only when the same meaning
213
+ is reused across capabilities.
214
+ 4. Split operations by API surface when the file still mixes independently owned
159
215
  workflows.
160
- 4. Validate the moved refs with `sumr kontract validate`.
161
- 5. Generate with the smallest useful scope and review both the spec diff and
216
+ 5. Validate the moved refs with `sumr kontract validate`.
217
+ 6. Generate with the smallest useful scope and review both the spec diff and
162
218
  generated output diff.
163
219
 
164
220
  ## Refactor order for oversized code