Skip to content

Record which command is executing on the causation chain - #2616

Merged
einari merged 3 commits into
mainfrom
feat/command-causation
Aug 29, 2026
Merged

Record which command is executing on the causation chain#2616
einari merged 3 commits into
mainfrom
feat/command-causation

Conversation

@einari

@einari einari commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Records which command is executing on the causation chain, so every event a command appends carries the command that produced it — and, when one command executes another, the command one level up. Also brings every dependency to its latest version, including Cratis.Chronicle 16.39.1.

Added

  • Events appended by a command now carry a Command causation naming that command. The chain already said how the work arrived — an HTTP request, a reactor — but not what was asked for, so an appended event could be traced back to a request path and no further. A command executed from another command stacks its link on the outer one's, which is what makes "the command one level up" answerable.

Changed

  • Every dependency updated to its latest version, including Cratis.Chronicle 16.39.1 and the Cratis.Fundamentals 7.18.2 / Cratis.Metrics.Roslyn 7.18.2 it requires.

Fixed

  • The Chronicle Published automation retried a version conflict for ten minutes and then reported it as a NuGet indexing timeout. A conflict is a decision the workflow cannot make — the new Chronicle wants a dependency newer than the version pinned here — so it now fails immediately with the conflicting pins instead of blaming NuGet. This is what made the 16.39.1 update fail.
  • The same automation merged its update with --squash, which collapses the branch's commits into a new one and leaves the originals unreachable. It now merges with a real merge commit.

einari and others added 2 commits August 28, 2026 19:39
The chain already says how work arrived - an HTTP request, a reactor -
but not what was asked for. Without a link naming the command, an
appended event can be traced back to a request path and no further, and
a command executed from another command is indistinguishable from one
executed directly.

CommandCausationScope adds the link immediately before the command's
filters and handler run, so it is on the chain for every append the
command makes, and removes it when the command completes. Removal is
what keeps two commands run one after the other - a reactor executing
both, a job looping - siblings rather than making the second read as
caused by the first.

The per-event causation for returned events names the command too, so
both append paths carry it.

Provisional: pinned to a locally packed Chronicle prerelease for
BeginScope. Re-pin to the published version before opening a PR.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KqW4sfUp2ieSu1pbxV4RzA
Picks up Cratis.Chronicle 16.39.1 along with the Cratis.Fundamentals
7.18.2 and Cratis.Metrics.Roslyn 7.18.2 it requires - the conflict that
made the chronicle-published automation fail, since it bumps only the
Chronicle pins and a downgrade error is not something retrying resolves.

The analyzer majors that came with it needed two answers of different
kinds:

- MA0219 asks for a lang attribute on every inline <c> element and fires
  1410 times. The codebase uses <c> to name a type or member in prose,
  where there is no language to state, so it is turned off alongside the
  other rules this repository has judged noise.
- CRSPEC0001 found a spec named for what it does rather than for the fact
  it asserts. That one is a real convention violation, so it is renamed
  rather than silenced.

The regenerated TestApps proxies come from the generator as it stands
today; they were last written before it changed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KqW4sfUp2ieSu1pbxV4RzA
@einari einari added the minor label Aug 29, 2026
NSubstitute 6 changes the Castle.Core it brings, and that combination
deadlocks MongoCollectionInterceptor: the whole MongoDB.Specs assembly
hangs before a single test runs, which reads in CI as a thirty-minute
job timeout rather than as a failure.

Bisected from a green baseline one package at a time, then located with
a hang dump - the run stops in
Resilience.for_MongoCollectionInterceptor.when_intercepting.

Moving to 6 is a migration of the DynamicProxy layer rather than a
version bump, so it is left for work that can take that on.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KqW4sfUp2ieSu1pbxV4RzA
@einari
einari merged commit 51445fc into main Aug 29, 2026
58 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant