Skip to content

The product is filed under a few domains, and a feature names its one

The product is filed under a few domains, and a feature names its one

majordomus://adr/adr-0104proposed architecturetaxonomyprojectionsproduct

it references

referenced by

Nothing in the layer names it. Backlinks are derived, so an empty list is an answer rather than an omission.

104. The product is filed under a few domains, and a feature names its one

Context

ADR 0023 made every product feature an object of the layer and the landing page a projection of them. It did not give the product a shape above the feature. The homepage's "what it does" section therefore grouped the features by the only taxonomy the layer had, the operational areas of the why catalogue, and listed every stable feature under every area it serves. Measured on the tree this decision was written against: twenty-six stable features, nine areas, fourteen features under two or three areas each, one area holding a single feature and one holding no feature as its first area. A first-time reader met a flat inventory, with the same feature repeated, and was left to derive the product model from it.

The areas are the wrong instrument for that job, and deliberately so. An area is a part of operations a moment is filed under: where it hurts. Membership is many-to-many on purpose — a feature that answers pain in two parts of operations belongs in both diagnoses — and the Cockpit derives a module's area from it (ADR 0026). Re-cutting the nine areas down to six to serve a product map would have changed every moment's filing, the diagnosis a reader's symptoms resolve to and the Cockpit's sidebar, to answer a question none of them asks.

The question the product map asks is the other one: what does the product control? That is a partition, not a diagnosis — each feature has one place in the answer, and the answer has few parts so that a reader can hold it.

Decision

A domain is an object of the layer: .ai/repo/features/domains/<id>.md, kind domain, schema domain/v1. It states its title, a one-sentence headline (what the product does about it), a one-sentence problem (the failure it answers), its status and its weight (the presentation order). Its body says what it covers and what it does not.

A feature names exactly one domain in its own domain field. The domain lists nothing. Its members, the interfaces they reach, the distinct claims, use cases, rules and capabilities behind them and the moments they answer are derived by crate::product from the features that name it, exposed as the capability product.domains (command line, HTTP, MCP), and published in product.json through an allow-list, as features are.

The references run one way and are held both ways:

  • a domain a feature names that does not exist is an unknown_reference error, with the nearest candidate;
  • a stable feature that names no domain while the layer declares any is an error (unassigned_domain), because every surface that presents the product by domain would otherwise leave it out without saying so;
  • a stable feature filed under a domain that is not stable is an error (draft_domain);
  • a stable domain no stable feature names is a warning (empty_domain), and is shown nowhere.

The areas keep their job. A feature still names the areas it serves; the why catalogue, the diagnosis and the Cockpit are unchanged.

Why this is not a new noun

project.no-new-nouns refuses agents, personas, roles, tiers and registries. A domain is none of these: it is a taxonomy of the product's own features, an object of the same mechanism as a feature or an area (a kind, a schema, a source class), carrying no state, assigning no work and naming no worker. It is entered in docs/CONCEPTS.md beside feature, so the vocabulary stays the whole vocabulary.

Consequences

  • The homepage can show a small, stable product model whose membership nobody maintains: a feature added under a domain appears in that domain's map entry and on its page with no other edit, and one removed disappears the same way.
  • A domain page (/domains/<id>/) and a breadcrumb on every feature page become derivable.
  • Choosing a feature's domain is an editorial act, like choosing its weight, and is reviewed as one. The six domains this decision was written with — context, coordination, governance, evidence, completion, surfaces — are data, not part of the decision.
  • Repositories that declare no domain are unaffected: nothing is required of their features.

Where this comes from

canonical file
.ai/repo/adrs/0104-the-product-is-filed-under-a-few-domains-and-a-feature-names-its-one.md
identity
adr-0104
also served as
MCP resource majordomus://adr/adr-0104 · majordomus entity show adr/adr-0104 · GET /api/v1/entity?uri=majordomus://adr/adr-0104
in the Cockpit
/cockpit/objects/adr/adr-0104

This page is generated from the file above by scripts/generate-site-data; editing the page changes nothing, editing the file changes every surface. The relations above are edges of docs/generated/graph.json, which the executable writes from the same index.

Searches the titles and descriptions of every page this site publishes.