@cratis/pi 0.0.1 → 2.0.1
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.
- package/LICENSE +21 -0
- package/README.md +18 -37
- package/package/corpus/agents/backend-developer.md +125 -0
- package/package/corpus/agents/code-reviewer.md +165 -0
- package/package/corpus/agents/coordinator.md +163 -0
- package/package/corpus/agents/frontend-developer.md +246 -0
- package/package/corpus/agents/orchestrator.md +196 -0
- package/package/corpus/agents/performance-reviewer.md +109 -0
- package/package/corpus/agents/planner.md +145 -0
- package/package/corpus/agents/repository-investigation-reviewer.md +45 -0
- package/package/corpus/agents/repository-investigator.md +50 -0
- package/package/corpus/agents/security-reviewer.md +118 -0
- package/package/corpus/agents/slice-implementer.md +59 -0
- package/package/corpus/agents/spec-writer.md +149 -0
- package/package/corpus/harnesses/pi/extensions/cratis-hooks/index.ts +213 -0
- package/package/corpus/harnesses/pi/extensions/cratis-rules/index.ts +27 -0
- package/package/corpus/harnesses/pi/extensions/package.json +4 -0
- package/package/corpus/harnesses/pi/extensions/subagent/agents.ts +167 -0
- package/package/corpus/harnesses/pi/extensions/subagent/index.ts +352 -0
- package/package/corpus/hooks/README.md +434 -0
- package/package/corpus/hooks/agent-stop.md +49 -0
- package/package/corpus/hooks/pre-commit.md +47 -0
- package/package/corpus/hooks/scripts/cratis-guard-writes.sh +87 -0
- package/package/corpus/hooks/scripts/cratis-nuget-pins.txt +11 -0
- package/package/corpus/hooks/scripts/cratis-pattern-scan.sh +197 -0
- package/package/corpus/hooks/scripts/cratis-patterns.json +84 -0
- package/package/corpus/hooks/scripts/cratis-quality-gate.sh +219 -0
- package/package/corpus/hooks/scripts/hook-lib.sh +152 -0
- package/package/corpus/hooks/scripts/quality-gates.json +261 -0
- package/package/corpus/hooks/scripts/type-references-allowlist.txt +71 -0
- package/package/corpus/hooks/scripts/validate-package-imports.sh +166 -0
- package/package/corpus/hooks/scripts/validate-package-subpaths.sh +120 -0
- package/package/corpus/hooks/scripts/validate-type-references.sh +308 -0
- package/package/corpus/hooks/settings.template.json +40 -0
- package/package/corpus/prompts/add-business-rule.prompt.md +22 -0
- package/package/corpus/prompts/add-concept.prompt.md +17 -0
- package/package/corpus/prompts/add-ef-migration.prompt.md +24 -0
- package/package/corpus/prompts/add-projection.prompt.md +20 -0
- package/package/corpus/prompts/add-reactor.prompt.md +22 -0
- package/package/corpus/prompts/add-reducer.prompt.md +20 -0
- package/package/corpus/prompts/audit-hooks.prompt.md +15 -0
- package/package/corpus/prompts/check-doc-drift.prompt.md +21 -0
- package/package/corpus/prompts/code-review.prompt.md +9 -0
- package/package/corpus/prompts/new-feature.prompt.md +9 -0
- package/package/corpus/prompts/new-vertical-slice.prompt.md +18 -0
- package/package/corpus/prompts/review-pr.prompt.md +35 -0
- package/package/corpus/prompts/review-skill.prompt.md +16 -0
- package/package/corpus/prompts/scaffold-feature.prompt.md +16 -0
- package/package/corpus/prompts/ship-changes.prompt.md +20 -0
- package/package/corpus/prompts/verify-ai-setup.prompt.md +19 -0
- package/package/corpus/prompts/write-documentation.prompt.md +21 -0
- package/package/corpus/prompts/write-specs.prompt.md +22 -0
- package/package/corpus/rules/capability-is-not-authority.md +31 -0
- package/package/corpus/rules/code-quality.csharp.md +91 -0
- package/package/corpus/rules/code-quality.md +82 -0
- package/package/corpus/rules/code-quality.typescript.md +89 -0
- package/package/corpus/rules/components.md +207 -0
- package/package/corpus/rules/concepts.md +115 -0
- package/package/corpus/rules/csharp.md +269 -0
- package/package/corpus/rules/dialogs.md +264 -0
- package/package/corpus/rules/documentation-structure-and-formatting.md +148 -0
- package/package/corpus/rules/documentation.md +90 -0
- package/package/corpus/rules/editing-cratis-docs.md +69 -0
- package/package/corpus/rules/efcore.md +235 -0
- package/package/corpus/rules/efcore.specs.md +44 -0
- package/package/corpus/rules/exit-codes-and-wrappers.md +33 -0
- package/package/corpus/rules/framework.md +52 -0
- package/package/corpus/rules/frontend-quality.md +59 -0
- package/package/corpus/rules/frontend-testing.md +126 -0
- package/package/corpus/rules/general.md +305 -0
- package/package/corpus/rules/git-commits.md +138 -0
- package/package/corpus/rules/github-actions.md +92 -0
- package/package/corpus/rules/glossary.md +61 -0
- package/package/corpus/rules/guards-and-fuses.md +45 -0
- package/package/corpus/rules/local-work-artifacts.md +33 -0
- package/package/corpus/rules/managing-ai-rules.md +40 -0
- package/package/corpus/rules/orleans.md +50 -0
- package/package/corpus/rules/pull-requests.md +78 -0
- package/package/corpus/rules/react.md +195 -0
- package/package/corpus/rules/reactors.md +238 -0
- package/package/corpus/rules/rtk.md +37 -0
- package/package/corpus/rules/specs.csharp.md +139 -0
- package/package/corpus/rules/specs.md +132 -0
- package/package/corpus/rules/specs.scenarios.csharp.md +172 -0
- package/package/corpus/rules/specs.typescript.md +139 -0
- package/package/corpus/rules/storybook.md +84 -0
- package/package/corpus/rules/terminal-commands.md +19 -0
- package/package/corpus/rules/typescript.md +149 -0
- package/package/corpus/rules/verification-discipline.md +21 -0
- package/package/corpus/rules/vertical-slices.md +338 -0
- package/package/corpus/rules/web-fetching.md +11 -0
- package/package/corpus/rules/writing-correct-examples.md +35 -0
- package/package/corpus/rules/writing-cratis-docs.md +70 -0
- package/package/corpus/skills/cratis-engineering-csharp-conventions/LICENSE +2 -0
- package/package/corpus/skills/cratis-engineering-csharp-conventions/SKILL.md +131 -0
- package/package/corpus/skills/cratis-engineering-csharp-conventions/references/code-style.md +187 -0
- package/package/corpus/skills/cratis-engineering-csharp-conventions/references/domain-philosophy.md +91 -0
- package/package/corpus/skills/cratis-engineering-csharp-conventions/references/exceptions-logging-and-di.md +223 -0
- package/package/corpus/skills/cratis-engineering-decision-record/LICENSE +2 -0
- package/package/corpus/skills/cratis-engineering-decision-record/SKILL.md +133 -0
- package/package/corpus/skills/cratis-engineering-decision-record/references/record-format.md +107 -0
- package/package/corpus/skills/cratis-engineering-docs-authoring/LICENSE +2 -0
- package/package/corpus/skills/cratis-engineering-docs-authoring/SKILL.md +86 -0
- package/package/corpus/skills/cratis-engineering-docs-authoring/references/site-format.md +46 -0
- package/package/corpus/skills/cratis-engineering-effect-boundaries/LICENSE +2 -0
- package/package/corpus/skills/cratis-engineering-effect-boundaries/SKILL.md +130 -0
- package/package/corpus/skills/cratis-engineering-effect-boundaries/references/failure-archetypes.md +133 -0
- package/package/corpus/skills/cratis-fundamentals-concept/verification.json +8 -0
- package/package/profile-catalog.json +821 -0
- package/package.json +35 -13
- package/src/index.ts +80 -0
- /package/{skills → package/corpus/skills}/cratis-application-react-specifications/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-application-react-specifications/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-application-slice-specifications/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-application-slice-specifications/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-authentication-authorization-and-identity/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-authentication-authorization-and-identity/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-authentication-authorization-and-identity/references/authentication.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-authentication-authorization-and-identity/references/authorization.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-authentication-authorization-and-identity/references/frontend.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-authentication-authorization-and-identity/references/local-development.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-authentication-authorization-and-identity/references/tenancy.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-command/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-command/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-command/references/command-result.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-command/references/handler-shapes.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-command/references/proxy-generation.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-command/references/read-model-injection.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-command-execution/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-command-execution/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-command-validation/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-command-validation/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-ef-core-migration/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-ef-core-migration/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-observable-query-http/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-observable-query-http/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-query-paging/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-query-paging/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-react-page/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-react-page/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-react-page/references/data-page.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-react-page/references/data-tables.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-react-page/references/dialogs.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-react-page/references/mvvm.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-react-page/references/queries-and-commands.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-cli-operations/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-cli-operations/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-client-dotnet/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-client-dotnet/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-client-elixir/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-client-elixir/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-client-kotlin/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-client-kotlin/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-client-typescript/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-client-typescript/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-compliance/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-compliance/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-event-constraints/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-event-constraints/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-event-modeling/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-event-modeling/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-event-specifications/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-event-specifications/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-event-type-migration/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-event-type-migration/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-mcp-inspection/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-mcp-inspection/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-mcp-inspection/references/blocked-tools.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-mcp-inspection/references/observational-tools.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-multi-tenancy/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-multi-tenancy/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-projection/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-projection/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-projection/references/fluent-builder.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-projection/references/model-bound-attributes.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-reactor/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-reactor/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-read-model/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-read-model/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-read-model/references/queries.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-read-model-specifications/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-read-model-specifications/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-reducer/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-reducer/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-web-workbench/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-web-workbench/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-cli-terminal-workbench/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-cli-terminal-workbench/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-code-review/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-code-review/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-components-accessibility/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-components-accessibility/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-components-schema-editor/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-components-schema-editor/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-components-stepper-command-dialog/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-components-stepper-command-dialog/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-components-styling/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-components-styling/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-components-toolbar/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-components-toolbar/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-documentation-writing/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-documentation-writing/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-event-model-diagram/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-event-model-diagram/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-fundamentals-concept/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-fundamentals-concept/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-fundamentals-type-discovery/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-fundamentals-type-discovery/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-governed-release-methodology/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-governed-release-methodology/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-lens-browser-extension/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-lens-browser-extension/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-performance-review/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-performance-review/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-screenplay-model-authoring/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-screenplay-model-authoring/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-security-review/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-security-review/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-specification-by-example/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-specification-by-example/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-specifications-csharp/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-specifications-csharp/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-specifications-csharp/references/application-scenarios.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-specifications-csharp/references/csharp-patterns.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-specifications-csharp/references/integration-specs.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-specifications-typescript/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-specifications-typescript/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-specifications-typescript/references/typescript-patterns.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-stage-rendering-and-sandbox/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-stage-rendering-and-sandbox/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-studio-mcp-safety-guidance/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-studio-mcp-safety-guidance/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-studio-mcp-safety-guidance/references/blocked-tools.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-studio-mcp-safety-guidance/references/observational-tools.md +0 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "**/Documentation/**/*.{md,mdx}"
|
|
3
|
+
paths:
|
|
4
|
+
- "**/Documentation/**/*.md"
|
|
5
|
+
- "**/Documentation/**/*.mdx"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Writing Cratis documentation — tour voice and Starlight authoring
|
|
9
|
+
|
|
10
|
+
The Cratis docs must **take the reader on a tour, like a teacher** — the way [Marten](https://martendb.io), [Wolverine](https://wolverinefx.net), and [aspire.dev](https://aspire.dev) docs do — **not** state facts like a reference dump. The differentiator is pedagogical structure, not decoration. Match it.
|
|
11
|
+
|
|
12
|
+
## The bar
|
|
13
|
+
|
|
14
|
+
- **Pain → relief.** Open by naming the friction the reader feels, then reveal the feature as the relief.
|
|
15
|
+
- **Why before how.** A reader who understands the reasoning handles edge cases the docs do not cover.
|
|
16
|
+
- **Active voice, present tense, second person.** “You append the event,” not “the event is appended.”
|
|
17
|
+
- **Be honest about limits.** A “when this is the wrong fit” section builds more trust than omitting the limits.
|
|
18
|
+
|
|
19
|
+
## One page equals one Diátaxis type
|
|
20
|
+
|
|
21
|
+
| Type | Reader is… | Reads like |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| **Tutorial** | learning by doing | a guided lesson — each step produces a visible result |
|
|
24
|
+
| **How-to** | solving a specific problem | a recipe — assume competence, no teaching |
|
|
25
|
+
| **Explanation** | trying to understand | a discussion — concepts, trade-offs, *why*, a diagram |
|
|
26
|
+
| **Reference** | looking something up | a dictionary — exhaustive, terse, tables/signatures |
|
|
27
|
+
|
|
28
|
+
Never mix types. A tutorial padded with reference detail overwhelms; a how-to interrupted by concept digressions stops being a recipe. Diátaxis type does not imply a universal navigation bucket; bucket names are product-specific.
|
|
29
|
+
|
|
30
|
+
## The tour-voice checklist
|
|
31
|
+
|
|
32
|
+
Apply this checklist to tutorials, getting-started pages, and explanations:
|
|
33
|
+
|
|
34
|
+
1. **Open with a concrete scenario**, not a definition of the tool.
|
|
35
|
+
2. **Name the friction first**, then the feature as its relief.
|
|
36
|
+
3. **Use chronological verbs** such as define → append → project → query.
|
|
37
|
+
4. **After every code block, explain the invisible** — what happens under the hood and why it matters.
|
|
38
|
+
5. **Recap before pivoting** to the next concept.
|
|
39
|
+
6. **Anticipate the reader's doubt** with a meaningful aside.
|
|
40
|
+
7. **Show the result** — output, a resulting model, or another visible success signal.
|
|
41
|
+
8. **Organize by workflow**, not alphabetically.
|
|
42
|
+
9. **End each substantial section with the natural next step** when one exists.
|
|
43
|
+
|
|
44
|
+
Read a current, well-reviewed tutorial in the product or a closely related product before writing; do not assume one product's domain vocabulary fits every other product.
|
|
45
|
+
|
|
46
|
+
## Use presentation to support the tour
|
|
47
|
+
|
|
48
|
+
Choose the simplest authoring surface that preserves the reading flow. Use steps for real procedures, tabs for genuine alternatives, asides for meaningful context or risk, and diagrams for non-trivial flows. Do not turn sequential cause-and-effect examples into tabs merely because they use different languages; hiding one side can make the explanation harder to follow.
|
|
49
|
+
|
|
50
|
+
Full-stack type safety is a differentiator, so show both the backend contract and generated frontend shape when both matter. Use `FullStackTabs` only when each pane remains understandable independently.
|
|
51
|
+
|
|
52
|
+
The raw Markdown mirror behind page actions such as “Copy Markdown” comes from synchronized Markdown/MDX rather than rendered HTML. Converter rewrites and normalized frontmatter are present, but component imports and JSX remain visible. Prefer plain Markdown unless a component adds real teaching value.
|
|
53
|
+
|
|
54
|
+
The exact Markdown/MDX boundary, aside semantics, component contracts, import paths, and rendering checks live in [Documentation Structure and Formatting](./documentation-structure-and-formatting.md). Do not duplicate or infer that rendering API here.
|
|
55
|
+
|
|
56
|
+
## Two voices, connected products
|
|
57
|
+
|
|
58
|
+
- **Two voices per area:** the toured/educational layer and the terse, exhaustive reference. Narrative pages link *down* into the reference; the reference stays a dictionary.
|
|
59
|
+
- **Connect at the seams** rather than re-explaining. Show how neighboring products meet in the user's workflow and link to the glossary for shared terms.
|
|
60
|
+
- **Coming-from-X bridges** map new concepts to what the reader already knows without organizing the whole product around a competitor.
|
|
61
|
+
|
|
62
|
+
## Before you call a page done
|
|
63
|
+
|
|
64
|
+
- Verify every framework API in a code example against real source — see [Writing Correct Code Examples](./writing-correct-examples.md). Readers paste snippets verbatim.
|
|
65
|
+
- The owning repository's local documentation gate passes when one exists; when available, the sibling Documentation site's full check has zero hard lint errors and zero broken rendered links attributable to the change.
|
|
66
|
+
- For a visual page, screenshot it in light **and** dark — see the `qa-cratis-docs` skill.
|
|
67
|
+
|
|
68
|
+
Study the **aspire.dev** docs for strong Starlight information architecture and tour writing.
|
|
69
|
+
|
|
70
|
+
The edit/sync/verify loop and source ownership live in [Editing Cratis Documentation](./editing-cratis-docs.md).
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cratis-engineering-csharp-conventions
|
|
3
|
+
description: Apply the Cratis C# house conventions when writing or reviewing C# in a Cratis repository - formatting, naming, records and primary constructors, nullable handling, XML documentation, custom exceptions, structured logging, dependency injection, and service lifetimes. Use for any "how should this be written" C# style question; defer product API decisions and specification authoring to their focused workflows.
|
|
4
|
+
license: LICENSE
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Cratis C# engineering conventions
|
|
8
|
+
|
|
9
|
+
These are the house conventions Cratis maintainers apply across every
|
|
10
|
+
repository. They are **conventions**, not framework contracts: nothing here is
|
|
11
|
+
enforced by an analyzer unless this skill says so. Follow them for consistency;
|
|
12
|
+
do not claim the framework requires them.
|
|
13
|
+
|
|
14
|
+
## Route near misses
|
|
15
|
+
|
|
16
|
+
- The question is what a Cratis product API *does*: resolve it against the
|
|
17
|
+
owning product repository, not against this style guide.
|
|
18
|
+
- The subject is a specification file: the specification conventions own the
|
|
19
|
+
`Establish`/`Because`/`should_` pattern and the `for_`/`when_` hierarchy.
|
|
20
|
+
- The subject is TypeScript or React: this skill covers C# only.
|
|
21
|
+
- The subject is repository structure or documentation: those are separate
|
|
22
|
+
workflows.
|
|
23
|
+
|
|
24
|
+
## Quick reference
|
|
25
|
+
|
|
26
|
+
- Use current C# language features — records, primary constructors, pattern
|
|
27
|
+
matching, collection expressions.
|
|
28
|
+
- `var` over an explicit type; the right-hand side already names the type.
|
|
29
|
+
- File-scoped namespace declarations.
|
|
30
|
+
- `using` directives alphabetically sorted, single-line, unused ones removed.
|
|
31
|
+
- No regions. A file that needs them needs refactoring instead.
|
|
32
|
+
- No technical postfixes on type names: no `Impl`, `Service`, `Manager`,
|
|
33
|
+
`Handler`, `Base`, `Async`.
|
|
34
|
+
- No `Exception` suffix on exception types — `AuthorNotFound`, not
|
|
35
|
+
`AuthorNotFoundException`.
|
|
36
|
+
- Never throw a built-in exception type. Always define a domain exception.
|
|
37
|
+
- `record` for events, commands, read models, concepts, and DTOs.
|
|
38
|
+
- `is null` and `is not null` — never `== null` or `!= null`.
|
|
39
|
+
- Blank line before the opening `{` of every block.
|
|
40
|
+
- A final `return` sits on its own line.
|
|
41
|
+
- Private fields are `_camelCase`; interfaces take the `I` prefix.
|
|
42
|
+
- American English everywhere — initialize, behavior, color, serialize.
|
|
43
|
+
- Every file starts with the repository license header.
|
|
44
|
+
|
|
45
|
+
## Formatting
|
|
46
|
+
|
|
47
|
+
```csharp
|
|
48
|
+
// Copyright (c) Cratis. All rights reserved.
|
|
49
|
+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
50
|
+
|
|
51
|
+
namespace <RootNamespace>.<Feature>;
|
|
52
|
+
|
|
53
|
+
using <Namespace>.<First>;
|
|
54
|
+
using <Namespace>.<Second>;
|
|
55
|
+
|
|
56
|
+
// Blank line before the opening brace of every block
|
|
57
|
+
if (<condition>)
|
|
58
|
+
{
|
|
59
|
+
<statement>;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Expression-bodied form for simple members
|
|
63
|
+
public string <PropertyName> => $"{<First>} {<Second>}";
|
|
64
|
+
|
|
65
|
+
// The final return stands alone
|
|
66
|
+
public <ReturnType> <MethodName>()
|
|
67
|
+
{
|
|
68
|
+
var result = <expression>;
|
|
69
|
+
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Naming
|
|
75
|
+
|
|
76
|
+
| Artifact | Convention | Example |
|
|
77
|
+
| --- | --- | --- |
|
|
78
|
+
| Type, method, public member | PascalCase | `RegisterAuthor`, `AuthorId` |
|
|
79
|
+
| Private field | `_camelCase` | `_eventLog` |
|
|
80
|
+
| Local variable | camelCase | `authorId` |
|
|
81
|
+
| Interface | `I` prefix | `IEventLog` |
|
|
82
|
+
| Exception type | No `Exception` suffix | `AuthorNotFound` |
|
|
83
|
+
| Feature folder | Pluralized domain noun | `Authors/` |
|
|
84
|
+
| Concept file | The concept name | `AuthorId.cs` |
|
|
85
|
+
|
|
86
|
+
Avoid abbreviations unless they are universally known (`Id`, `Xml`, `Json`,
|
|
87
|
+
`Url`). Never add a prefix or postfix that names a technical role —
|
|
88
|
+
`Controller`, `ViewModel`, `Handler`, `Manager`, `Factory`, `Base`. Name after
|
|
89
|
+
the domain, not the pattern.
|
|
90
|
+
|
|
91
|
+
## Where the detail lives
|
|
92
|
+
|
|
93
|
+
| Topic | Reference |
|
|
94
|
+
| --- | --- |
|
|
95
|
+
| Records, primary constructors, `var`, collections, nullable, async, pattern matching, XML documentation | [code-style.md](references/code-style.md) |
|
|
96
|
+
| Custom exceptions, structured logging, dependency injection, service lifetimes, implementation discovery | [exceptions-logging-and-di.md](references/exceptions-logging-and-di.md) |
|
|
97
|
+
| CUPID, cohesion over layers, ubiquitous language, immutability | [domain-philosophy.md](references/domain-philosophy.md) |
|
|
98
|
+
|
|
99
|
+
Read the reference that covers the decision at hand rather than all three.
|
|
100
|
+
|
|
101
|
+
## The two rules most often got wrong
|
|
102
|
+
|
|
103
|
+
**`[Singleton]` is a narrow choice, not the default.** A singleton may not
|
|
104
|
+
depend on anything that belongs to a tenant, a user, or a request. Capturing a
|
|
105
|
+
scoped collaborator does not throw — it silently binds to the root scope's
|
|
106
|
+
default namespace forever and returns empty results. See
|
|
107
|
+
[exceptions-logging-and-di.md](references/exceptions-logging-and-di.md).
|
|
108
|
+
|
|
109
|
+
**Use `IInstancesOf<T>`, never `IEnumerable<T>`, to enumerate implementations of
|
|
110
|
+
an abstraction.** `IEnumerable<T>` only works when every implementation is
|
|
111
|
+
hand-registered, which defeats convention-based discovery.
|
|
112
|
+
|
|
113
|
+
## Verify
|
|
114
|
+
|
|
115
|
+
- Every file carries the repository license header and a file-scoped namespace.
|
|
116
|
+
- `using` directives are sorted, single-line, and free of unused entries.
|
|
117
|
+
- No regions, no technical postfixes, no `Exception` suffix.
|
|
118
|
+
- Every thrown exception is a domain type deriving from `Exception` with a
|
|
119
|
+
meaningful message and an XML `<exception>` or `<summary>` doc starting with
|
|
120
|
+
"The exception that is thrown when".
|
|
121
|
+
- No `catch` block is empty or silently swallowing.
|
|
122
|
+
- Null checks use `is null` / `is not null`, and no defensive check contradicts a
|
|
123
|
+
non-nullable annotation.
|
|
124
|
+
- Every public type, method, property, and operator carries multiline XML
|
|
125
|
+
documentation with `<param>` and `<returns>` where applicable.
|
|
126
|
+
- No `[Singleton]` holds tenant-, user-, or request-bound state.
|
|
127
|
+
- No `services.Add*<TInterface, TImplementation>()` registers a type that exists
|
|
128
|
+
to be discovered by convention.
|
|
129
|
+
- Text is American English.
|
|
130
|
+
- The solution builds with zero warnings and zero errors, and the affected
|
|
131
|
+
specifications pass.
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# C# code style
|
|
2
|
+
|
|
3
|
+
## Records
|
|
4
|
+
|
|
5
|
+
Use `record` for every immutable data structure — events, commands, read
|
|
6
|
+
models, concepts, DTOs. Records supply value equality, immutability, and concise
|
|
7
|
+
syntax. A `record class` with `init`-only properties is equivalent when the type
|
|
8
|
+
also needs methods.
|
|
9
|
+
|
|
10
|
+
```csharp
|
|
11
|
+
public record <EventName>(<ConceptType> <PropertyName>);
|
|
12
|
+
|
|
13
|
+
public record <ModelName>(<IdentityType> Id, <ConceptType> <PropertyName>);
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Primary constructors
|
|
17
|
+
|
|
18
|
+
Use primary constructors for all types. They remove the field-plus-constructor
|
|
19
|
+
ceremony.
|
|
20
|
+
|
|
21
|
+
```csharp
|
|
22
|
+
// Preferred
|
|
23
|
+
public class <ClassName>(<CollaboratorType> <collaborator>)
|
|
24
|
+
{
|
|
25
|
+
public async Task <MethodName>(<ArgumentType> <argument>) =>
|
|
26
|
+
await <collaborator>.<Method>(<argument>);
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
When a type genuinely needs field initialization logic and cannot use a primary
|
|
31
|
+
constructor, declare private fields with the `_camelCase` prefix.
|
|
32
|
+
|
|
33
|
+
## `var`
|
|
34
|
+
|
|
35
|
+
Always use `var` for a local variable. The right-hand side already names the
|
|
36
|
+
type.
|
|
37
|
+
|
|
38
|
+
```csharp
|
|
39
|
+
var <identifier> = <Factory>.New();
|
|
40
|
+
var <items> = <source>.Where(<predicate>).ToList();
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Expression-bodied members
|
|
44
|
+
|
|
45
|
+
Use expression-bodied form for simple members.
|
|
46
|
+
|
|
47
|
+
```csharp
|
|
48
|
+
public string <PropertyName> => $"{<First>} {<Second>}";
|
|
49
|
+
public void <MethodName>(string <argument>) => <collaborator>.<Method>(<argument>);
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Collections
|
|
53
|
+
|
|
54
|
+
Return read-only sequence types from public APIs. Never expose a mutable
|
|
55
|
+
collection type — a caller could mutate state its owner is responsible for.
|
|
56
|
+
|
|
57
|
+
```csharp
|
|
58
|
+
// Preferred
|
|
59
|
+
public IEnumerable<<ItemType>> <MethodName>() => <source>.ToList();
|
|
60
|
+
public IReadOnlyDictionary<<KeyType>, <ItemType>> <MethodName>() => <source>;
|
|
61
|
+
|
|
62
|
+
// Avoid on a public API
|
|
63
|
+
public List<<ItemType>> <MethodName>() => <source>;
|
|
64
|
+
public Dictionary<<KeyType>, <ItemType>> <MethodName>() => <source>;
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Nullable reference types
|
|
68
|
+
|
|
69
|
+
Embrace the type system — it is the first defense against null bugs. When an
|
|
70
|
+
annotation says a value cannot be null, trust it.
|
|
71
|
+
|
|
72
|
+
```csharp
|
|
73
|
+
// Use is null / is not null
|
|
74
|
+
if (<value> is null) throw new <DomainException>();
|
|
75
|
+
if (<value> is not null) <statement>;
|
|
76
|
+
|
|
77
|
+
// Do not add a defensive check the annotation already guarantees
|
|
78
|
+
public void <MethodName>(<NonNullableType> <argument>)
|
|
79
|
+
{
|
|
80
|
+
<statement>;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Add ! only where the compiler cannot see what you can prove
|
|
84
|
+
var <identifier> = <source>.FirstOrDefault(<predicate>)!;
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Never write `== null` or `!= null`.
|
|
88
|
+
|
|
89
|
+
## Async
|
|
90
|
+
|
|
91
|
+
- Use `async`/`await`; return `Task` or `Task<T>`.
|
|
92
|
+
- Do not suffix a method with `Async` unless the suffix disambiguates an
|
|
93
|
+
overload.
|
|
94
|
+
- Never use `.Result` or `.Wait()`.
|
|
95
|
+
|
|
96
|
+
```csharp
|
|
97
|
+
public async Task <MethodName>(<ArgumentType> <argument>) =>
|
|
98
|
+
await <collaborator>.<Method>(<argument>);
|
|
99
|
+
|
|
100
|
+
public async Task<<ResultType>?> <FindMethod>(<IdentityType> id) => <expression>;
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Immutability
|
|
104
|
+
|
|
105
|
+
Prefer immutable designs. Produce a modified copy with a `with` expression
|
|
106
|
+
rather than mutating in place.
|
|
107
|
+
|
|
108
|
+
```csharp
|
|
109
|
+
var updated = <existing> with { <PropertyName> = <newValue> };
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
The owner of state is responsible for its mutations. Do not return a mutable
|
|
113
|
+
object a caller could change behind the owner's back.
|
|
114
|
+
|
|
115
|
+
## Pattern matching
|
|
116
|
+
|
|
117
|
+
Use pattern matching and switch expressions wherever they read better than a
|
|
118
|
+
branch chain.
|
|
119
|
+
|
|
120
|
+
```csharp
|
|
121
|
+
if (<result> is <ResultType>.Success success)
|
|
122
|
+
return success.Value;
|
|
123
|
+
|
|
124
|
+
var <identifier> = <value> switch
|
|
125
|
+
{
|
|
126
|
+
<EnumType>.<Member> => <expression>,
|
|
127
|
+
<EnumType>.<OtherMember> => <expression>,
|
|
128
|
+
_ => <fallback>
|
|
129
|
+
};
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## String interpolation
|
|
133
|
+
|
|
134
|
+
```csharp
|
|
135
|
+
// Preferred
|
|
136
|
+
var message = $"<text> '{<value>}' <text>";
|
|
137
|
+
|
|
138
|
+
// Avoid
|
|
139
|
+
var message = string.Format("<text> '{0}' <text>", <value>);
|
|
140
|
+
var message = "<text> '" + <value> + "' <text>";
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Interface bodies
|
|
144
|
+
|
|
145
|
+
Omit the body of a member-less interface.
|
|
146
|
+
|
|
147
|
+
```csharp
|
|
148
|
+
// Preferred
|
|
149
|
+
public interface <IMarkerName>;
|
|
150
|
+
|
|
151
|
+
// Avoid
|
|
152
|
+
public interface <IMarkerName> { }
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## XML documentation
|
|
156
|
+
|
|
157
|
+
XML documentation is a public API's first impression. Every public type, method,
|
|
158
|
+
property, and operator carries it.
|
|
159
|
+
|
|
160
|
+
- `<summary>` is **always multiline** — opening and closing tags on their own
|
|
161
|
+
lines. Never cram it onto one line.
|
|
162
|
+
- Every method or operator with parameters includes a `<param name="…">` for
|
|
163
|
+
each one.
|
|
164
|
+
- Every non-void method or operator includes `<returns>`.
|
|
165
|
+
- Every method that throws documents it with `<exception cref="…">`.
|
|
166
|
+
- Cross-reference with `<see cref="…"/>` and `<paramref name="…"/>`.
|
|
167
|
+
- Keep summaries concise. Document only where it adds understanding beyond the
|
|
168
|
+
name.
|
|
169
|
+
|
|
170
|
+
```csharp
|
|
171
|
+
/// <summary>
|
|
172
|
+
/// Represents <description>.
|
|
173
|
+
/// </summary>
|
|
174
|
+
/// <param name="<parameterName>">The <see cref="<ParameterType>"/> to <purpose>.</param>
|
|
175
|
+
public class <ClassName>(<ParameterType> <parameterName>) : <IInterfaceName>
|
|
176
|
+
{
|
|
177
|
+
/// <summary>
|
|
178
|
+
/// <Verb> the <subject>.
|
|
179
|
+
/// </summary>
|
|
180
|
+
/// <param name="<argumentName>">The <see cref="<ArgumentType>"/> to <purpose>.</param>
|
|
181
|
+
/// <returns>A <see cref="<ReturnType>"/> representing <description>.</returns>
|
|
182
|
+
public async Task<<ReturnType>> <MethodName>(<ArgumentType> <argumentName>)
|
|
183
|
+
{
|
|
184
|
+
<statement>;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
```
|
package/package/corpus/skills/cratis-engineering-csharp-conventions/references/domain-philosophy.md
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Domain philosophy
|
|
2
|
+
|
|
3
|
+
## CUPID characteristics
|
|
4
|
+
|
|
5
|
+
Cratis favors the CUPID characteristics over a strict SOLID reading:
|
|
6
|
+
|
|
7
|
+
| Letter | Characteristic | What it means |
|
|
8
|
+
| --- | --- | --- |
|
|
9
|
+
| **C** | Composable | Parts play nicely together with minimal coupling and can be assembled freely |
|
|
10
|
+
| **U** | Unix philosophy | Do one thing well — focused, single-purpose components |
|
|
11
|
+
| **P** | Predictable | Deterministic behavior, consistent output, no surprises |
|
|
12
|
+
| **I** | Idiomatic | Code feels natural for the language and its ecosystem |
|
|
13
|
+
| **D** | Domain-based | Domain vocabulary and structure, not technical vocabulary |
|
|
14
|
+
|
|
15
|
+
## Cohesion over layers
|
|
16
|
+
|
|
17
|
+
Do not split code by technical role.
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
# Avoid — layered by technical role
|
|
21
|
+
Models/
|
|
22
|
+
<Model>.cs
|
|
23
|
+
Controllers/
|
|
24
|
+
<Name>Controller.cs
|
|
25
|
+
Services/
|
|
26
|
+
<Name>Service.cs
|
|
27
|
+
Events/
|
|
28
|
+
<Name>Event.cs
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Group by feature instead, so everything that changes together lives together.
|
|
32
|
+
Feature folders sit directly under the source root; there is no `Features/`
|
|
33
|
+
wrapper.
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
# Preferred — cohesive by feature
|
|
37
|
+
<Feature>/
|
|
38
|
+
<Behavior>/
|
|
39
|
+
<Behavior>.cs ← the backend artifacts for this behavior
|
|
40
|
+
<Behavior>.tsx ← its component
|
|
41
|
+
<OtherBehavior>/
|
|
42
|
+
<OtherBehavior>.cs
|
|
43
|
+
<OtherBehavior>.tsx
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Frontend and backend concerns naturally separate into different projects, but
|
|
47
|
+
each project keeps the cohesive feature structure inside it.
|
|
48
|
+
|
|
49
|
+
## Ubiquitous language
|
|
50
|
+
|
|
51
|
+
Name after the domain concept, not the technical pattern.
|
|
52
|
+
|
|
53
|
+
| Domain-named | Tech-named |
|
|
54
|
+
| --- | --- |
|
|
55
|
+
| `Authors` | `AuthorController`, `AuthorManager` |
|
|
56
|
+
| `Registration` | `RegisterAuthorHandler`, `RegisterAuthorCommand` |
|
|
57
|
+
| `AuthorNotFound` | `AuthorNotFoundException`, `NotFoundException` |
|
|
58
|
+
| `AuthorId` | a raw `Guid authorId` |
|
|
59
|
+
| `Listing` | `GetAllAuthorsQuery` |
|
|
60
|
+
|
|
61
|
+
## Pluralization
|
|
62
|
+
|
|
63
|
+
Features are groupings, so pluralize them consistently across folder, route, and
|
|
64
|
+
schema: `Authors/`, `/api/Authors/{authorId}`, an `Authors` schema.
|
|
65
|
+
|
|
66
|
+
## Twelve-factor operability
|
|
67
|
+
|
|
68
|
+
Systems follow the twelve-factor guidance for scalability, maintainability, and
|
|
69
|
+
operability:
|
|
70
|
+
|
|
71
|
+
- Configuration comes from the environment, never hardcoded.
|
|
72
|
+
- Processes are stateless.
|
|
73
|
+
- Logs are treated as event streams.
|
|
74
|
+
- Setup is declarative so an environment can be replicated.
|
|
75
|
+
|
|
76
|
+
## Frictionless dependencies
|
|
77
|
+
|
|
78
|
+
Healthy dependencies mean fast, independent releases. If two components must
|
|
79
|
+
have their releases coordinated, that is unhealthy coupling — address it through
|
|
80
|
+
events, an interface, or package versioning rather than accepting the lockstep.
|
|
81
|
+
|
|
82
|
+
## Immutability and side effects
|
|
83
|
+
|
|
84
|
+
Favor immutable designs to reduce side effects:
|
|
85
|
+
|
|
86
|
+
- Records with `init`-only properties.
|
|
87
|
+
- Return a new instance rather than mutating an existing one.
|
|
88
|
+
- Expose `IEnumerable<T>` and `IReadOnlyDictionary<TKey, TValue>` from public
|
|
89
|
+
APIs, never a mutable collection.
|
|
90
|
+
- The owner of state is responsible for its mutations. Do not let a consumer
|
|
91
|
+
mutate internal state.
|