@cratis/pi 0.0.1 → 2.0.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 (234) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +18 -37
  3. package/package/corpus/agents/backend-developer.md +125 -0
  4. package/package/corpus/agents/code-reviewer.md +165 -0
  5. package/package/corpus/agents/coordinator.md +163 -0
  6. package/package/corpus/agents/frontend-developer.md +246 -0
  7. package/package/corpus/agents/orchestrator.md +196 -0
  8. package/package/corpus/agents/performance-reviewer.md +109 -0
  9. package/package/corpus/agents/planner.md +145 -0
  10. package/package/corpus/agents/repository-investigation-reviewer.md +45 -0
  11. package/package/corpus/agents/repository-investigator.md +50 -0
  12. package/package/corpus/agents/security-reviewer.md +118 -0
  13. package/package/corpus/agents/slice-implementer.md +59 -0
  14. package/package/corpus/agents/spec-writer.md +149 -0
  15. package/package/corpus/harnesses/pi/extensions/cratis-hooks/index.ts +213 -0
  16. package/package/corpus/harnesses/pi/extensions/cratis-rules/index.ts +27 -0
  17. package/package/corpus/harnesses/pi/extensions/package.json +4 -0
  18. package/package/corpus/harnesses/pi/extensions/subagent/agents.ts +167 -0
  19. package/package/corpus/harnesses/pi/extensions/subagent/index.ts +352 -0
  20. package/package/corpus/hooks/README.md +434 -0
  21. package/package/corpus/hooks/agent-stop.md +49 -0
  22. package/package/corpus/hooks/pre-commit.md +47 -0
  23. package/package/corpus/hooks/scripts/cratis-guard-writes.sh +87 -0
  24. package/package/corpus/hooks/scripts/cratis-nuget-pins.txt +11 -0
  25. package/package/corpus/hooks/scripts/cratis-pattern-scan.sh +197 -0
  26. package/package/corpus/hooks/scripts/cratis-patterns.json +84 -0
  27. package/package/corpus/hooks/scripts/cratis-quality-gate.sh +219 -0
  28. package/package/corpus/hooks/scripts/hook-lib.sh +152 -0
  29. package/package/corpus/hooks/scripts/quality-gates.json +261 -0
  30. package/package/corpus/hooks/scripts/type-references-allowlist.txt +71 -0
  31. package/package/corpus/hooks/scripts/validate-package-imports.sh +166 -0
  32. package/package/corpus/hooks/scripts/validate-package-subpaths.sh +120 -0
  33. package/package/corpus/hooks/scripts/validate-type-references.sh +308 -0
  34. package/package/corpus/hooks/settings.template.json +40 -0
  35. package/package/corpus/prompts/add-business-rule.prompt.md +22 -0
  36. package/package/corpus/prompts/add-concept.prompt.md +17 -0
  37. package/package/corpus/prompts/add-ef-migration.prompt.md +24 -0
  38. package/package/corpus/prompts/add-projection.prompt.md +20 -0
  39. package/package/corpus/prompts/add-reactor.prompt.md +22 -0
  40. package/package/corpus/prompts/add-reducer.prompt.md +20 -0
  41. package/package/corpus/prompts/audit-hooks.prompt.md +15 -0
  42. package/package/corpus/prompts/check-doc-drift.prompt.md +21 -0
  43. package/package/corpus/prompts/code-review.prompt.md +9 -0
  44. package/package/corpus/prompts/new-feature.prompt.md +9 -0
  45. package/package/corpus/prompts/new-vertical-slice.prompt.md +18 -0
  46. package/package/corpus/prompts/review-pr.prompt.md +35 -0
  47. package/package/corpus/prompts/review-skill.prompt.md +16 -0
  48. package/package/corpus/prompts/scaffold-feature.prompt.md +16 -0
  49. package/package/corpus/prompts/ship-changes.prompt.md +20 -0
  50. package/package/corpus/prompts/verify-ai-setup.prompt.md +19 -0
  51. package/package/corpus/prompts/write-documentation.prompt.md +21 -0
  52. package/package/corpus/prompts/write-specs.prompt.md +22 -0
  53. package/package/corpus/rules/capability-is-not-authority.md +31 -0
  54. package/package/corpus/rules/code-quality.csharp.md +91 -0
  55. package/package/corpus/rules/code-quality.md +82 -0
  56. package/package/corpus/rules/code-quality.typescript.md +89 -0
  57. package/package/corpus/rules/components.md +207 -0
  58. package/package/corpus/rules/concepts.md +115 -0
  59. package/package/corpus/rules/csharp.md +269 -0
  60. package/package/corpus/rules/dialogs.md +264 -0
  61. package/package/corpus/rules/documentation-structure-and-formatting.md +148 -0
  62. package/package/corpus/rules/documentation.md +90 -0
  63. package/package/corpus/rules/editing-cratis-docs.md +69 -0
  64. package/package/corpus/rules/efcore.md +235 -0
  65. package/package/corpus/rules/efcore.specs.md +44 -0
  66. package/package/corpus/rules/exit-codes-and-wrappers.md +33 -0
  67. package/package/corpus/rules/framework.md +52 -0
  68. package/package/corpus/rules/frontend-quality.md +59 -0
  69. package/package/corpus/rules/frontend-testing.md +126 -0
  70. package/package/corpus/rules/general.md +305 -0
  71. package/package/corpus/rules/git-commits.md +138 -0
  72. package/package/corpus/rules/github-actions.md +92 -0
  73. package/package/corpus/rules/glossary.md +61 -0
  74. package/package/corpus/rules/guards-and-fuses.md +45 -0
  75. package/package/corpus/rules/local-work-artifacts.md +33 -0
  76. package/package/corpus/rules/managing-ai-rules.md +40 -0
  77. package/package/corpus/rules/orleans.md +50 -0
  78. package/package/corpus/rules/pull-requests.md +78 -0
  79. package/package/corpus/rules/react.md +195 -0
  80. package/package/corpus/rules/reactors.md +238 -0
  81. package/package/corpus/rules/rtk.md +37 -0
  82. package/package/corpus/rules/specs.csharp.md +139 -0
  83. package/package/corpus/rules/specs.md +132 -0
  84. package/package/corpus/rules/specs.scenarios.csharp.md +172 -0
  85. package/package/corpus/rules/specs.typescript.md +139 -0
  86. package/package/corpus/rules/storybook.md +84 -0
  87. package/package/corpus/rules/terminal-commands.md +19 -0
  88. package/package/corpus/rules/typescript.md +149 -0
  89. package/package/corpus/rules/verification-discipline.md +21 -0
  90. package/package/corpus/rules/vertical-slices.md +338 -0
  91. package/package/corpus/rules/web-fetching.md +11 -0
  92. package/package/corpus/rules/writing-correct-examples.md +35 -0
  93. package/package/corpus/rules/writing-cratis-docs.md +70 -0
  94. package/package/corpus/skills/cratis-engineering-csharp-conventions/LICENSE +2 -0
  95. package/package/corpus/skills/cratis-engineering-csharp-conventions/SKILL.md +131 -0
  96. package/package/corpus/skills/cratis-engineering-csharp-conventions/references/code-style.md +187 -0
  97. package/package/corpus/skills/cratis-engineering-csharp-conventions/references/domain-philosophy.md +91 -0
  98. package/package/corpus/skills/cratis-engineering-csharp-conventions/references/exceptions-logging-and-di.md +223 -0
  99. package/package/corpus/skills/cratis-engineering-decision-record/LICENSE +2 -0
  100. package/package/corpus/skills/cratis-engineering-decision-record/SKILL.md +133 -0
  101. package/package/corpus/skills/cratis-engineering-decision-record/references/record-format.md +107 -0
  102. package/package/corpus/skills/cratis-engineering-docs-authoring/LICENSE +2 -0
  103. package/package/corpus/skills/cratis-engineering-docs-authoring/SKILL.md +86 -0
  104. package/package/corpus/skills/cratis-engineering-docs-authoring/references/site-format.md +46 -0
  105. package/package/corpus/skills/cratis-engineering-effect-boundaries/LICENSE +2 -0
  106. package/package/corpus/skills/cratis-engineering-effect-boundaries/SKILL.md +130 -0
  107. package/package/corpus/skills/cratis-engineering-effect-boundaries/references/failure-archetypes.md +133 -0
  108. package/package/corpus/skills/cratis-fundamentals-concept/verification.json +8 -0
  109. package/package/profile-catalog.json +821 -0
  110. package/package.json +35 -13
  111. package/src/index.ts +80 -0
  112. /package/{skills → package/corpus/skills}/cratis-application-react-specifications/LICENSE +0 -0
  113. /package/{skills → package/corpus/skills}/cratis-application-react-specifications/SKILL.md +0 -0
  114. /package/{skills → package/corpus/skills}/cratis-application-slice-specifications/LICENSE +0 -0
  115. /package/{skills → package/corpus/skills}/cratis-application-slice-specifications/SKILL.md +0 -0
  116. /package/{skills → package/corpus/skills}/cratis-arc-authentication-authorization-and-identity/LICENSE +0 -0
  117. /package/{skills → package/corpus/skills}/cratis-arc-authentication-authorization-and-identity/SKILL.md +0 -0
  118. /package/{skills → package/corpus/skills}/cratis-arc-authentication-authorization-and-identity/references/authentication.md +0 -0
  119. /package/{skills → package/corpus/skills}/cratis-arc-authentication-authorization-and-identity/references/authorization.md +0 -0
  120. /package/{skills → package/corpus/skills}/cratis-arc-authentication-authorization-and-identity/references/frontend.md +0 -0
  121. /package/{skills → package/corpus/skills}/cratis-arc-authentication-authorization-and-identity/references/local-development.md +0 -0
  122. /package/{skills → package/corpus/skills}/cratis-arc-authentication-authorization-and-identity/references/tenancy.md +0 -0
  123. /package/{skills → package/corpus/skills}/cratis-arc-command/LICENSE +0 -0
  124. /package/{skills → package/corpus/skills}/cratis-arc-command/SKILL.md +0 -0
  125. /package/{skills → package/corpus/skills}/cratis-arc-command/references/command-result.md +0 -0
  126. /package/{skills → package/corpus/skills}/cratis-arc-command/references/handler-shapes.md +0 -0
  127. /package/{skills → package/corpus/skills}/cratis-arc-command/references/proxy-generation.md +0 -0
  128. /package/{skills → package/corpus/skills}/cratis-arc-command/references/read-model-injection.md +0 -0
  129. /package/{skills → package/corpus/skills}/cratis-arc-command-execution/LICENSE +0 -0
  130. /package/{skills → package/corpus/skills}/cratis-arc-command-execution/SKILL.md +0 -0
  131. /package/{skills → package/corpus/skills}/cratis-arc-command-validation/LICENSE +0 -0
  132. /package/{skills → package/corpus/skills}/cratis-arc-command-validation/SKILL.md +0 -0
  133. /package/{skills → package/corpus/skills}/cratis-arc-ef-core-migration/LICENSE +0 -0
  134. /package/{skills → package/corpus/skills}/cratis-arc-ef-core-migration/SKILL.md +0 -0
  135. /package/{skills → package/corpus/skills}/cratis-arc-observable-query-http/LICENSE +0 -0
  136. /package/{skills → package/corpus/skills}/cratis-arc-observable-query-http/SKILL.md +0 -0
  137. /package/{skills → package/corpus/skills}/cratis-arc-query-paging/LICENSE +0 -0
  138. /package/{skills → package/corpus/skills}/cratis-arc-query-paging/SKILL.md +0 -0
  139. /package/{skills → package/corpus/skills}/cratis-arc-react-page/LICENSE +0 -0
  140. /package/{skills → package/corpus/skills}/cratis-arc-react-page/SKILL.md +0 -0
  141. /package/{skills → package/corpus/skills}/cratis-arc-react-page/references/data-page.md +0 -0
  142. /package/{skills → package/corpus/skills}/cratis-arc-react-page/references/data-tables.md +0 -0
  143. /package/{skills → package/corpus/skills}/cratis-arc-react-page/references/dialogs.md +0 -0
  144. /package/{skills → package/corpus/skills}/cratis-arc-react-page/references/mvvm.md +0 -0
  145. /package/{skills → package/corpus/skills}/cratis-arc-react-page/references/queries-and-commands.md +0 -0
  146. /package/{skills → package/corpus/skills}/cratis-chronicle-cli-operations/LICENSE +0 -0
  147. /package/{skills → package/corpus/skills}/cratis-chronicle-cli-operations/SKILL.md +0 -0
  148. /package/{skills → package/corpus/skills}/cratis-chronicle-client-dotnet/LICENSE +0 -0
  149. /package/{skills → package/corpus/skills}/cratis-chronicle-client-dotnet/SKILL.md +0 -0
  150. /package/{skills → package/corpus/skills}/cratis-chronicle-client-elixir/LICENSE +0 -0
  151. /package/{skills → package/corpus/skills}/cratis-chronicle-client-elixir/SKILL.md +0 -0
  152. /package/{skills → package/corpus/skills}/cratis-chronicle-client-kotlin/LICENSE +0 -0
  153. /package/{skills → package/corpus/skills}/cratis-chronicle-client-kotlin/SKILL.md +0 -0
  154. /package/{skills → package/corpus/skills}/cratis-chronicle-client-typescript/LICENSE +0 -0
  155. /package/{skills → package/corpus/skills}/cratis-chronicle-client-typescript/SKILL.md +0 -0
  156. /package/{skills → package/corpus/skills}/cratis-chronicle-compliance/LICENSE +0 -0
  157. /package/{skills → package/corpus/skills}/cratis-chronicle-compliance/SKILL.md +0 -0
  158. /package/{skills → package/corpus/skills}/cratis-chronicle-event-constraints/LICENSE +0 -0
  159. /package/{skills → package/corpus/skills}/cratis-chronicle-event-constraints/SKILL.md +0 -0
  160. /package/{skills → package/corpus/skills}/cratis-chronicle-event-modeling/LICENSE +0 -0
  161. /package/{skills → package/corpus/skills}/cratis-chronicle-event-modeling/SKILL.md +0 -0
  162. /package/{skills → package/corpus/skills}/cratis-chronicle-event-specifications/LICENSE +0 -0
  163. /package/{skills → package/corpus/skills}/cratis-chronicle-event-specifications/SKILL.md +0 -0
  164. /package/{skills → package/corpus/skills}/cratis-chronicle-event-type-migration/LICENSE +0 -0
  165. /package/{skills → package/corpus/skills}/cratis-chronicle-event-type-migration/SKILL.md +0 -0
  166. /package/{skills → package/corpus/skills}/cratis-chronicle-mcp-inspection/LICENSE +0 -0
  167. /package/{skills → package/corpus/skills}/cratis-chronicle-mcp-inspection/SKILL.md +0 -0
  168. /package/{skills → package/corpus/skills}/cratis-chronicle-mcp-inspection/references/blocked-tools.md +0 -0
  169. /package/{skills → package/corpus/skills}/cratis-chronicle-mcp-inspection/references/observational-tools.md +0 -0
  170. /package/{skills → package/corpus/skills}/cratis-chronicle-multi-tenancy/LICENSE +0 -0
  171. /package/{skills → package/corpus/skills}/cratis-chronicle-multi-tenancy/SKILL.md +0 -0
  172. /package/{skills → package/corpus/skills}/cratis-chronicle-projection/LICENSE +0 -0
  173. /package/{skills → package/corpus/skills}/cratis-chronicle-projection/SKILL.md +0 -0
  174. /package/{skills → package/corpus/skills}/cratis-chronicle-projection/references/fluent-builder.md +0 -0
  175. /package/{skills → package/corpus/skills}/cratis-chronicle-projection/references/model-bound-attributes.md +0 -0
  176. /package/{skills → package/corpus/skills}/cratis-chronicle-reactor/LICENSE +0 -0
  177. /package/{skills → package/corpus/skills}/cratis-chronicle-reactor/SKILL.md +0 -0
  178. /package/{skills → package/corpus/skills}/cratis-chronicle-read-model/LICENSE +0 -0
  179. /package/{skills → package/corpus/skills}/cratis-chronicle-read-model/SKILL.md +0 -0
  180. /package/{skills → package/corpus/skills}/cratis-chronicle-read-model/references/queries.md +0 -0
  181. /package/{skills → package/corpus/skills}/cratis-chronicle-read-model-specifications/LICENSE +0 -0
  182. /package/{skills → package/corpus/skills}/cratis-chronicle-read-model-specifications/SKILL.md +0 -0
  183. /package/{skills → package/corpus/skills}/cratis-chronicle-reducer/LICENSE +0 -0
  184. /package/{skills → package/corpus/skills}/cratis-chronicle-reducer/SKILL.md +0 -0
  185. /package/{skills → package/corpus/skills}/cratis-chronicle-web-workbench/LICENSE +0 -0
  186. /package/{skills → package/corpus/skills}/cratis-chronicle-web-workbench/SKILL.md +0 -0
  187. /package/{skills → package/corpus/skills}/cratis-cli-terminal-workbench/LICENSE +0 -0
  188. /package/{skills → package/corpus/skills}/cratis-cli-terminal-workbench/SKILL.md +0 -0
  189. /package/{skills → package/corpus/skills}/cratis-code-review/LICENSE +0 -0
  190. /package/{skills → package/corpus/skills}/cratis-code-review/SKILL.md +0 -0
  191. /package/{skills → package/corpus/skills}/cratis-components-accessibility/LICENSE +0 -0
  192. /package/{skills → package/corpus/skills}/cratis-components-accessibility/SKILL.md +0 -0
  193. /package/{skills → package/corpus/skills}/cratis-components-schema-editor/LICENSE +0 -0
  194. /package/{skills → package/corpus/skills}/cratis-components-schema-editor/SKILL.md +0 -0
  195. /package/{skills → package/corpus/skills}/cratis-components-stepper-command-dialog/LICENSE +0 -0
  196. /package/{skills → package/corpus/skills}/cratis-components-stepper-command-dialog/SKILL.md +0 -0
  197. /package/{skills → package/corpus/skills}/cratis-components-styling/LICENSE +0 -0
  198. /package/{skills → package/corpus/skills}/cratis-components-styling/SKILL.md +0 -0
  199. /package/{skills → package/corpus/skills}/cratis-components-toolbar/LICENSE +0 -0
  200. /package/{skills → package/corpus/skills}/cratis-components-toolbar/SKILL.md +0 -0
  201. /package/{skills → package/corpus/skills}/cratis-documentation-writing/LICENSE +0 -0
  202. /package/{skills → package/corpus/skills}/cratis-documentation-writing/SKILL.md +0 -0
  203. /package/{skills → package/corpus/skills}/cratis-event-model-diagram/LICENSE +0 -0
  204. /package/{skills → package/corpus/skills}/cratis-event-model-diagram/SKILL.md +0 -0
  205. /package/{skills → package/corpus/skills}/cratis-fundamentals-concept/LICENSE +0 -0
  206. /package/{skills → package/corpus/skills}/cratis-fundamentals-concept/SKILL.md +0 -0
  207. /package/{skills → package/corpus/skills}/cratis-fundamentals-type-discovery/LICENSE +0 -0
  208. /package/{skills → package/corpus/skills}/cratis-fundamentals-type-discovery/SKILL.md +0 -0
  209. /package/{skills → package/corpus/skills}/cratis-governed-release-methodology/LICENSE +0 -0
  210. /package/{skills → package/corpus/skills}/cratis-governed-release-methodology/SKILL.md +0 -0
  211. /package/{skills → package/corpus/skills}/cratis-lens-browser-extension/LICENSE +0 -0
  212. /package/{skills → package/corpus/skills}/cratis-lens-browser-extension/SKILL.md +0 -0
  213. /package/{skills → package/corpus/skills}/cratis-performance-review/LICENSE +0 -0
  214. /package/{skills → package/corpus/skills}/cratis-performance-review/SKILL.md +0 -0
  215. /package/{skills → package/corpus/skills}/cratis-screenplay-model-authoring/LICENSE +0 -0
  216. /package/{skills → package/corpus/skills}/cratis-screenplay-model-authoring/SKILL.md +0 -0
  217. /package/{skills → package/corpus/skills}/cratis-security-review/LICENSE +0 -0
  218. /package/{skills → package/corpus/skills}/cratis-security-review/SKILL.md +0 -0
  219. /package/{skills → package/corpus/skills}/cratis-specification-by-example/LICENSE +0 -0
  220. /package/{skills → package/corpus/skills}/cratis-specification-by-example/SKILL.md +0 -0
  221. /package/{skills → package/corpus/skills}/cratis-specifications-csharp/LICENSE +0 -0
  222. /package/{skills → package/corpus/skills}/cratis-specifications-csharp/SKILL.md +0 -0
  223. /package/{skills → package/corpus/skills}/cratis-specifications-csharp/references/application-scenarios.md +0 -0
  224. /package/{skills → package/corpus/skills}/cratis-specifications-csharp/references/csharp-patterns.md +0 -0
  225. /package/{skills → package/corpus/skills}/cratis-specifications-csharp/references/integration-specs.md +0 -0
  226. /package/{skills → package/corpus/skills}/cratis-specifications-typescript/LICENSE +0 -0
  227. /package/{skills → package/corpus/skills}/cratis-specifications-typescript/SKILL.md +0 -0
  228. /package/{skills → package/corpus/skills}/cratis-specifications-typescript/references/typescript-patterns.md +0 -0
  229. /package/{skills → package/corpus/skills}/cratis-stage-rendering-and-sandbox/LICENSE +0 -0
  230. /package/{skills → package/corpus/skills}/cratis-stage-rendering-and-sandbox/SKILL.md +0 -0
  231. /package/{skills → package/corpus/skills}/cratis-studio-mcp-safety-guidance/LICENSE +0 -0
  232. /package/{skills → package/corpus/skills}/cratis-studio-mcp-safety-guidance/SKILL.md +0 -0
  233. /package/{skills → package/corpus/skills}/cratis-studio-mcp-safety-guidance/references/blocked-tools.md +0 -0
  234. /package/{skills → package/corpus/skills}/cratis-studio-mcp-safety-guidance/references/observational-tools.md +0 -0
@@ -0,0 +1,148 @@
1
+ ---
2
+ applyTo: "**/Documentation/**/*.{md,mdx}"
3
+ paths:
4
+ - "**/Documentation/**/*.md"
5
+ - "**/Documentation/**/*.mdx"
6
+ ---
7
+
8
+ # Documentation structure and formatting
9
+
10
+ This is the authoritative rendering contract for product documentation consumed by the Astro Starlight site. For content and teaching voice, see [Writing Cratis Documentation](./writing-cratis-docs.md). For source ownership and the edit loop, see [Editing Cratis Documentation](./editing-cratis-docs.md).
11
+
12
+ Product `.md` and `.mdx` files are copied through the Documentation repository's `web/scripts/sync-content.mjs`; the converter preserves the extension and rewrites the content before Starlight renders it.
13
+
14
+ ## Frontmatter
15
+
16
+ ```yaml
17
+ ---
18
+ title: Append an event
19
+ description: Append a domain event to one event source and inspect the result.
20
+ tableOfContents: false # optional per-page override
21
+ sidebar:
22
+ badge: { text: New, variant: tip }
23
+ ---
24
+ ```
25
+
26
+ - Product pages should declare `title` and `description`. The title becomes the page H1; the description feeds metadata and AI-facing exports.
27
+ - Preserve existing frontmatter when editing unless the task deliberately changes it. The converter preserves only `title`, `description`, `sidebar`, and `tableOfContents`; it drops DocFX keys and other Starlight keys. Features such as `template`, `hero`, `banner`, `head`, `prev`, `next`, `slug`, and `draft` work only on site-level pages authored directly in the Documentation repository.
28
+ - Product navigation comes from `toc.yml`, not Starlight autogeneration. `sidebar.badge` works, but `sidebar.order`, `sidebar.label`, and `sidebar.hidden` do not control product navigation.
29
+ - A frontmatter-less page falls back to its first H1, but that loses the description and relies on converter inference. Do not add new pages that way.
30
+
31
+ ## Headings
32
+
33
+ - Do not put an H1 in the body; frontmatter supplies it.
34
+ - The global “On this page” list shows H2 headings only. Organize the page around a short, flat set of `##` sections; use H3/H4 only inside them.
35
+ - Use sentence case and no trailing punctuation.
36
+ - Keep a real H2 when a section needs a stable URL anchor. A card or aside title is presentation, not document structure.
37
+
38
+ ## Files, folders, and navigation
39
+
40
+ - A navigable product folder normally has `toc.yml` plus one landing page: `<folder>/index.md[x]` or a sibling `<folder>.md[x]`.
41
+ - Never keep both `<folder>.md[x]` and `<folder>/index.md[x]`. A legacy `<folder>.md` sibling makes the sync move the directory index to `/overview/`; other duplicate landing shapes can fail the build. Either outcome can orphan the intended landing page or make compatibility links point back to themselves.
42
+ - A folder with neither an index nor a sibling landing has no page at its bare URL.
43
+ - Product bucket names are product-specific. Read that product's `PRODUCTS[].buckets` entry in `web/scripts/sync-content.mjs`; do not assume generic “Get started / Guides / Understand / Reference” labels.
44
+ - A missing built slug is dropped from the sidebar and counted as a broken toc entry. Keep that count at zero.
45
+ - `toc.yml` entries with external URLs, `../`, or `/api/` are intentionally dropped. A group with one child collapses to the child link. Check the generated sidebar rather than inferring it from YAML alone.
46
+ - Sync slugification lowercases path segments and removes characters outside `[a-z0-9_-]`; for example, `react.mvvm` becomes `reactmvvm`. Verify hand-authored site-absolute URLs against the built route.
47
+
48
+ ## Choose Markdown or MDX
49
+
50
+ Use the least powerful format that communicates the idea:
51
+
52
+ - Keep `.md` for headings, prose, links, GFM tables, fenced code, Mermaid/EventModeling diagrams, images, and Starlight aside directives.
53
+ - Use `.mdx` only when the page needs imported Astro components, expressions, props, or named slots.
54
+ - Imports and JSX in `.md` fail silently: the import can render as visible prose and the component as an inert element. Permissive Markdown HTML allowlists can hide this mistake. A page using a component must be `.mdx`.
55
+ - Do not rename a page to `.mdx` merely for a callout or diagram. Renames require checking `toc.yml`, inbound links, generated routes, and AI-facing Markdown output.
56
+ - Do not add raw HTML, inline styling, scripts, or one-off visual components to decorate a product page. Reuse an established component or make an explicit reusable site change in the Documentation repository.
57
+
58
+ ## Callouts and asides
59
+
60
+ The complete Starlight directive set is `note`, `tip`, `caution`, and `danger`. These work in both `.md` and `.mdx` and support a custom title:
61
+
62
+ ```markdown
63
+ :::caution[Do not use a raw Guid as the event source id]
64
+ Chronicle treats a raw `Guid` as an ordinary response value.
65
+ :::
66
+ ```
67
+
68
+ | Variant | Meaning |
69
+ |---|---|
70
+ | `note` | Neutral context or an important clarification |
71
+ | `tip` | A recommendation or easier path |
72
+ | `caution` | A likely mistake, compatibility trap, or behavior that produces the wrong result |
73
+ | `danger` | Destructive, security-sensitive, or data-loss consequences |
74
+
75
+ The set is closed. Do not use `warning`, `important`, `info`, or `success`: an unknown container directive silently renders as an unstyled `<div>` rather than failing the build.
76
+
77
+ Legacy DocFX alerts are converted as follows; prefer titled native directives when editing the surrounding content:
78
+
79
+ | DocFX | Starlight |
80
+ |---|---|
81
+ | `> [!NOTE]` / `> [!IMPORTANT]` | `:::note` |
82
+ | `> [!TIP]` | `:::tip` |
83
+ | `> [!WARNING]` | `:::caution` |
84
+ | `> [!CAUTION]` | `:::danger` |
85
+
86
+ In MDX, `<Aside type="tip" title="A specific title">…</Aside>` is available when component composition requires it. Directive asides can also take a Starlight icon attribute, but verify the icon name first; a bad aside icon fails the build.
87
+
88
+ ## Code blocks
89
+
90
+ - Always tag the language: `csharp`, `tsx`, `typescript`, `bash`, `yaml`, and so on.
91
+ - Expressive Code supports useful metadata such as ``title="Program.cs"`` and line/text markers. Use them to orient the reader or focus a diff, not to decorate every snippet.
92
+ - DocFX-era aliases include `env`, `pdl`, `ebnf`, `pql`, `gitignore`, `flow`, and `screenplay`; use a real language where one exists.
93
+ - Dedent snippets to column zero while preserving their internal indentation.
94
+ - Show both sides of a full-stack contract, but do not automatically hide sequential C#→generated-TypeScript explanations behind tabs. Use `FullStackTabs` only when the snippets are alternatives that remain understandable independently.
95
+ - The converter's DocFX-alert and link rewriting is not fully code-fence-aware. Literal `> [!NOTE]`, Markdown-link targets, or `href="…"` examples can be rewritten; inspect the synced output when documenting those syntaxes.
96
+
97
+ ## Tables, images, links, and diagrams
98
+
99
+ - Use GFM tables with a separator row and a blank line before the table. `remarkGfm` in the Documentation site's Astro config is load-bearing for `.mdx`; raw pipe text in a rendered page indicates that integration is missing or degraded.
100
+ - Keep images beside the source page, use meaningful alt text, and rely on the site's click-to-zoom behavior.
101
+ - In product source, relative links to files keep their real `.md` or `.mdx` extension. The converter strips either extension for the public route. Directory URLs end in `/`.
102
+ - Site-level MDX uses clean root-relative routes such as `/arc/backend/commands/`. Cross-product links are also root-relative.
103
+ - Link text describes the destination; `here`, `click here`, and `see documentation` are hard lint errors.
104
+ - Use `mermaid` for architecture, sequence, flow, and state diagrams. Use `eventmodeling` for EventModeling diagrams. Both are pre-rendered to responsive SVG at build time.
105
+
106
+ ## MDX component surface
107
+
108
+ Place imports immediately after frontmatter, with a blank line before the first body content. Import only what the page uses. Starlight exports exactly `Aside`, `Badge`, `Card`, `CardGrid`, `Code`, `FileTree`, `Icon`, `LinkButton`, `LinkCard`, `Steps`, `TabItem`, and `Tabs`:
109
+
110
+ ```mdx
111
+ import { Aside, Steps, TabItem, Tabs } from '@astrojs/starlight/components';
112
+ ```
113
+
114
+ Shared Cratis components are default imports through exact `@components/<Name>.astro` paths; there is no bare `@components` barrel:
115
+
116
+ ```mdx
117
+ import FullStackTabs from '@components/FullStackTabs.astro';
118
+ import Recap from '@components/Recap.astro';
119
+ ```
120
+
121
+ Common shared components include `FullStackTabs`, `OsAwareTabs`, `TopicHero`, `SimpleCard`, `StackDiagram`, `YouWillLearn`, and `Recap`. Inspect the current component and an existing page before using its props or slots; do not infer an API from the component name.
122
+
123
+ Icon names must come from the installed Starlight set. Use `seti:windows`, not `windows`. Invalid icons in `Icon`, `TabItem`, `SimpleCard`, and `TopicHero` can produce an empty SVG without a build failure, so visual verification is mandatory.
124
+
125
+ ## AI-facing Markdown
126
+
127
+ The published `.md` mirror behind page actions such as “Copy Markdown” is copied from synchronized Markdown/MDX rather than reconstructed from rendered HTML. Synced frontmatter and converter rewrites are present, but MDX imports and JSX remain visible in that raw Markdown surface. Prefer plain Markdown unless a component creates a real teaching advantage, and inspect the emitted `.md` artifact when changing a page's authoring format. Generated AI indexes can process content separately; do not infer their exact representation from the page action.
128
+
129
+ ## Verification
130
+
131
+ Run the owning repository's local documentation gate first when it has one. Many product repositories expose:
132
+
133
+ ```bash
134
+ ./Documentation/verify-markdown.sh
135
+ ```
136
+
137
+ For full-fidelity rendering, use the sibling Documentation checkout:
138
+
139
+ ```bash
140
+ cd ../Documentation/web
141
+ npm run check
142
+ ```
143
+
144
+ The local gate validates the authored repository in isolation. The full site check builds and syncs every available sibling product, runs site linting and rendered-link checks, and can expose unrelated sibling failures; diagnose those separately rather than silently waiving them. Some optional local tools skip when not installed, so name what actually ran.
145
+
146
+ A successful build proves syntax, not presentation. For any aside, diagram, tabs, cards, or custom component change, use the `qa-cratis-docs` skill to inspect light and dark screenshots.
147
+
148
+ End every file with a single trailing newline.
@@ -0,0 +1,90 @@
1
+ ---
2
+ applyTo: "**/Documentation/**/*.{md,mdx}"
3
+ paths:
4
+ - "**/Documentation/**/*.{md,mdx}"
5
+ ---
6
+
7
+ # How to write documentation
8
+
9
+ Documentation exists for one audience: **developers who need to use the framework** — not the team that built it. Write from the reader's perspective. They want to know *what this does*, *why they should care*, and *how to use it* — in that order.
10
+
11
+ Every page should answer: “If I were a developer encountering this concept for the first time, what would I need to understand to use it correctly?”
12
+
13
+ The site is built with [Astro Starlight](https://starlight.astro.build/). Documentation lives in the `Documentation/` folder of each product repository as [GitHub Flavored Markdown](https://github.github.com/gfm/); a converter synchronizes product `.md`/`.mdx` into the Starlight site, and all repositories are aggregated into one published site. Readers experience it as a single place — write for that whole, not for one repository in isolation. For the authoritative rendering contract, see [Documentation Structure and Formatting](./documentation-structure-and-formatting.md).
14
+
15
+ ## Every page is exactly one Diátaxis type
16
+
17
+ We organize documentation with the [Diátaxis framework](https://diataxis.fr/). Before writing, decide which of the four types a page is — and write *only* that type. Mixing types is the most common way docs fail: a tutorial padded with reference detail overwhelms the learner; a how-to interrupted by concept digressions stops being a quick recipe.
18
+
19
+ | Type | The reader is… | Reads like | Rule |
20
+ |---|---|---|---|
21
+ | **Tutorial** | learning by doing | a guided lesson | Steps that each produce a visible result. Do not explain *why* — just *do this, then this*. The reader must succeed even before they fully understand. |
22
+ | **How-to guide** | solving a specific problem | a recipe | Assume competence. Goal → prerequisites → steps → done. No teaching. |
23
+ | **Reference** | looking something up | a dictionary | Exhaustive and terse. Tables, signatures, attributes, configuration. No narrative. |
24
+ | **Explanation** | trying to understand | a discussion | Concepts, trade-offs, architecture, *why*. No steps. Lean on diagrams. |
25
+
26
+ Diátaxis governs a page's purpose and voice, not a universal set of sidebar labels. Each product has navigation buckets suited to its domain; read `PRODUCTS[].buckets` in the Documentation site's sync script before placing a new section.
27
+
28
+ For authoring a single page step by step, use the `write-documentation` skill.
29
+
30
+ ## Onboarding is the most important documentation you write
31
+
32
+ Most readers decide whether to adopt Cratis in the first ten minutes. Protect that path.
33
+
34
+ - **One canonical getting-started per product**, not a menu of competing quickstarts. Host variants are how-to guides linked *from* the canonical path — never rival front doors.
35
+ - Drive to a **visible payoff fast** — something running the reader can see. State it up front: “By the end you'll have X running.”
36
+ - **One threaded tutorial per product** builds a single realistic domain across chapters, each adding one concept. Open every chapter with what the reader will build or learn and close with a recap. The reader finishes with a working application, not a pile of snippets.
37
+ - **One cross-product capstone tutorial** builds a real full-stack feature using the relevant Cratis products together. This is the connective tissue between products — keep it current and runnable.
38
+
39
+ ## Connect the products
40
+
41
+ Readers do not care about repository boundaries — they are building one application.
42
+
43
+ - The site has **one front door** stating what Cratis is, with a one-sentence definition and a “start here” link for each product.
44
+ - Every product index opens with a **one-sentence definition** and a **“without vs. with” framing** of the problem it removes — lead with the pain, then the relief.
45
+ - **Cross-link at the seams** rather than re-explaining: show how the products meet in the reader's workflow.
46
+ - Maintain a **glossary** of shared terms and link to it instead of redefining terms per page. One term, one concept, everywhere.
47
+
48
+ ## Writing style
49
+
50
+ The project's voice is **direct, practical, and opinionated**. Write like an experienced colleague explaining something to a capable developer — confident but never condescending.
51
+
52
+ - **Active voice, present tense, second person.** “You append the event,” not “The event is appended.”
53
+ - **Lead with *why* before *how*.** A reader who understands the reasoning handles edge cases the docs do not cover.
54
+ - **Do not document the obvious.** If the API is self-explanatory, a complete code example is enough.
55
+ - Use headings, lists, tables, and code blocks — dense paragraphs lose readers.
56
+ - **Be honest about trade-offs.** A “when this is the wrong fit” section builds more trust than omitting the limits.
57
+ - Focus on public APIs and behavior — never internal implementation or third-party libraries.
58
+
59
+ ## Diagrams
60
+
61
+ - Use [Mermaid](https://mermaid-js.github.io/mermaid/#/) for every non-trivial concept — architecture, event and command flow, state transitions, projection and reactor pipelines. A concept page without a diagram is usually incomplete.
62
+
63
+ ## Code examples
64
+
65
+ - Prefer `record` types for events, commands, and read models — match the codebase.
66
+ - Use argument-free `[EventType]` for new events. A new generation or an explicit legacy identifier is valid only when documenting evolution of an existing stored-event contract.
67
+ - Every example must be **complete and correct** — no pseudo-code, no `// ...` elisions that leave the reader guessing.
68
+ - **Short illustrative snippets** may be purpose-built. **Longer or real samples must be embedded from compiled, tested source** when snippet tooling is available, so they cannot drift as APIs change. Never paste untested code, and never substitute a bare “see the repository” link for showing the code.
69
+ - Where a feature spans products or languages, show both sides when both matter. Keep causal explanations sequential; use tabs only for alternatives.
70
+
71
+ ## Links
72
+
73
+ - **Link text must describe the destination.** Write `[Event types](...)`, never `[see documentation](...)`, `[here](...)`, or `[click here](...)`. Non-descriptive link text is a defect.
74
+ - Use relative links for internal product-source references. Verify every link resolves — broken links and links to non-existent folders fail review.
75
+
76
+ ## What every product's docs must have
77
+
78
+ - A front-door **index** with a one-sentence definition and a “start here” link.
79
+ - A **“Why <product>”** explanation page covering the problem it solves and when *not* to use it.
80
+ - A canonical **getting started** with a visible payoff.
81
+ - A **threaded tutorial**.
82
+ - A **concepts/glossary** page and an **architecture diagram**.
83
+ - A **troubleshooting/FAQ** page.
84
+ - An **`llms.txt`** and **`llms-full.txt`** output so AI assistants can ground answers in the docs.
85
+
86
+ ## File rules
87
+
88
+ - Follow [Documentation Structure and Formatting](./documentation-structure-and-formatting.md) for frontmatter, landing pages, `toc.yml`, Markdown/MDX, links, and rendering.
89
+ - End every Markdown file with a single trailing newline.
90
+ - Run the owning repository's local documentation gate when present; use `cd ../Documentation/web && npm run check` for full-fidelity site verification when the sibling checkout is available.
@@ -0,0 +1,69 @@
1
+ ---
2
+ applyTo: "**/Documentation/**/*.{md,mdx}"
3
+ paths:
4
+ - "**/Documentation/**/*.md"
5
+ - "**/Documentation/**/*.mdx"
6
+ ---
7
+
8
+ # Editing Cratis documentation
9
+
10
+ Cratis documentation is split across product repositories and aggregated by the sibling `Documentation` repository. Find the authored source before editing; synchronized product copies under `Documentation/web/src/content/docs/` are disposable build output.
11
+
12
+ ## Find the source of truth
13
+
14
+ Common routes map as follows:
15
+
16
+ | Public route | Authored source |
17
+ |---|---|
18
+ | `/chronicle/**` | `Chronicle/Documentation/**` |
19
+ | `/arc/**` | `Arc/Documentation/**` |
20
+ | `/components/**` | `Components/Documentation/**` |
21
+ | `/chronicle-mcp/**`, `/authproxy/**`, `/cli/**`, `/fundamentals/**`, `/screenplay/**`, `/prologue/**`, `/prompter/**`, and other product routes | The product or family-source repository selected by `PRODUCTS` |
22
+ | `/contributing/**` | The organization `.github` repository (legacy fallback: `GitHubLanding`) |
23
+ | Site-level routes such as `/`, `/why-cratis`, `/cratis-stack`, `/glossary`, `/ai/**`, and `/compare-event-sourcing-*` | `Documentation/web/src/content/docs/**` |
24
+
25
+ The definitive source map is `PRODUCTS` and its optional `familySources` in `Documentation/web/scripts/sync-content.mjs`. The site prefers sibling checkouts and falls back to configured submodules. Do not hard-code a shorter product list when the script can answer ownership.
26
+
27
+ Never edit a synchronized subtree under `Documentation/web/src/content/docs/`. Each `PRODUCTS[].key` is regenerated there even when Git state or `.gitignore` makes a particular directory look hand-authored. Site-level files that are not populated from `PRODUCTS` are authored directly in the Documentation repository. Check `PRODUCTS`, source paths, and the site configuration when ownership is unclear.
28
+
29
+ ## Edit and verify
30
+
31
+ From the owning repository:
32
+
33
+ 1. Edit the authored `.md` or `.mdx` file and preserve its existing frontmatter unless the task deliberately changes it.
34
+ 2. Run that repository's local documentation gate when present, commonly `./Documentation/verify-markdown.sh`.
35
+ 3. For full rendering, run the site from the sibling checkout:
36
+
37
+ ```bash
38
+ cd ../Documentation/web
39
+ npm run check
40
+ ```
41
+
42
+ 4. Preview with `npm run dev` from that same `../Documentation/web` directory and inspect visual changes in light and dark.
43
+
44
+ The local gate validates authored content without requiring every sibling product. The full site check synchronizes every available product and can expose unrelated sibling or optional-tool failures; diagnose and report those separately. Report which checks actually ran when local prose, Markdown, or external-link tools skip because their executables are absent.
45
+
46
+ Restart `npm run dev` after a build/check. The build re-sync can degrade a running dev server, producing 500s or missing table rendering. If a change still appears stale, clear `web/.astro` and `web/node_modules/.astro`, restart, and recheck before blaming the source.
47
+
48
+ ## Add, move, rename, or delete a page
49
+
50
+ - Product navigation comes from its `toc.yml`; site-level navigation comes from `astro.config.mjs`.
51
+ - Product navigation buckets are defined per product in `PRODUCTS[].buckets`. Read the actual names and section lists before changing them.
52
+ - Keep exactly one landing for a route. A sibling `<folder>.md[x]` collides with `<folder>/index.md[x]`; a legacy `.md` collision can move the directory index to `/overview/`, while other duplicate landing shapes can fail the build.
53
+ - Update inbound links and `toc.yml` together. For a published route change, inspect the Documentation site's redirect mechanism rather than assuming a source-file move preserves old URLs.
54
+ - Watch sync output for dropped toc entries and verify the built sidebar. External, `../`, and `/api/` toc targets are intentionally omitted; single-child groups collapse.
55
+
56
+ ## Links
57
+
58
+ - Product source links to files keep the real `.md` or `.mdx` extension. The converter removes either extension for the public route.
59
+ - Directory links end in `/`.
60
+ - Site-level MDX and cross-product links use clean root-relative public routes such as `/arc/backend/commands/`.
61
+ - Slugification removes punctuation from path segments (`react.mvvm` becomes `reactmvvm`), so verify hand-authored site-absolute paths against the build.
62
+
63
+ ## Content and rendering
64
+
65
+ - Match the page's Diátaxis type and the tour voice in [Writing Cratis Documentation](./writing-cratis-docs.md).
66
+ - Verify framework APIs against source using [Writing Correct Code Examples](./writing-correct-examples.md).
67
+ - Follow [Documentation Structure and Formatting](./documentation-structure-and-formatting.md) as the single authority for frontmatter, Markdown/MDX boundaries, asides, components, navigation behavior, and gates.
68
+
69
+ Commit in the repository that owns the authored source. Touch the Documentation repository only when the task deliberately changes site-level content, navigation composition, components, styling, redirects, or build behavior.
@@ -0,0 +1,235 @@
1
+ ---
2
+ applyTo: "**/*.cs"
3
+ paths:
4
+ - "**/*.cs"
5
+ profile: application
6
+ ---
7
+
8
+ # Entity Framework Core Instructions
9
+
10
+ > **⚠️ APPLIES ONLY TO PROJECTS USING ENTITY FRAMEWORK CORE**
11
+ > If your project does not reference `Microsoft.EntityFrameworkCore` or any EF Core packages, **ignore this entire file**. These rules are irrelevant outside of EF Core contexts.
12
+
13
+ ## Project Structure
14
+
15
+ Responsibilities are split across three projects:
16
+
17
+ | Project | Responsibility |
18
+ |---------|----------------|
19
+ | `Database` | Migrations only – no entities, no DbContexts |
20
+ | `Core` | Entities and feature DbContexts (co-located with features) |
21
+ | `Infrastructure` | DbContext registration, migration runner, cross-cutting EF setup |
22
+
23
+ **Critical dependency rule**: `Database` must NEVER import from `Core`. Migrations reference only `WellKnownTables` constants (strings) and EF migration types. The dependency chain is:
24
+
25
+ ```
26
+ Core → Infrastructure → Database
27
+ ```
28
+
29
+ ## DbContext Base Types
30
+
31
+ Always use the Cratis Arc base types — never inherit directly from `DbContext`:
32
+
33
+ - **`ReadOnlyDbContext`** — for all read model / projection contexts (the vast majority)
34
+ - **`BaseDbContext`** — only for writable contexts that own state (e.g. device state, infrastructure state)
35
+
36
+ ```csharp
37
+ // ✅ Read model context
38
+ public class StartupPhaseDbContext(DbContextOptions<StartupPhaseDbContext> options)
39
+ : ReadOnlyDbContext(options)
40
+ {
41
+ public DbSet<StartupPhase> StartupPhases => Set<StartupPhase>();
42
+ public DbSet<PersonnelAssignment> PersonnelAssignments => Set<PersonnelAssignment>();
43
+ }
44
+
45
+ // ✅ Writable (state-owning) context
46
+ public class DeviceStateDbContext(DbContextOptions<DeviceStateDbContext> options)
47
+ : BaseDbContext(options)
48
+ {
49
+ public DbSet<DeviceState> DeviceStates => Set<DeviceState>();
50
+ }
51
+ ```
52
+
53
+ Use the primary constructor pattern. Expose `DbSet<T>` as expression-bodied properties using `Set<T>()`.
54
+
55
+ ## Feature Contexts — Not God Contexts
56
+
57
+ Create one focused DbContext per feature or tightly-related feature group. Never aggregate unrelated entities into a single context.
58
+
59
+ ```csharp
60
+ // ❌ God context
61
+ public class AppDbContext : DbContext
62
+ {
63
+ public DbSet<Mission> Missions { get; set; }
64
+ public DbSet<User> Users { get; set; }
65
+ public DbSet<Station> Stations { get; set; }
66
+ // ... many more
67
+ }
68
+
69
+ // ✅ Focused feature context
70
+ public class StartupPhaseDbContext(DbContextOptions<StartupPhaseDbContext> options)
71
+ : ReadOnlyDbContext(options)
72
+ {
73
+ public DbSet<StartupPhase> StartupPhases => Set<StartupPhase>();
74
+ public DbSet<PersonnelAssignment> PersonnelAssignments => Set<PersonnelAssignment>();
75
+ }
76
+ ```
77
+
78
+ Co-locate the DbContext file with its feature:
79
+
80
+ ```
81
+ Missions/Ongoing/StartupPhase/
82
+ ├── StartupPhase.cs
83
+ ├── StartupPhaseDbContext.cs
84
+ └── ...
85
+ ```
86
+
87
+ ## State Mutation — The Golden Rule
88
+
89
+ > **Never mutate state directly through a DbContext.**
90
+
91
+ All state changes must flow through events and Chronicle projections. Direct writes bypass the audit trail and event log.
92
+
93
+ ```csharp
94
+ // ❌ Direct mutation — forbidden
95
+ dbContext.StartupPhases.Add(new StartupPhase(...));
96
+ await dbContext.SaveChangesAsync();
97
+
98
+ // ✅ Correct: emit an event, let the projection handle writes
99
+ [Command]
100
+ public record UpdateStartupPhase(MissionId MissionId, ...) { ... }
101
+ ```
102
+
103
+ Only infrastructure projection code, the Chronicle event engine, and reference data sync may write through DbContexts.
104
+
105
+ ## Registration
106
+
107
+ Use the Cratis Arc `Cratis.Arc.EntityFrameworkCore` extension methods:
108
+
109
+ ```csharp
110
+ // Register a single writable DbContext
111
+ services.AddDbContextWithConnectionString<DeviceStateDbContext>(connectionString, optionalConfigure);
112
+
113
+ // Auto-discover and register ALL ReadOnlyDbContext subtypes from given assemblies
114
+ services.AddReadModelDbContextsWithConnectionStringFromAssemblies(
115
+ connectionString,
116
+ configureOptions,
117
+ [Assembly.GetExecutingAssembly()]);
118
+ ```
119
+
120
+ Configure the database provider using `UseDatabaseFromConnectionString`, which auto-detects PostgreSQL vs SQLite from the connection string:
121
+
122
+ ```csharp
123
+ options.UseDatabaseFromConnectionString(connectionString);
124
+ ```
125
+
126
+ Centralize all DbContext setup in a single `AddApplicationDbContexts` extension method per layer.
127
+
128
+ ## Multiple Database Support
129
+
130
+ The application supports both PostgreSQL (ASP.NET mode) and SQLite (MAUI mode) from the same code. The provider is selected at runtime via the connection string — `UseDatabaseFromConnectionString` handles the detection.
131
+
132
+ Never hardcode a provider (e.g. `UseSqlite` or `UseNpgsql`) in application code. Always use `UseDatabaseFromConnectionString`.
133
+
134
+ ## Migrations
135
+
136
+ Migrations live exclusively in the **`Database`** project, never in `Core` or `Infrastructure`.
137
+
138
+ ### Organization
139
+
140
+ Each entity category has its own folder with versioned migration files:
141
+
142
+ ```
143
+ Database/
144
+ ├── Missions/
145
+ │ ├── v1_0_0.cs
146
+ │ └── v1_1_0.cs
147
+ ├── Users/
148
+ │ └── v1_0_0.cs
149
+ └── WellKnownTables.cs
150
+ ```
151
+
152
+ ### Naming
153
+
154
+ Version files using the pattern `v{major}_{minor}_{patch}.cs` and place them inside a namespace matching their folder:
155
+
156
+ ```csharp
157
+ namespace Database.Missions;
158
+
159
+ public class v1_0_0 : Migration
160
+ {
161
+ protected override void Up(MigrationBuilder migrationBuilder) { ... }
162
+ protected override void Down(MigrationBuilder migrationBuilder) { ... }
163
+ }
164
+ ```
165
+
166
+ The migration ID is composed as `{folder}_{ClassName}` (e.g. `Missions_v1_0_0`).
167
+
168
+ ### Cross-Database Column Helpers
169
+
170
+ Always use the Cratis Arc `MigrationBuilder` extension helpers to define columns. These abstract over PostgreSQL and SQLite type differences:
171
+
172
+ | Helper | Use for |
173
+ |--------|---------|
174
+ | `table.StringColumn(migrationBuilder)` | Text / varchar columns |
175
+ | `table.GuidColumn(migrationBuilder)` | UUID / GUID columns |
176
+ | `table.NumberColumn<T>(migrationBuilder)` | Integer, long, or numeric columns |
177
+ | `table.DateTimeOffsetColumn(migrationBuilder)` | Timestamps with timezone |
178
+
179
+ Never use raw EF `table.Column<string>()` etc. — the helpers ensure cross-database compatibility.
180
+
181
+ ```csharp
182
+ // ✅ Cross-database migration
183
+ migrationBuilder.CreateTable(
184
+ name: WellKnownTables.Missions,
185
+ columns: table => new
186
+ {
187
+ Id = table.StringColumn(migrationBuilder, nullable: false),
188
+ Title = table.StringColumn(migrationBuilder, maxLength: 200, nullable: false),
189
+ ResourceId = table.NumberColumn<int>(migrationBuilder, nullable: true),
190
+ DispatchTime = table.DateTimeOffsetColumn(migrationBuilder),
191
+ UrgencyId = table.GuidColumn(migrationBuilder)
192
+ },
193
+ constraints: table =>
194
+ {
195
+ table.PrimaryKey("PK_Missions", x => x.Id);
196
+ table.ForeignKey("FK_Missions_Urgency", x => x.UrgencyId,
197
+ WellKnownTables.MissionUrgencies, "Id", onDelete: ReferentialAction.SetNull);
198
+ });
199
+ ```
200
+
201
+ ### Table Names — WellKnownTables
202
+
203
+ Always reference table names from `WellKnownTables` constants. Never use magic strings directly in migrations.
204
+
205
+ ```csharp
206
+ // ❌ Magic string
207
+ migrationBuilder.CreateTable(name: "Missions", ...);
208
+
209
+ // ✅ Constant
210
+ migrationBuilder.CreateTable(name: WellKnownTables.Missions, ...);
211
+ ```
212
+
213
+ Add new table names to `Database/WellKnownTables.cs` before writing the migration.
214
+
215
+ ### Applying Migrations
216
+
217
+ Migrations are applied via a custom runner from the `Database` project (not `dotnet ef database update`):
218
+
219
+ ```csharp
220
+ // ASP.NET mode
221
+ await app.ApplyAllMigrations(connectionString);
222
+
223
+ // MAUI / IServiceProvider mode
224
+ await services.ApplyAllMigrations(connectionString);
225
+ ```
226
+
227
+ The runner discovers all `Migration` subclasses from the `Database` assembly, checks the EF history table, and applies pending migrations in version order within a transaction. Both PostgreSQL and SQLite are supported through the same runner.
228
+
229
+ ## Auto-Discovery
230
+
231
+ The Cratis Arc `IImplementationsOf<T>` mechanism discovers DbContext types at runtime:
232
+
233
+ - `IImplementationsOf<BaseDbContext>` — all `DbContext` subtypes across all loaded assemblies.
234
+ - `DiscoverAndFilterDbContextTypes<ReadOnlyDbContext>(assemblies)` — discovers the read-model contexts; the registration helpers (`AddReadModelDbContextsWithConnectionStringFromAssemblies` / `AddReadModelDbContextsFromAssemblies`) build on it.
235
+ - To isolate **writable** contexts, filter the discovered set on assignability — `types.Where(t => !typeof(ReadOnlyDbContext).IsAssignableFrom(t))` — rather than a dedicated extension.
@@ -0,0 +1,44 @@
1
+ ---
2
+ applyTo: "**/for_*/**/*.cs, **/when_*/**/*.cs"
3
+ paths:
4
+ - "**/for_*/**/*.cs"
5
+ - "**/when_*/**/*.cs"
6
+ profile: application
7
+ ---
8
+
9
+ # Entity Framework Core Specs
10
+
11
+ > **⚠️ APPLIES ONLY TO PROJECTS USING ENTITY FRAMEWORK CORE**
12
+ > If your project does not reference `Microsoft.EntityFrameworkCore` or any EF Core packages, **ignore this entire file**. These rules are irrelevant outside of EF Core contexts.
13
+
14
+ EF Core specs verify database interaction logic — migrations, queries, and error handling. They use SQLite in-memory databases, which are fast, isolated, and disposable. This keeps specs independent of any real database server.
15
+
16
+ These specs are for code that interacts directly with `DbContext`. For event-sourcing integration specs (testing commands against Chronicle), use the Chronicle integration spec pattern in [specs.scenarios.csharp.md](./specs.scenarios.csharp.md) instead.
17
+
18
+ ## Database Setup
19
+
20
+ - Use SQLite in-memory database for all `DbContext` specs — it's fast and each spec gets a clean database.
21
+ - Configure and dispose the in-memory database properly to avoid state leakage between tests. Each spec run should start with a fresh schema.
22
+
23
+ ## Mocking DbContext
24
+
25
+ - `SaveChanges()` and `SaveChangesAsync()` are virtual — mock with NSubstitute.
26
+ - `DbSet<T>` methods are virtual — mock as needed.
27
+ - Pass options when substituting: `Substitute.For<YourDbContext>(options)`.
28
+
29
+ ```csharp
30
+ var options = new DbContextOptionsBuilder<YourDbContext>()
31
+ .UseSqlite("DataSource=:memory:")
32
+ .Options;
33
+
34
+ var context = Substitute.For<YourDbContext>(options);
35
+ ```
36
+
37
+ ## Simulating Failures
38
+
39
+ Mock `SaveChanges` / `SaveChangesAsync` to throw exceptions for testing error handling and recovery:
40
+
41
+ ```csharp
42
+ context.SaveChangesAsync(Arg.Any<CancellationToken>())
43
+ .Throws(new DbUpdateException("Simulated failure"));
44
+ ```
@@ -0,0 +1,33 @@
1
+ ---
2
+ applyTo: "**/*"
3
+ ---
4
+
5
+ # Exit codes and wrappers
6
+
7
+ An exit code is a verdict, and a wrapper that loses it turns a red run green. Every line
8
+ is tagged **[contract]** (binding) or **[convention]** (the house default) per the Three
9
+ Levels of Authority in [`general.md`](./general.md).
10
+
11
+ - **[contract] Three codes, three meanings.** `0` ran clean, `1` found defects, `2` could
12
+ not run. A tool that cannot distinguish "found nothing" from "never looked" has no
13
+ usable verdict.
14
+ - **[contract] `2` is never reported as a pass.** Could-not-run is an unknown, and
15
+ unknown is not pass; see [`verification-discipline.md`](./verification-discipline.md).
16
+ - **[contract] A wrapper's own success is not the child's verdict.** A script that runs a
17
+ checker and then exits `0` because *the script* finished has thrown the result away.
18
+ Propagate the child's status.
19
+ - **[contract] Pipelines and loops lose exit codes by default.** Use `set -euo pipefail`,
20
+ check `PIPESTATUS` where a pipeline's left side matters, and accumulate a failure flag
21
+ inside a loop rather than relying on the last iteration.
22
+ - **[contract] Green prints counts.** A clean run says how many subjects it examined. A
23
+ bare "OK" cannot be distinguished from a run over an empty set; see
24
+ [`guards-and-fuses.md`](./guards-and-fuses.md).
25
+ - **[contract] `--self-test` plants defects.** A checker ships a self-test that seeds
26
+ known violations and fails if it does not find every one of them. That is the only way
27
+ to know the checker still detects anything.
28
+ - **[contract] Never swallow output to make a gate quiet.** Redirecting stderr, adding
29
+ `|| true`, or catching and ignoring is a decision to stop checking. Say so out loud or
30
+ do not do it.
31
+ - **[convention] Name the subject in the failure line.** The path, the id, the rule — a
32
+ failure a reader cannot locate costs more than it saves.
33
+ - **[convention] Keep the wrapper thin.** Logic in a wrapper is logic no test covers.