@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,130 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cratis-engineering-effect-boundaries
|
|
3
|
+
description: Apply the Cratis effect-boundary contract when writing or reviewing code that publishes, persists, generates, propagates, or releases. On those boundaries partial success is failure - no catch-and-continue, no defaulting to success on an unknown outcome. Use when a degraded run could still report success; defer style questions and specification authoring to their own workflows.
|
|
4
|
+
license: LICENSE
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Effect boundaries fail loudly
|
|
8
|
+
|
|
9
|
+
An **effect boundary** is the point where work leaves the process and becomes
|
|
10
|
+
something other people observe: a package published, a row written, a file
|
|
11
|
+
generated, content propagated to other repositories, a release cut.
|
|
12
|
+
|
|
13
|
+
The contract:
|
|
14
|
+
|
|
15
|
+
> On an effect boundary, **partial success is failure.** No catch-and-continue,
|
|
16
|
+
> no defaulting to success on an unknown outcome. A degraded operation must fail
|
|
17
|
+
> the operation, surface the delta, or emit an explicit degraded-mode signal.
|
|
18
|
+
|
|
19
|
+
Silent failure is the dominant recurring bug archetype across Cratis. The
|
|
20
|
+
2026-08-24 organization-wide review found one disease with six manifestations,
|
|
21
|
+
in the release action, the Arc proxy generator, Stage, the Chronicle container
|
|
22
|
+
host, Chronicle constraint enforcement, and corpus propagation. They are written
|
|
23
|
+
out in [failure-archetypes.md](references/failure-archetypes.md); read them
|
|
24
|
+
before deciding that your case is different.
|
|
25
|
+
|
|
26
|
+
## When you need this
|
|
27
|
+
|
|
28
|
+
- You are writing or reviewing a `catch` around an operation with an effect —
|
|
29
|
+
publish, write, generate, copy, notify, tag, release.
|
|
30
|
+
- An operation processes a set and some members can fail independently: a
|
|
31
|
+
fan-out, a batch, a matrix, a per-file generator.
|
|
32
|
+
- A call returns an outcome you did not model: an unexpected status code, a
|
|
33
|
+
null, an empty result, a timeout.
|
|
34
|
+
- Two implementations of one interface exist and only one of them really
|
|
35
|
+
enforces the behavior — an in-memory or SQL sibling of a real store.
|
|
36
|
+
- A host, container, or long-running process can reach a "started" state while
|
|
37
|
+
the thing it started has already thrown.
|
|
38
|
+
|
|
39
|
+
## When you do not
|
|
40
|
+
|
|
41
|
+
- **Pure computation with no effect.** A parser that returns a partial tree for
|
|
42
|
+
a caller that inspects it is not an effect boundary.
|
|
43
|
+
- **A retry that will still report the final outcome truthfully.** Retrying is
|
|
44
|
+
not swallowing; reporting success after the retries also failed is.
|
|
45
|
+
- **A genuinely optional enrichment whose absence is stated in the result.** An
|
|
46
|
+
optional cache warm that records `cache: skipped` is a degraded-mode signal,
|
|
47
|
+
which is exactly what this contract asks for.
|
|
48
|
+
- **Style, naming, or structure questions.** Those belong to the C# and
|
|
49
|
+
TypeScript conventions.
|
|
50
|
+
- **Deciding whether an operation should exist at all.** That is a product or
|
|
51
|
+
scope ruling, not an error-handling one.
|
|
52
|
+
|
|
53
|
+
## Steps
|
|
54
|
+
|
|
55
|
+
1. **Name the boundary before you write the handler.** Say out loud what leaves
|
|
56
|
+
the process: which package, which rows, which files, which repositories.
|
|
57
|
+
If nothing leaves, this contract does not apply and you can stop here.
|
|
58
|
+
2. **Enumerate the outcomes the call can produce, including the ones you did not
|
|
59
|
+
design for.** An unexpected status code, an empty response, and a timeout are
|
|
60
|
+
outcomes. A handler that maps everything it did not enumerate onto success is
|
|
61
|
+
the defect.
|
|
62
|
+
3. **Choose one of the three permitted responses to a degraded outcome, and say
|
|
63
|
+
which one you chose.** Fail the operation; or complete and surface the delta
|
|
64
|
+
in the result; or emit an explicit degraded-mode signal the caller must
|
|
65
|
+
handle. Anything else is catch-and-continue.
|
|
66
|
+
4. **Make partial fan-out visible in the aggregate, not just in the log.** Count
|
|
67
|
+
attempted, succeeded, and failed, and put all three in the returned result
|
|
68
|
+
and the summary line. "29 of 36 succeeded" and "36 of 36 succeeded" must not
|
|
69
|
+
produce the same output.
|
|
70
|
+
5. **Refuse to convert an unknown into a pass.** An outcome the code could not
|
|
71
|
+
classify is `indeterminate`. Report it as its own state; never roll it up
|
|
72
|
+
into the success count.
|
|
73
|
+
6. **Check the sibling implementations of the same interface.** When a real
|
|
74
|
+
store enforces a constraint, its in-memory and SQL siblings must enforce the
|
|
75
|
+
same one or throw `NotSupported`. A sibling that silently accepts what the
|
|
76
|
+
real one rejects makes every specification that uses it pass vacuously.
|
|
77
|
+
7. **Make the process state follow the work.** If startup threw, the host is not
|
|
78
|
+
`Running`. A liveness or readiness state that survives a failed start is a
|
|
79
|
+
lie the orchestrator will believe.
|
|
80
|
+
8. **Plant the failure and watch it surface.** Force the degraded outcome —
|
|
81
|
+
inject the status code, delete an input, fail one fan-out member — and
|
|
82
|
+
confirm the operation fails, the delta appears, or the degraded signal fires.
|
|
83
|
+
A boundary whose failure path was never executed is not known to have one.
|
|
84
|
+
|
|
85
|
+
## What breaks
|
|
86
|
+
|
|
87
|
+
Every item below is a real Cratis defect, not an illustration. Detail and issue
|
|
88
|
+
references are in [failure-archetypes.md](references/failure-archetypes.md).
|
|
89
|
+
|
|
90
|
+
- **A swallowed conflict reported as a successful release.** The release action
|
|
91
|
+
caught a 422 from a concurrent publish and reported the release as done. The
|
|
92
|
+
version was never published, and the only artifact that said so was a caught
|
|
93
|
+
exception nobody saw.
|
|
94
|
+
- **A generator that degrades silently.** The Arc proxy generator emitted fewer
|
|
95
|
+
proxies than its inputs implied and exited zero. The failure shows up much
|
|
96
|
+
later as a missing TypeScript type, far from the generator that dropped it.
|
|
97
|
+
- **A renderer that quietly renders less.** Stage produced degraded output on a
|
|
98
|
+
path that reported success, so the difference between correct output and
|
|
99
|
+
partial output was invisible at the boundary that produced it.
|
|
100
|
+
- **A container that stays `Running` after startup threw.** The Chronicle host
|
|
101
|
+
reported healthy while the thing it hosts had already failed to start, so the
|
|
102
|
+
orchestrator kept routing to it.
|
|
103
|
+
- **A constraint that only one implementation enforces.** Chronicle unique
|
|
104
|
+
constraints were not enforced on the SQL and in-memory storage providers.
|
|
105
|
+
Every specification exercising them passed while proving nothing.
|
|
106
|
+
- **A fan-out that succeeded 29 times out of 36 and said "done".** Corpus
|
|
107
|
+
propagation aggregated per-target results into a single success, so seven
|
|
108
|
+
repositories silently did not receive the change.
|
|
109
|
+
|
|
110
|
+
The shared symptom: **the failure is discovered downstream, by someone who
|
|
111
|
+
cannot see the boundary that caused it.** That is what makes this archetype
|
|
112
|
+
expensive rather than merely annoying.
|
|
113
|
+
|
|
114
|
+
## How it is proven
|
|
115
|
+
|
|
116
|
+
- **The failure path was executed.** Name the planted defect and the observed
|
|
117
|
+
result: the injected status code, the removed input, the failed fan-out
|
|
118
|
+
member — and what the operation did in response.
|
|
119
|
+
- **Counts appear on success.** The clean run reports how many subjects it
|
|
120
|
+
attempted and how many succeeded. A bare "OK" cannot be distinguished from a
|
|
121
|
+
run over an empty set.
|
|
122
|
+
- **Exit codes carry the verdict.** `0` ran clean, `1` found defects, `2` could
|
|
123
|
+
not run. A wrapper that exits `0` because the wrapper finished has thrown the
|
|
124
|
+
child's verdict away; check the child's status and, in a pipeline, the status
|
|
125
|
+
of every stage.
|
|
126
|
+
- **The degraded signal is asserted, not just emitted.** A specification reads
|
|
127
|
+
the delta or the degraded-mode field and fails when it is absent.
|
|
128
|
+
- **Sibling implementations are covered by the same specification.** The test
|
|
129
|
+
that proves the constraint runs against every implementation of the interface,
|
|
130
|
+
not only the one that enforces it.
|
package/package/corpus/skills/cratis-engineering-effect-boundaries/references/failure-archetypes.md
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# The six cited failure archetypes
|
|
2
|
+
|
|
3
|
+
These are the six manifestations the 2026-08-24 Cratis organization-wide review
|
|
4
|
+
identified as one disease: silent failure on an effect boundary. Each is a real,
|
|
5
|
+
tracked defect. Read them as the shape of the mistake, not as a list of fixed
|
|
6
|
+
bugs — the same shape keeps reappearing in new code.
|
|
7
|
+
|
|
8
|
+
For each: what the boundary was, what the code did, why the failure was
|
|
9
|
+
expensive, and what the contract required instead.
|
|
10
|
+
|
|
11
|
+
## 1. A swallowed conflict reported as a successful release
|
|
12
|
+
|
|
13
|
+
*release-action #178.*
|
|
14
|
+
|
|
15
|
+
**Boundary.** Publishing a version — the most public effect there is.
|
|
16
|
+
|
|
17
|
+
**What happened.** A concurrent publish made the registry return HTTP 422. The
|
|
18
|
+
action caught it and continued, and the run reported the release as successful.
|
|
19
|
+
|
|
20
|
+
**Why it was expensive.** The one artifact that recorded the truth was an
|
|
21
|
+
exception nobody saw. Everything downstream — release notes, subscriber pins,
|
|
22
|
+
the assumption that the version existed — was built on a success that had not
|
|
23
|
+
happened. Nothing later in the pipeline re-checked the registry, because a
|
|
24
|
+
successful publish is normally proof enough.
|
|
25
|
+
|
|
26
|
+
**What the contract required.** A 422 on publish is an outcome that must be
|
|
27
|
+
classified, not caught. Either the version already exists and is byte-identical
|
|
28
|
+
(report it as already-published, explicitly), or it does not and the publish
|
|
29
|
+
failed. "Caught an exception, carried on" is neither.
|
|
30
|
+
|
|
31
|
+
## 2. A generator that degrades silently
|
|
32
|
+
|
|
33
|
+
*Arc #2571, #2564, #2527 — the proxy generator.*
|
|
34
|
+
|
|
35
|
+
**Boundary.** Generating TypeScript proxies from C# sources. The output is what
|
|
36
|
+
the whole frontend compiles against.
|
|
37
|
+
|
|
38
|
+
**What happened.** The generator produced fewer proxies than its inputs implied
|
|
39
|
+
and still exited zero.
|
|
40
|
+
|
|
41
|
+
**Why it was expensive.** The symptom appears far from the cause: a missing
|
|
42
|
+
TypeScript type in a component, at a point where nobody is thinking about the
|
|
43
|
+
generator. The natural first hypothesis is that the frontend is wrong.
|
|
44
|
+
|
|
45
|
+
**What the contract required.** A generator that consumed N inputs and emitted
|
|
46
|
+
fewer than N artifacts reports the delta and fails, or names the skipped inputs
|
|
47
|
+
and why. Reporting the count on success is what makes the shortfall visible at
|
|
48
|
+
all: "generated 41 of 41" and "generated 38 of 41" have to read differently.
|
|
49
|
+
|
|
50
|
+
## 3. A renderer that quietly renders less
|
|
51
|
+
|
|
52
|
+
*Stage #53.*
|
|
53
|
+
|
|
54
|
+
**Boundary.** Rendering output that someone will look at and act on.
|
|
55
|
+
|
|
56
|
+
**What happened.** A degraded rendering path produced partial output while
|
|
57
|
+
reporting success.
|
|
58
|
+
|
|
59
|
+
**Why it was expensive.** Partial output looks like output. There is no error to
|
|
60
|
+
search for and no count to compare, so the difference between correct and
|
|
61
|
+
degraded is invisible at exactly the boundary that produced it.
|
|
62
|
+
|
|
63
|
+
**What the contract required.** A renderer that could not render something says
|
|
64
|
+
so in its result — a degraded-mode signal the caller has to handle, not a log
|
|
65
|
+
line at the end of a stream nobody reads.
|
|
66
|
+
|
|
67
|
+
## 4. A container that stays `Running` after startup threw
|
|
68
|
+
|
|
69
|
+
*Chronicle #3682.*
|
|
70
|
+
|
|
71
|
+
**Boundary.** Process and container lifecycle — the state an orchestrator reads
|
|
72
|
+
to decide whether to send traffic.
|
|
73
|
+
|
|
74
|
+
**What happened.** Startup threw, and the container remained in `Running`.
|
|
75
|
+
|
|
76
|
+
**Why it was expensive.** The orchestrator believed the reported state and kept
|
|
77
|
+
routing to a host that had never finished starting. The failure surfaces as
|
|
78
|
+
inexplicable behavior in callers rather than as a failed start.
|
|
79
|
+
|
|
80
|
+
**What the contract required.** Process state follows the work. If startup
|
|
81
|
+
failed, the process exits non-zero or reports unhealthy. A liveness state that
|
|
82
|
+
survives a failed start is not a degraded signal, it is a false one.
|
|
83
|
+
|
|
84
|
+
## 5. A constraint that only one implementation enforces
|
|
85
|
+
|
|
86
|
+
*Chronicle #3744 — unique constraints on the SQL and in-memory providers.*
|
|
87
|
+
|
|
88
|
+
**Boundary.** Persistence, and the invariant the store is supposed to guarantee.
|
|
89
|
+
|
|
90
|
+
**What happened.** Unique constraints were not enforced on the SQL and in-memory
|
|
91
|
+
storage providers, while the primary provider enforced them.
|
|
92
|
+
|
|
93
|
+
**Why it was expensive.** This is the worst variant, because it does not fail —
|
|
94
|
+
it makes specifications pass vacuously. Every test written against the
|
|
95
|
+
in-memory provider proved that duplicate writes were accepted, and read as
|
|
96
|
+
proof that the constraint worked. The gap only appears in the one environment
|
|
97
|
+
nobody tests against by default.
|
|
98
|
+
|
|
99
|
+
**What the contract required.** An alternate implementation of an interface
|
|
100
|
+
matches the primary one's *semantics*, not just its signature. Where it cannot,
|
|
101
|
+
it throws rather than silently accepting. The specification that proves the
|
|
102
|
+
constraint runs against every implementation.
|
|
103
|
+
|
|
104
|
+
## 6. A fan-out that succeeded 29 times out of 36 and said "done"
|
|
105
|
+
|
|
106
|
+
*The retired corpus propagation.*
|
|
107
|
+
|
|
108
|
+
**Boundary.** Propagating content into other repositories — an effect in 36
|
|
109
|
+
places at once.
|
|
110
|
+
|
|
111
|
+
**What happened.** Per-target results were aggregated into a single overall
|
|
112
|
+
success. Seven repositories did not receive the change, and the aggregate said
|
|
113
|
+
nothing about it.
|
|
114
|
+
|
|
115
|
+
**Why it was expensive.** Nobody knew which seven. Recovering meant re-deriving
|
|
116
|
+
the target list and comparing every repository by hand, long after the run's
|
|
117
|
+
own record of what happened had been lost to log rotation.
|
|
118
|
+
|
|
119
|
+
**What the contract required.** Attempted, succeeded, and failed are three
|
|
120
|
+
separate numbers, all three in the returned result and the summary line. A
|
|
121
|
+
fan-out that cannot name its failures has not reported its outcome. "29 of 36"
|
|
122
|
+
is not a success with a footnote; on an effect boundary it is a failure.
|
|
123
|
+
|
|
124
|
+
## What the six have in common
|
|
125
|
+
|
|
126
|
+
- The failing code **caught something and continued**, or **mapped an
|
|
127
|
+
unmodelled outcome onto success**.
|
|
128
|
+
- The success signal was **produced by the layer that failed**, so no later
|
|
129
|
+
check re-derived it.
|
|
130
|
+
- The cost was paid **downstream, by someone who could not see the boundary**.
|
|
131
|
+
- In the two worst cases (2 and 5) the defect made verification itself
|
|
132
|
+
meaningless: a green generator run and a green specification suite that were
|
|
133
|
+
both measuring nothing.
|