Repository navigation
Release v2.21.0
Corpus: exceptions are for unrecoverable state only, never anticipated control flow
Prompted by a real violation caught mid-session: IWorkerRuntime.Start (Cratis.AI's own worker
runtime, ported from Direct) throws WorkerIsAlreadyRunning/WorkerIsStillGoingAway/
WorkerLaunchWasRefused for three entirely anticipated, recoverable outcomes of trying to launch a
worker, and every caller is structured as one try wrapping three catch blocks that each go on to do
real application work - record a specific dispatch impediment, decide whether to keep a callback
token. That is exception-driven control flow with a well-documented exception type, which is still
the wrong tool: csharp.md already said "never for control flow" but without a concrete tell for
recognizing it or a worked alternative, and the pattern shipped anyway.
Strengthened the Exceptions section in .cratis/ai/rules/csharp.md:
- Named the actual test: exceptions are for unrecoverable state - state where the caller has no
correct next step but to stop. If a catch block goes on to do ordinary application work in
response to an anticipated outcome, that outcome belongs in the return type, not the throw list. - Named the tell: a catch block that isn't "log and rethrow" or "crash louder" is exception-driven
flow control, however well-named and documented the exception type is. - A concrete before/after pair using the actual violation as the "wrong" example and a
Cratis.Monads.Result<TResult, TError>-based redesign as the "right" one, naming every real outcome
in an enum the compiler forces every caller to handle - plus a pointer to Option for the
"value or nothing, no error to describe" shape.
This governs .cratis/ai/rules/csharp.md content only - it does not yet fix the actual violation in
Cratis.AI's own IWorkerRuntime/DockerWorkerRuntime/KubernetesWorkerRuntime/WorkerLauncher, which is
real, outstanding work tracked separately (the corpus rule needed to exist and ship before the code
fix, so every future PR - including the one fixing this one - is held to it, and so nobody else
copies the pattern in the meantime).
Verified: yarn workspace @cratis/ai-verification run verify (53 skills/66 profiles, passed),
@cratis/ai-verification/@cratis/harness-setup/@cratis/pi's own check scripts all clean, git diff
--check clean. Markdown line-length linting was checked and confirmed not to apply to
.cratis/ai/rules/*.md in this repository's actual CI (pre-existing lines in this same file already
exceed 600 characters; no workflow step lints this path) - the prose style here is intentionally
unwrapped, matching every other rule file.