# ADR: The staff review

Status: accepted, 2026-09-02, shipped as 1.0.0.22.

## In plain words

This page reviews a whole day's code as one body of work (a staff review), looking for duplication between files and for the seams where one change assumed another. Every finding is written down with a verdict, the ones deliberately left alone included. The review repeats whenever a day's work is large enough to need it.

What that is worth: a developer starts the next review from the same page instead of rediscovering old choices, and the organization gets a written record of what was fixed and what was knowingly put off.

## Context

Ten versions shipped in one day, each reviewed on its own before its push.
Nobody had yet read the day's work as one body of code the way a staff
engineer reads a pull request: for duplication between files, for the
seams where one change assumed another, for the small things a fast day
leaves behind. Steve asked for a review in the role of
architect and staff engineer: review the code, make the corrections, and
write a record of the improvements. This record is that review. Every finding is listed,
including the ones deliberately left alone, so the next reviewer starts
from the same page.

## Decision

The review is a written pass with three verdicts: fixed (shipped in this
version, with a test where behavior changed), kept (a choice that stands,
with its reason), and deferred (worth doing, not today, with what it would
take). It repeats whenever a day's work is large enough to need it, and each
pass gets its own dated addendum here.

### Fixed

- **One endpoint for every document.** Program.cs had twenty routes, one
  per document, each naming its file, and three of them bypassed the
  live-sample expander. They are one route over a catalog now: the slug in
  the address is looked up in
  [`api/TheYard.Api/DocumentationCatalog.cs`](https://github.com/SteveStout/TheYard/blob/main/api/TheYard.Api/DocumentationCatalog.cs),
  the file is read from the repo root, and every document goes through
  the expander. A slug that is not in the catalog is a 404, never a file
  read. Adding a record is one line in the catalog and one in
  [`src/library/pages.ts`](https://github.com/SteveStout/TheYard/blob/main/src/library/pages.ts) or [`src/library/records.ts`](https://github.com/SteveStout/TheYard/blob/main/src/library/records.ts),
  and
  [`api/TheYard.Tests/DocumentationCatalogTests.cs`](https://github.com/SteveStout/TheYard/blob/main/api/TheYard.Tests/DocumentationCatalogTests.cs)
  fails the build when the two lists disagree, when a file is missing, or
  when any slug serves a live fence unexpanded. The directory walk that
  found the docs folder on every request is gone; the repo root is
  resolved once at startup.
- **The phone header's way home from Admin.** The brand button in the
  header called the list's back-to-inventory path, which does nothing while
  the Admin tab is showing; the sidebar's brand button knew to close Admin
  first. Both call the same home function now
  ([`src/app/hooks/useNavigation.ts`](https://github.com/SteveStout/TheYard/blob/main/src/app/hooks/useNavigation.ts)),
  and the phone spec proves the tap
  ([`tests/e2e/mobile.spec.ts`](https://github.com/SteveStout/TheYard/blob/main/tests/e2e/mobile.spec.ts)).
- **Honest failure states on the Admin tab.** A card whose fetch failed
  showed "Loading" forever. Each card now says it could not read its data
  and that the next try is thirty seconds away
  ([`src/components/admin/AdminPanel/AdminPanel.tsx`](https://github.com/SteveStout/TheYard/blob/main/src/components/admin/AdminPanel/AdminPanel.tsx)).
  An observability screen that cannot say "I do not know" is not one.
- **The observability types out of the host file.** The health record,
  the error buffer and the Azure reader lived at the bottom of Program.cs.
  They moved verbatim to
  [`api/TheYard.Api/Observability.cs`](https://github.com/SteveStout/TheYard/blob/main/api/TheYard.Api/Observability.cs),
  so Program.cs reads as a composition root: what is wired, not how each
  piece works. The live block in ADR: Observability follows them.
- **Build provenance read once.** The version and commit environment
  variables were read in two endpoints; they are read at startup beside
  the repo root and shared.
- **One brand mark.** The lightning bolt was drawn twice, in the sidebar
  and the phone header; it is one component,
  [`src/components/layout/BrandMark/BrandMark.tsx`](https://github.com/SteveStout/TheYard/blob/main/src/components/layout/BrandMark/BrandMark.tsx).
  The four link rows in the sidebar were the same markup four times; they
  are one `LinkRow` in
  [`src/components/layout/SideNav/SideNav.tsx`](https://github.com/SteveStout/TheYard/blob/main/src/components/layout/SideNav/SideNav.tsx).
  The section headings there were `h3` under a page with no `h2`; they are
  `h2`, and the block's indentation was straightened.
- **Tests clean up after themselves.** The live-sample tests created a
  temporary repository per test and left it in the temp folder; the test
  class now deletes what it made
  ([`api/TheYard.Tests/LiveSamplesTests.cs`](https://github.com/SteveStout/TheYard/blob/main/api/TheYard.Tests/LiveSamplesTests.cs)).
- **The pipeline's small safeties.** The Deploy job has a thirty-minute
  timeout, so a hung roll cannot hold the deploy-production concurrency
  group for the default six hours, and its Verify step asks the origin's
  readiness endpoint as well as its version
  ([`.github/workflows/deploy.yml`](https://github.com/SteveStout/TheYard/blob/main/.github/workflows/deploy.yml)).
  CI runs with a read-only token
  ([`.github/workflows/ci.yml`](https://github.com/SteveStout/TheYard/blob/main/.github/workflows/ci.yml)).

### Kept

- **The doc viewer caches each document for the life of the tab**
  ([`src/library/DocDialog.tsx`](https://github.com/SteveStout/TheYard/blob/main/src/library/DocDialog.tsx)).
  A deploy under an open tab is served on the next load, and the page is
  no-cache since ADR: Cache headers, so a reload is always fresh.
- **The rendered markdown is our own.** The viewer sets HTML from the
  markdown the API serves; the API serves only files in this repository,
  and the expander splices source into fenced blocks, which the renderer
  escapes. That trust boundary is the repository, and it is written down
  here so nobody widens the catalog to user-supplied content without
  reading this.
- **A deploy has about a minute of downtime.** The roll replaces the one
  container group; zero-downtime is the App Service slots story under
  Hosting, deliberately undeployed. The Verify step waits for the new
  build rather than pretending otherwise.
- **The Admin endpoints stay public**, as ADR: Observability decided.
- **The live-sample whitelist is a string check first**, then a resolved
  path check, then the read, in that order, with tests for each rejection
  ([`api/TheYard.Api/LiveSamples.cs`](https://github.com/SteveStout/TheYard/blob/main/api/TheYard.Api/LiveSamples.cs)).
  The review looked for a way around it and found none.

### Deferred

- **The slug list lives in two places**, the catalog and the sidebar
  record, held together by a test. A served catalog (titles, menus and
  slugs from the API) would make it one, at the cost of the sidebar
  rendering after a fetch. Worth it when a second client appears.
- **Documents are expanded on every request.** The files are small and
  the ground is a warm disk; a per-build cache keyed by file is a few
  lines when a measurement asks for it.
- **The health checks are file-existence probes** and read 0 ms. A probe
  that exercises the dataset (a search) would give the duration column
  something to say.

## In the code

The endpoint and the catalog, read from this build
([`api/TheYard.Api/Endpoints/DocumentationEndpoints.cs`](https://github.com/SteveStout/TheYard/blob/main/api/TheYard.Api/Endpoints/DocumentationEndpoints.cs)
and
[`api/TheYard.Api/DocumentationCatalog.cs`](https://github.com/SteveStout/TheYard/blob/main/api/TheYard.Api/DocumentationCatalog.cs)):

```csharp
// One route for every document (ADR-017): the slug is looked up in the catalog
// (DocumentationCatalog.cs, the same slugs src/library/records.ts and pages.ts carry), the file
// is read from the repo root and its live blocks are expanded (ADR-014). A slug
// missing from the catalog is a 404, never a file read. The Bicep file and the
// resume keep their own routes below because they are not markdown; a literal
// route wins over the {slug} pattern.
app.MapGet("/api/docs/{slug}", Document)
    .WithName("GetDocument")
    .WithTags("Documents")
    .WithSummary("One of the served documents, as markdown with its code samples expanded")
    .WithDescription("The slug is one the sidebar offers: readme, architecture, a record such as adr-openapi. "
        + "Every live block is read from this build at request time.")
    .Produces<string>(StatusCodes.Status200OK, "text/markdown")
    .ProducesProblem(StatusCodes.Status404NotFound);
```
*Live from [`api/TheYard.Api/Endpoints/DocumentationEndpoints.cs`](https://github.com/SteveStout/TheYard/blob/1d6b50b/api/TheYard.Api/Endpoints/DocumentationEndpoints.cs#L17-L30), region `docs-endpoint`, read from this build at 1d6b50b.*

```csharp
/// <summary>Slug to file, relative to the repo root. Every one goes through the live-sample expander (ADR-014).</summary>
public static readonly IReadOnlyDictionary<string, string> Files = new Dictionary<string, string>(StringComparer.Ordinal)
{
    ["readme"] = "README.md",
    ["start-here"] = "docs/app-architecture/START-HERE.md",
    ["clean-architecture"] = "docs/app-architecture/CLEAN-ARCHITECTURE.md",
    ["solid"] = "docs/app-architecture/SOLID.md",
    ["vscode"] = "docs/app-architecture/VSCODE.md",
    ["dataflow"] = "docs/app-architecture/DATAFLOW.md",
    ["sql-vs-cosmos"] = "docs/sql-vs-cosmos/SQL-VS-COSMOS.md",
    ["projects"] = "docs/app-architecture/PROJECTS.md",
    ["hosting"] = "docs/hosting/HOSTING.md",
    ["adr-origin"] = "docs/decisions/ADR-001-front-door-origin.md",
    ["adr-docker"] = "docs/decisions/ADR-002-docker-packaging.md",
    ["adr-naming"] = "docs/decisions/ADR-003-azure-naming.md",
    ["adr-pivots"] = "docs/decisions/ADR-004-deployment-pivots.md",
    ["adr-edge-economics"] = "docs/decisions/ADR-007-edge-economics.md",
    ["adr-linux"] = "docs/decisions/ADR-008-linux-containers.md",
    ["cicd"] = "docs/ci-cd/CICD.md",
    ["adr-pipeline"] = "docs/decisions/ADR-009-deploy-pipeline.md",
    ["practices"] = "docs/best-practices/BEST-PRACTICES.md",
    ["sealed"] = "docs/best-practices/SEALED.md",
    ["onion"] = "docs/best-practices/ONION.md",
    ["adr-versioning"] = "docs/decisions/ADR-005-version-footer.md",
    ["adr-docs"] = "docs/decisions/ADR-006-docs-and-testing.md",
    ["adr-observability"] = "docs/decisions/ADR-010-observability.md",
    ["adr-phone"] = "docs/decisions/ADR-011-phone-header.md",
    // #region docs-changelog
    // The changelog and its record (ADR-012): one file, one sentence per version.
    ["changelog"] = "docs/CHANGELOG.md",
    ["adr-changelog"] = "docs/decisions/ADR-012-changelog.md",
    // #endregion docs-changelog
    ["adr-sidebar"] = "docs/decisions/ADR-013-sidebar.md",
    ["adr-live-samples"] = "docs/decisions/ADR-014-live-samples.md",
    ["adr-caching"] = "docs/decisions/ADR-015-cache-headers.md",
    ["adr-palette"] = "docs/decisions/ADR-016-palette.md",
    ["adr-review"] = "docs/decisions/ADR-017-staff-review.md",
    ["adr-program"] = "docs/decisions/ADR-018-program-cs-explained.md",
    ["adr-react"] = "docs/decisions/ADR-019-react-configuration-explained.md",
    ["adr-diagrams"] = "docs/decisions/ADR-020-diagram-pages.md",
    ["adr-tests"] = "docs/decisions/ADR-021-tests-explained.md",
    ["adr-grouping"] = "docs/decisions/ADR-022-app-architecture-group.md",
    ["adr-errors"] = "docs/decisions/ADR-023-error-handling.md",
    ["adr-telemetry"] = "docs/decisions/ADR-024-telemetry.md",
    ["adr-search"] = "docs/decisions/ADR-025-search-index.md",
    ["adr-keyboard"] = "docs/decisions/ADR-026-keyboard.md",
    ["adr-bidders"] = "docs/decisions/ADR-027-competing-bidders.md",
    ["adr-style"] = "docs/decisions/ADR-028-style-enforced.md",
    ["adr-records"] = "docs/decisions/ADR-029-records-index.md",
    ["adr-exceptions"] = "docs/decisions/ADR-030-exception-handler.md",
    ["adr-version-source"] = "docs/decisions/ADR-031-version-from-changelog.md",
    ["adr-method"] = "docs/decisions/ADR-032-ai-development.md",
    ["adr-store"] = "docs/decisions/ADR-033-relational-store.md",
    ["adr-ef"] = "docs/decisions/ADR-034-entity-framework-explained.md",
    ["adr-a11y-check"] = "docs/decisions/ADR-035-accessibility-check.md",
    ["adr-photos"] = "docs/decisions/ADR-036-responsive-photos.md",
    ["adr-accounts"] = "docs/decisions/ADR-037-accounts.md",
    ["adr-identity"] = "docs/decisions/ADR-038-identity-explained.md",
    ["adr-sql-server"] = "docs/decisions/ADR-039-sql-server-backend.md",
    ["adr-data-first"] = "docs/decisions/ADR-040-database-source-control.md",
    ["adr-providers"] = "docs/decisions/ADR-041-two-providers-explained.md",
    ["adr-exemptions"] = "docs/decisions/ADR-042-exemptions-that-hide.md",
    ["adr-sql-visible"] = "docs/decisions/ADR-043-what-the-database-is-doing.md",
    ["adr-interceptors"] = "docs/decisions/ADR-044-interceptors-explained.md",
    ["adr-self-review"] = "docs/decisions/ADR-045-reviewing-my-own-work.md",
    ["adr-the-name"] = "docs/decisions/ADR-046-the-name.md",
    ["adr-second-manifest"] = "docs/decisions/ADR-047-the-second-manifest.md",
    ["adr-reset"] = "docs/decisions/ADR-048-reset-is-one-persons.md",
    ["adr-room-account"] = "docs/decisions/ADR-049-the-room-needs-an-account.md",
    ["adr-lockout"] = "docs/decisions/ADR-050-a-password-guess-should-cost-something.md",
    ["adr-coverage"] = "docs/decisions/ADR-051-counting-what-the-tests-cover.md",
    ["adr-where-gates-live"] = "docs/decisions/ADR-052-where-a-gate-lives.md",
    ["adr-public-face"] = "docs/decisions/ADR-053-the-public-face.md",
    ["adr-one-write"] = "docs/decisions/ADR-054-the-one-write-a-stranger-can-make.md",
    ["adr-broken-windows"] = "docs/decisions/ADR-055-broken-windows.md",
    ["adr-stale-listing"] = "docs/decisions/ADR-056-the-listing-that-went-stale.md",
    ["adr-record-address"] = "docs/decisions/ADR-057-a-record-with-no-address.md",
    ["adr-partition-key"] = "docs/decisions/ADR-058-the-partition-key.md",
    ["adr-second-store"] = "docs/decisions/ADR-059-a-second-store-priced.md",
    ["adr-ports-wait"] = "docs/decisions/ADR-060-the-ports-learn-to-wait.md",
    ["adr-accounts-documents"] = "docs/decisions/ADR-061-accounts-on-a-document-store.md",
    ["adr-store-visible"] = "docs/decisions/ADR-062-what-the-store-is-actually-doing.md",
    ["adr-backends"] = "docs/decisions/ADR-063-backends-side-by-side.md",
    ["adr-measuring-stores"] = "docs/decisions/ADR-064-measuring-both-stores.md",
    ["adr-cosmos-explained"] = "docs/decisions/ADR-065-cosmos-db-explained.md",
    ["adr-one-container"] = "docs/decisions/ADR-066-one-container-both-stores.md",
    ["adr-proof"] = "docs/decisions/ADR-067-same-performance-proven.md",
    ["adr-five-minute-gate"] = "docs/decisions/ADR-068-the-five-minute-gate.md",
    ["adr-second-address"] = "docs/decisions/ADR-069-a-permanent-address-for-the-second-site.md",
    ["adr-three-readers"] = "docs/decisions/ADR-070-three-readers-with-no-memory.md",
    ["adr-activity"] = "docs/decisions/ADR-071-site-activity.md",
    ["adr-secrets"] = "docs/decisions/ADR-072-the-code-is-public-the-secrets-are-not.md",
    ["adr-kept-logs"] = "docs/decisions/ADR-073-logs-that-outlive-the-container.md",
    ["adr-highlighting"] = "docs/decisions/ADR-074-code-that-reads-like-code.md",
    ["adr-rules"] = "docs/decisions/ADR-075-the-rules-a-change-has-to-pass.md",
    ["adr-openapi"] = "docs/decisions/ADR-076-the-api-describes-itself.md",
    ["adr-page-status"] = "docs/decisions/ADR-077-every-page-checked.md",
    ["adr-machines"] = "docs/decisions/ADR-078-what-the-machines-are-doing.md",
    ["adr-one-plan"] = "docs/decisions/ADR-079-one-plan-two-sites.md",
    ["adr-admin-product"] = "docs/decisions/ADR-080-the-admin-tab-as-a-product.md",
    ["adr-glass-look"] = "docs/decisions/ADR-081-the-glass-look.md",
    ["adr-landing-page"] = "docs/decisions/ADR-082-the-landing-page-and-the-site-map.md",
    ["adr-tweaks"] = "docs/decisions/ADR-083-the-tweaks-pass.md",
    ["adr-component-folders"] = "docs/decisions/ADR-084-one-folder-per-component.md",
    ["adr-kept-awake"] = "docs/decisions/ADR-085-kept-awake.md",
    ["adr-composition-root"] = "docs/decisions/ADR-086-the-composition-root-split-by-job.md",
    ["adr-azure-costs"] = "docs/decisions/ADR-087-what-azure-charges.md",
    ["adr-onion-and-solid"] = "docs/decisions/ADR-088-onion-and-solid.md",
    ["adr-technology-versions"] = "docs/decisions/ADR-089-technology-versions.md",
    ["adr-dotnet-10"] = "docs/decisions/ADR-090-staying-on-dotnet-10.md",
    ["adr-docs-folders"] = "docs/decisions/ADR-091-one-folder-per-sidebar-section.md",
    ["adr-render-at-build-time"] = "docs/decisions/ADR-092-render-at-build-time.md",
    ["adr-request-pipeline"] = "docs/decisions/ADR-093-the-order-of-the-request-pipeline.md",
    ["adr-compiled-before-it-ships"] = "docs/decisions/ADR-094-compiled-before-it-ships.md",
    ["adr-blue-green-measured-and-held"] = "docs/decisions/ADR-095-blue-green-measured-and-held.md",
    ["adr-a-rendering-service-beside-the-api"] = "docs/decisions/ADR-096-a-rendering-service-beside-the-api.md",
    ["adr-the-editor-is-set-up-by-the-repository"] = "docs/decisions/ADR-097-the-editor-is-set-up-by-the-repository.md",
    ["adr-the-gate-runs-where-the-memory-is"] = "docs/decisions/ADR-098-the-gate-runs-where-the-memory-is.md",
    ["adr-the-resume-has-an-address"] = "docs/decisions/ADR-099-the-resume-has-an-address.md",
    ["adr-one-reading-for-the-first-screen"] = "docs/decisions/ADR-100-one-reading-for-the-first-screen.md",
    ["style-guide"] = "docs/style/STYLE-GUIDE.md",
    ["color-style"] = "docs/style/COLOR-STYLE.md",
    ["background-ribbon"] = "docs/style/BACKGROUND-RIBBON.md",
    ["ui-architecture"] = "docs/style/UI-ARCHITECTURE.md",
    ["document-style"] = "docs/style/DOCUMENT-STYLE.md",
    ["author"] = "docs/author/AUTHOR.md",
    ["security"] = "docs/best-practices/SECURITY.md",
    ["react-server-rendering"] = "docs/best-practices/REACT-SERVER-RENDERING.md",
    ["ahead-of-time-compilation"] = "docs/best-practices/AHEAD-OF-TIME-COMPILATION.md",
    ["ai-development"] = "docs/about/AI-DEVELOPMENT.md",
    ["built-with-ai"] = "docs/built-with-ai/BUILT-WITH-AI.md",
    ["infrastructure-overview"] = "docs/performance/INFRASTRUCTURE-OVERVIEW.md",
    ["web-overview"] = "docs/performance/WEB-OVERVIEW.md",
    ["performance"] = "docs/performance/PERFORMANCE.md",
    ["site-traffic"] = "docs/site-traffic/SITE-TRAFFIC.md",
    ["traffic-who"] = "docs/site-traffic/TRAFFIC-WHO.md",
    ["traffic-kept"] = "docs/site-traffic/TRAFFIC-KEPT.md",
    ["traffic-found"] = "docs/site-traffic/TRAFFIC-FOUND.md",
    ["traffic-search-console"] = "docs/site-traffic/TRAFFIC-SEARCH-CONSOLE.md",
    ["architecture"] = "docs/app-architecture/ARCHITECTURE.md",
    ["style"] = "docs/app-architecture/STYLE.md",
};
```
*Live from [`api/TheYard.Api/DocumentationCatalog.cs`](https://github.com/SteveStout/TheYard/blob/1d6b50b/api/TheYard.Api/DocumentationCatalog.cs#L11-L152), region `docs-catalog`, read from this build at 1d6b50b.*

## Consequences

- Program.cs is shorter by the twenty routes and the four types, and every
  document is served the same way; the next record costs two lines and
  cannot be forgotten on the server without a red test.
- The Admin tab's three cards each have three states, and a reviewer can
  see all three in the component.
- Every record reachable from the sidebar and from
  /api/docs/{slug}; the files each one decided are listed in the record
  itself, so a code review starts from the record and lands on the lines.

## Addendum, 2026-09-02: the documents audited against the code

At the end of the second build day, Steve asked for every document to
match the code. A mechanical pass over all thirty-two served documents,
checked in six classes rather than by reading: every count (tests, records,
endpoints, projects, entries), every backticked file path, every route,
every named identifier, every stated fact that could be measured, and every
live fence's file and region.

Three of the six came back clean: no served document names a retired route,
all one hundred live fences resolve to a real file and a real region, and
every colour token named in a document exists in `tokens.css`.

Twelve claims had drifted, all of them in prose rather than in samples,
which is the live-sample rule working as intended. The one that mattered:
ADR: Program.cs, explained still described a rejected query as
`Results.BadRequest(new { error })`, which ADR: Error handling replaced with
ProblemDetails the same day. The rest were counts a later version moved
(tests 131 to 139, browser checks 24 to 25, "Seventeen records", "Eleven
entries", "the six rules", "three hundred lines"), a palette sentence in
the project structure that still said navy after the repaint, and ADR: Live
code samples describing the four original roots in its body while both of
its addenda recorded the widening.

The lesson is the same one the live samples answered for code: a number
written in prose is a claim with no test behind it. Where a count is
load-bearing it now reads as a range or points at the thing that counts it;
where it is decorative it was removed. The audit script is worth keeping in
the mentor notes and rerunning before any review.

## Addendum, 2026-09-23 (1.0.3.5): a document's pictures come from this site

Every markdown file names its pictures on GitHub's raw host, so the files read on GitHub as they are. Read here, through the sidebar, that meant every document's pictures came from a third host, and the README on a phone was 1,402 KB by the responses' own headers, 985 KB of it `infrastructure.png`, a render of the `infrastructure.svg` this site already serves at 17 KB (measured at 390 in Chrome on 1.0.3.4, three runs). Four of the drawings have an SVG source beside their PNG, and twenty served documents name a picture on that host.

So the served markdown names them here instead (`DocImages`, in DocImages.cs): the raw address becomes `/api/docs/images/{name}`, a PNG whose SVG source stands beside it is served as that SVG, and the new route reads a name held to one shape from `docs/images` and nowhere else, cached for a day like the photographs. The markdown files are untouched, which is what keeps them right on GitHub. The renderer marks every picture in a document lazy, so a document's text is not sharing the connection with a screenshot below its first screen. `DocumentationCatalogTests` holds the rewrite, the route, and that every picture a served document names is in the repository.

## Where it sits

The review's fixes land in the host Api and the front end: one documents endpoint now reads DocumentationCatalog.cs, the health and Azure types moved out of Program.cs into Observability.cs, and on the browser side one BrandMark and one home function. Moving those types out is single responsibility, so the host file only wires things up, and the catalog follows the open/closed principle because a new record is one line of data instead of a new route. The cost is a slug list kept in two places (the catalog and src/library) that DocumentationCatalogTests holds equal. A second client reading the same documents would justify serving the catalog from the API and dropping the copy.

## Files

- [`api/TheYard.Api/Endpoints/DocumentationEndpoints.cs`](https://github.com/SteveStout/TheYard/blob/main/api/TheYard.Api/Endpoints/DocumentationEndpoints.cs): one endpoint serving every document instead of twenty routes.
- [`api/TheYard.Api/DocumentationCatalog.cs`](https://github.com/SteveStout/TheYard/blob/main/api/TheYard.Api/DocumentationCatalog.cs): the slug-to-file catalog that endpoint reads.
- [`api/TheYard.Api/Observability.cs`](https://github.com/SteveStout/TheYard/blob/main/api/TheYard.Api/Observability.cs) and [`api/TheYard.Api/Replies.cs`](https://github.com/SteveStout/TheYard/blob/main/api/TheYard.Api/Replies.cs): the health and build types this review moved out of the host file.
- [`api/TheYard.Tests/DocumentationCatalogTests.cs`](https://github.com/SteveStout/TheYard/blob/main/api/TheYard.Tests/DocumentationCatalogTests.cs): the test that holds the catalog and the sidebar to the same list.
- [`src/library/documents.ts`](https://github.com/SteveStout/TheYard/blob/main/src/library/documents.ts): the sidebar's copy of that list, and the one brand mark this review deduplicated.
- [`.github/workflows/deploy.yml`](https://github.com/SteveStout/TheYard/blob/main/.github/workflows/deploy.yml): the timeout and the readiness check this review added to the pipeline.
- [`docs/decisions/ADR-075-the-rules-a-change-has-to-pass.md`](https://github.com/SteveStout/TheYard/blob/main/docs/decisions/ADR-075-the-rules-a-change-has-to-pass.md): the record that made this section a rule rather than a habit.
