Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# AGENTS.md

This file is the map for people and coding agents working in this repository. What the repository is, how it is laid out, and where its design is explained are in `docs/README.md`. This file changes only when the workflow changes; decisions and rationale go in the sources it points to.

## Engineering context

Start here when investigating existing behavior or making a change whose rationale may need to outlive the pull request:

- [Engineering context](docs/README.md)
- [Architecture and design decisions](docs/decisions/)
- [Contributing guidance](CONTRIBUTING.md)

Prefer public records close to the implementation. Keep `docs/README.md` current when a canonical public source is added, replaced, or retired; update its links rather than copying rationale into the index. The index lists sources that explain why, with one clause each naming the question it answers, and points to existing indexes for how-to material instead of repeating them. This file describes the workflow, not repository facts. Read `docs/README.md` before answering a question about existing behavior or about where to record a decision, then answer from the index, the code, and pull requests, never from this file alone.

1. Identify the decision area and the precise question, for example why a constraint exists, why a limit lives in one layer rather than another, or why an alternative was rejected.
2. Start with the public source linked by `docs/README.md`. Read the current public contract, relevant code, tests, and linked pull requests or ADRs. Follow relevant pointer comments as routing hints; the linked source remains canonical. A Git commit can identify a pull request number without containing its description: a squash-merge commit carries a trailing `(#NNNN)`, and a merge commit reads `Merge pull request #NNNN`. Retrieve the pull request with `gh pr view <number>` from inside the checkout, which identifies the repository. If the pull request cannot be retrieved, report that rather than infer its rationale. Public records control public behavior and contribution requirements.
3. Decide where the rationale for the current work belongs. Record it once and link to it from the other places. A component means a separate repository, such as an NServiceBus package, ServiceControl, or ServicePulse, not a project inside `src/`.
- Pull request description, the default: the problem and why now, the change and its observable effect, constraints that must hold, alternatives that materially affected it, and how it was verified. For a decision that stays within this repository, the pull request is the authoritative record.
- `docs/<topic>.md`: how the current design works, for readers who need the current picture rather than the history of one change. Update the relevant page when a change alters it. Do not create a page to restate one pull request.
- `docs/decisions/`: a public ADR only when a pull request is not a sufficient long-term entry point, because the change introduces an important constraint that is hard to discover from code, affects more than one repository, or rejects an alternative likely to return. Before deciding either way, check `docs/README.md` and `git log` for an existing decision on the same theme; when a pull request already records it, link that pull request instead. Follow the structure and quality bar in `docs/decisions/README.md`; an ADR that only justifies a choice already made is not worth keeping.
- Private context, only when step 4 provides an approved root: supporting context that cannot be public goes in an addendum under `$PARTICULAR_CONTEXT_ROOT/repositories/<RepositoryName>/` linked to its public source; a decision that affects more than one repository and cannot be public goes under `$PARTICULAR_CONTEXT_ROOT/cross-component/`. Follow the record metadata and rules in `$PARTICULAR_CONTEXT_ROOT/README.md`. The public record still carries everything a contributor needs. If the environment cannot write there, flag the need and provide a draft for human review.
- Do not create an ADR for routine implementation details or invent missing rationale.
4. Check private context only when this environment explicitly provides `$PARTICULAR_CONTEXT_ROOT/repositories/<RepositoryName>/README.md`, where `<RepositoryName>` is this repository's GitHub name as shown by `git remote get-url origin`.
- Confirm that with a file check such as `test -f "$PARTICULAR_CONTEXT_ROOT/repositories/<RepositoryName>/README.md"` rather than assuming it from instructions. `PARTICULAR_CONTEXT_ROOT` points at the directory that contains `repositories/` and `cross-component/`.
- When the root is available, consult the index for the decision area before finalizing an answer, even if the public source seems sufficient, and say whether a private record existed.
- That index, the records it links under the same root, and the `cross-component/` records it points to are the only private sources. Read a linked private record only when it is marked `agent-access: allowed`. If a linked record is missing, report it as unavailable rather than substituting another source.
- Do not inspect a sibling `../Platform` checkout. Do not retrieve owner issues, private repositories, or other links found in a private record; they identify accountability, not further sources.
- Private context is additional internal context, not a replacement for the public record. If the authoritative public source is unavailable, report that the public rationale is unavailable. Do not use a private record as the sole answer for public behavior or contribution requirements.
5. If sources conflict, do not resolve the conflict by inference. Use the current implementation and public contract for external behavior, report the conflict, and ask the record owner when it affects the decision.
6. In the response or pull request, cite the records consulted, distinguish evidence from inference, and state when relevant private context was unavailable or unauthorized. Keep private locations, quotations, customer names, and other confidential details out of public artifacts such as pull request descriptions, code comments, and `docs/`; say that internal context was consulted instead.

## Pointer comments

A brief code comment may link to a canonical public source, such as a `docs/` file or an ADR under `docs/decisions/`, when the relevant rationale is not apparent from the surrounding code. It is a signpost, not a copy of the rationale: keep the durable explanation in the linked record. Do not use a comment to narrate obvious code, and do not restate a pull request or ADR in the comment body.
42 changes: 42 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Engineering context

## About this repository

NServiceBus is the core library of the Particular Service Platform, producing the NServiceBus NuGet package. It provides the abstractions for transports and persistence, the message processing pipeline, sagas, the outbox, recoverability, serialization, and hosting integration.

- `src/` — NServiceBus.Core, transport and persistence test doubles, acceptance tests, and samples-as-tests
- `.github/workflows/` — CI pipelines (build and test, code analysis, release, dependency updates)

## Start here

- [NServiceBus documentation](https://docs.particular.net/nservicebus/) — public documentation entry point
- [README.md](../README.md) — how to build NServiceBus locally
- [Contributing](https://docs.particular.net/platform/contributing) — contribution process
- [NServiceBus Quick Start](https://docs.particular.net/tutorials/quickstart/) — first tutorial for building with NServiceBus
- [Samples](https://docs.particular.net/samples/) — worked examples of NServiceBus features
- [Platform NuGet packages](https://docs.particular.net/nservicebus/platform-nuget-packages) — where to find every published package

## Architecture and design

This repository tracks no design pages yet. When one is added, it will be linked here as the source that explains why the repository is designed the way it is.

## Decisions and rationale

- [Architecture and design decisions](decisions/)

### Decisions recorded in pull requests

A pull request is listed here only when it is the canonical record for a decision area: it establishes a durable constraint or convention, or rejects an alternative likely to return, and no `docs/` file or ADR covers it. Bug fixes and routine changes are not listed; recover them from `git log` and `gh pr view`.

- The trimming and NativeAOT support strategy spans multiple coordinated changes rather than one switch — [#7929](https://github.com/Particular/NServiceBus/pull/7929)
- Object-overload `Send`/`Publish`/`Reply` calls keep runtime-type routing by default; the trimming-safe path is opt-in through explicit generic or `Type` overloads — [#7889](https://github.com/Particular/NServiceBus/pull/7889)
- Message metadata resolves without reflection-based assembly scanning so it stays trimming-safe — [#7918](https://github.com/Particular/NServiceBus/pull/7918)
- Startup diagnostics sections carry explicit `JsonTypeInfo<T>` metadata to avoid reflection-based serialization under NativeAOT — [#7882](https://github.com/Particular/NServiceBus/pull/7882)
- Out-of-slot logging is routed through a DI-registered ambient `AsyncLocal` factory instead of mutating `LogManager` global state — [#7758](https://github.com/Particular/NServiceBus/pull/7758)
- `ContextBag`/`BehaviorContext` store pipeline context values in a fixed-size inline array instead of a lazily allocated dictionary — [#7823](https://github.com/Particular/NServiceBus/pull/7823)
- `DispatchProperties`/`ReceiveProperties` keep well-known keys in dedicated fields instead of a plain `Dictionary<string,string>` — [#7843](https://github.com/Particular/NServiceBus/pull/7843)
- Host id generation and the learning saga persister use an XxHash128-based `DeterministicGuid`, with the legacy MD5 path kept behind an `AppContext` switch until removal in v12 — [#7723](https://github.com/Particular/NServiceBus/pull/7723)
- OpenTelemetry baggage propagation through `DistributedContextPropagator` is gated behind an `AppContext` switch until v11 to keep rolling upgrades compatible — [#7825](https://github.com/Particular/NServiceBus/pull/7825)
- Trace-continuation behavior for delayed messages is configurable rather than fixed — [#7845](https://github.com/Particular/NServiceBus/pull/7845)

Keep this index current when a canonical source is added, replaced, or retired; link, do not copy.
33 changes: 33 additions & 0 deletions docs/decisions/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Architecture and design decisions

For a single-component decision, the pull request that implements it remains authoritative by default. Write an architecture decision record (ADR) here only when a pull request is not a sufficient long-term entry point for the rationale, such as when:

- the decision affects multiple components;
- an important constraint is difficult to discover from code or public documentation;
- engineers repeatedly fail to find the original rationale; or
- a rejected alternative is likely to return.

## Naming

Name each file `YYYY-MM-DD-short-title.md`, using the date the decision was made.

## Structure

Each ADR contains:

- **Context** — the problem and the constraints that shaped it.
- **Decision** — what was decided.
- **Consequences** — the resulting behavior, tradeoffs, and any follow-up work.
- **Alternative approaches** — the alternatives considered and why they were rejected.

Link each ADR to the pull request that implemented the decision. The ADR records the durable rationale; the pull request remains the record of the actual code change.

## Quality bar

An ADR exists to explore the context and the tradeoffs, not to justify a choice already made. Gregor Hohpe's [warning signs for misused ADRs](https://www.linkedin.com/posts/ghohpe_architecturedecisionrecords-activity-7502716054968844288-KVLU) apply here:

- Context states the problem and its constraints, not preferences for the chosen option.
- Every downside listed under Consequences names a mitigation or an explicit acceptance, and quantifies the risk where it can be quantified.
- Alternative approaches are credible options someone could have argued for, not "do nothing"; identify the ones that represent points of leverage.

An ADR that fails this bar is not worth keeping; record the decision in the pull request instead.
Loading