Group Arc's documentation by backend language, and show shared pages in both - #2708
Merged
Merged
Conversation
The checker reported success the same way whether it validated every page or none at all, so a path that resolved to an empty tree printed "passed for 0 files" and exited clean. That is the failure the script exists to catch, and it becomes far more likely while pages are moving between folders. Refuse to pass vacuously.
Arc now has two backend implementations, and the documentation was shaped for one. Everything under backend/ was C#, so a JVM reader had nowhere to land and no way to tell which pages applied to them. Move the C# pages to backend/csharp/ and add a backend overview that names both implementations and says what they agree on. The two pages that only ever described the C# stack — the MediatR and MVC comparison and the Screenplay generator, which has no JVM equivalent — move under C# as well, so Concepts and architecture holds only pages that are true of Arc rather than of one stack. Fold Chronicle in under C# too. It was a top-level Integrations section documenting the .NET Chronicle client exclusively, which stops being honest once a second backend exists with its own Chronicle integration. Put the MVVM pages and the React getting-started under React, so everything React-shaped sits together and a future frontend framework becomes a sibling rather than a special case. Links were repaired against what actually resolves on disk rather than by pattern, and the moved routes are redirected on the site.
Identity enrichment, authorization attributes and tenant resolution are the same ideas whichever backend runs them, and the page explaining them showed only C#. A JVM reader had to translate the examples themselves and guess whether the behaviour matched. Move the two examples into snippet files per language and render them as selectable tabs, so the explanation is written once and the code is shown in the reader's language. The Kotlin side is taken from the JVM implementation's own documented API rather than transliterated from C#.
The scenario recipes, the real-time tutorial chapter and the proxy boundary explanation showed C# only, so a JVM reader had to translate every example and hope the behaviour carried over. Each example now renders as a tab per backend language, drawn from a snippet file the implementation owns. Where the backends genuinely differ the prose says so rather than implying symmetry: a suspending provide has no cancellation token, a JVM handler carries validation feedback out through an exception because it exposes a single client response leaf, and the shared fluent validator accepts only literal rules. Scope the command-operation recommendations to C#. The JVM has no operation mechanism at all — no match in any module or ABI baseline — so seven shared pages were recommending something half their readers cannot use. Rewrite the proxy-generator step for the same reason: it described a post-build executable reading the compiled assembly as though that were the only way, when the JVM discovers the same artifacts with a compile-time annotation processor. Both are now named. Compile the C# snippets. The JVM side has been checked against source all along, so the two languages were held to different standards; the validator builds every snippet against the real Arc projects, and its self-test plants a reference to a type that does not exist and fails unless the build rejects it.
Arc had no glossary at all on the C# side, and the JVM side's was written in JVM terms, so there was nowhere a reader could learn what Arc means by a command key, an execution scope or an observable query without also learning one implementation's spelling of it. Add a shared glossary that defines the idea and names both spellings where they differ, and leave each implementation's own glossary to the terms that genuinely belong to it.
A page and a sibling folder differed only in case, and the site lowercases every path segment when it builds a slug, so both claimed the same route. The fourteen-line "this has moved" stub won it, which meant the configuration overview in the sidebar served a notice telling the reader the documentation had moved and linking back to itself. The reference it was pointing at had no reachable landing page at all. Delete the stub. The route is unchanged because both spellings always produced it; it now serves the reference that was being shadowed. Teach the authoring check to compare names rather than asking the filesystem. It derived the folder path and stat'ed it, which finds nothing on a case-sensitive volume and lets exactly this collision through — the one place it matters most, since that is what CI runs on.
The local-development principal fixture is an ASP.NET Core concern, and it sat at the shared level under a "General" section that held nothing else, so a JVM reader met a C#-only page among the pages that are meant to be true of Arc. Move it under C# and retire the section, redirecting both old routes. Signpost the JVM troubleshooting page from the shared one the same way the tutorial now does: the symptoms are the same on either backend, the fixes are not. Two pages linked to that section's index as though it documented domain concepts, when it was a one-row table about principals. Point them at the glossary, which actually defines the term.
Eight landing pages existed as routes but appeared in no table of contents, so the sidebar offered no way to reach them — the frontend overview, the Core and React overviews, the MVVM landing, and the ASP.NET Core, Arc.Core, MongoDB and Entity Framework section landings. A reader could only get there by deleting path segments in the address bar. Give each section an entry pointing at its own landing page. Nothing is unreachable from the navigation now.
Two shared pages showed C# without saying so. The standalone-slice walkthrough leans on the C# MongoDB integration and test library, and a CommandForm page showed a C# validator fragment as though it were the only way to declare the rule. Neither point is C#-specific — a slice needs no event log either way, and both backends generate the same client from the same kind of rule — so name the stack being shown and link to the JVM equivalent rather than leaving a reader to assume the page is not for them.
Same topics, same sequence: setup, then commands and queries, then authorization, identity and tenancy, then persistence, then the proxy boundary and its analysis, then testing and Chronicle. Only the order changes; no page moves and no URL changes.
The two backends are one product because they speak one protocol: a TypeScript client generated from C# has to work against a JVM backend. That contract was documented only from the JVM side, and the C# side had no equivalent page, so the one artifact that must be identical was described in a place half its audience would not look. State it once, verified against both implementations rather than inherited from either. Claims that could not be confirmed for C# are not asserted as contract; several moved to a section recording where the two genuinely differ, which until now could only be discovered by reading both repositories. One of those differences deserves attention rather than only documentation: the C# SSE control endpoints look a connection up by id and never check that the caller owns it, while the JVM compares the principal and tenant and returns 404 on a mismatch.
This was referenced Sep 21, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Arc has two backend implementations. The documentation was shaped for one, so a Kotlin or Java reader had nowhere to land and no way to tell which pages applied to them.
Added
[Key]and@CommandKey.Changed
backend/csharp/, and the two pages that only ever described the C# stack moved with them. Chronicle moved under C# as well, since it documents the .NET client exclusively. Every moved route is redirected.Fixed
Notes for review
This is one of three coordinated pull requests. Merge order matters: this and
Cratis/Arc.Kotlin#<pr>must land beforeCratis/Documentation#<pr>, because the documentation site checks out product repositories atmain.