taxonomy/vocabulary.project.taxonomy.md
taxonomy/vocabulary.project.taxonomy.md is a file in Coordination Surface. 205 lines of code and 0 definitions.
---
name: vocabulary
summary: The closed concern vocabulary this package draws from. Adding a word is a deliberate SSOT edit, never a convenience.
type: taxonomy
concern: governance
status: current
---
# Concern vocabulary
This file is the raw word list. The rules that turn it into a deterministic standard live in
`placement.project.taxonomy.md`, which is read first, and this file is the closed vocabulary it draws
from.
The machine-readable form is `taxonomy.config.ts`. That file is authoritative for the gate, and this
one is authoritative for a reader. The two are cross-checked, so **a tag in one and not the other is a
bug in whichever drifted.**
**The SSOT holds data, not reasoning.** It carries the declarations a rule reads. Every rule _about_
those declarations lives here, because a rule written into a config is a document disguised as a
schema, and no code ever reads it.
## Scope
The concern set covers the files this package authors: contracts, rules, models, processing stages,
reports, entry points and templates. A family that classifies nothing is left out, because unused
words make the real set harder to search. A host that authors a new kind of file adds its family by an
edit to `taxonomy.config.ts`, following the steps under _Adding a word is the last resort_.
## How a word is read: position, not membership
Resolution is **positional, not lexical**. The concern is the last dot-segment before the extension,
the subject is the first, and the variant sits between. A word is read by the slot it lands in, never
by which array declares it.
- **The concern slot** takes a declared concern tag, from a closed set.
- **The subject slot** takes any declared subject **or any concern tag**, because a file may be about
a class of things: a registry of rules, a validator of schemas.
- **The variant slot** takes a word from `variants` ∪ `subjects`, declared like every other slot.
- **The subject must not equal the concern.** `config.config.ts` is degenerate, because its subject
carries no information.
The legal subject set is `subjects` ∪ every concern tag, so `subjects` lists only domain nouns that
are **not already concerns**, and the config's type assertions fail on a redundant redeclaration.
A concern word in the subject slot is legal only when the file's target _is_ that class of thing.
`rule.registry.ts` is a registry of rules. It does not license `rule.cache.ts` to mean "a cache that
internally holds rules", which would be a variant disguised as a subject.
**A hyphen inside a slot is spelling, and the dot is the only separator.** Names are kebab-case
throughout. A folder carries one word and never a dot.
## Adding a word is the last resort
**An undeclared word is not a license to add it.** The steps are worked in order.
1. **Pick an existing word.** The vocabulary is small on purpose. Most undeclared words are a
synonym, an abbreviation, or a process-name for something already declared.
2. **Reason the word.** Subject = a noun naming a thing the system has. Variant = a noun that
narrows a subject. Concern = a role a file plays. Container = a grouping of modules. The reasoning
states which and why from the word's own meaning, never from where the file currently sits.
3. **Apply the is-a test.** Does a file IS-A this word? Then it is a role → `concerns`. Does the
system merely HAS-A it? Then it is a domain noun → `subjects`.
4. **If it fails the reasoning, the filename is wrong.** The file is renamed, and the vocabulary is
not bent to fit a bad name.
5. **If the file has two roles, the file is wrong.** It is split, because the ambiguity is the finding.
6. **Only if it survives, propose it.** A word is approved after the reasoning is shown, never
silently, never in bulk and never to make a check pass.
### Reject on sight
1. **Nominalized verbs and processes**, which name what the system does rather than what it has.
2. **Adjectives**, because no slot takes them.
3. **Plurals as subjects**, because a subject is singular.
4. **Abbreviations duplicating a real word.**
5. **Grouping labels** such as `misc`, `common`, `shared`, `core` and `util`, which name a bucket rather
than a thing. This governs the subject slot, since a grouping is exactly what a container is for.
`base` is exempt, as described below.
6. **Measurements and properties**, which are data rather than files.
7. **Generic catch-alls** such as `util`, `helper`, `handler`, `manager` and `thing`. They exclude
nothing, so they classify nothing.
8. **Instance ids**, because registry entries are content rather than vocabulary.
9. **A word overlapping an existing entry.**
10. **A compound that swallowed a concern**, where the tail is the concern and the head is the subject.
> `util`, `helper` and `handler` are not declared as concerns, because each is a generic catch-all
> under the list above. A file reaching for `handler` takes `processor`, `coordinator` or
> `service` by what it actually does.
**`manager` is not a concern.** It names a stature, not a role, which is why it attaches to lifecycle
owners, caches, registries and coordinators alike. It resolves to `coordinator` (owns a lifecycle,
drives collaborators) or `service` (stateful capability). A file that cannot choose is doing both, and
it is split.
**`base` is the one sanctioned generic subject.** It means the file is generic over its subject and
would be byte-identical in any domain. Both tests must hold: the file is generic over its type
parameters, and it names no domain noun anywhere in its source. A file mentioning any domain noun
takes that noun instead. `base` is not a home for files that resist classification.
## The concerns
Each tag carries exactly one canonical layer. The spine is
`domain > application > processing > runtime > infrastructure > operations > product`, ordered
domain-ward, and used **only as a tie-break**. It is the classification axis, what kind of thing a
file is, and says nothing about who may depend on whom.
### Structure and contract: infrastructure and domain
| folder | file tag | layer |
| ---------------- | ----------------- | -------------- |
| `contracts` | `.contract.` | infrastructure |
| `specifications` | `.specification.` | domain |
| `schemas` | `.schemas.` | infrastructure |
| `types` | `.types.` | infrastructure |
| `constants` | `.constants.` | infrastructure |
| `strings` | `.strings.` | infrastructure |
| `predicates` | `.predicate.` | infrastructure |
| `guards` | `.guard.` | infrastructure |
### Dependency and extension: infrastructure
| folder | file tag |
| ------------ | ------------ |
| `registries` | `.registry.` |
| `resolvers` | `.resolver.` |
| `loaders` | `.loader.` |
| `factories` | `.factory.` |
| `manifests` | `.manifest.` |
| `bindings` | `.binding.` |
| `plugins` | `.plugin.` |
| `config` | `.config.` |
| `caches` | `.cache.` |
### Domain modeling: domain
| folder | file tag |
| ------------- | -------------- |
| `rules` | `.rule.` |
| `policies` | `.policy.` |
| `models` | `.model.` |
| `invariants` | `.invariant.` |
| `constraints` | `.constraint.` |
| `records` | `.record.` |
| `collections` | `.collection.` |
| `snapshots` | `.snapshot.` |
### Application services: application
| folder | file tag |
| --------------- | ---------------- |
| `coordinators` | `.coordinator.` |
| `orchestrators` | `.orchestrator.` |
| `services` | `.service.` |
| `stages` | `.stage.` |
| `steps` | `.step.` |
### Serialization and processing: processing
| folder | file tag |
| -------------- | --------------- |
| `readers` | `.reader.` |
| `writers` | `.writer.` |
| `transformers` | `.transformer.` |
| `normalizers` | `.normalizer.` |
| `formatters` | `.formatter.` |
| `pipelines` | `.pipeline.` |
| `processors` | `.processor.` |
| `filters` | `.filter.` |
| `validators` | `.validator.` |
| `matchers` | `.matcher.` |
| `comparators` | `.comparator.` |
| `iterators` | `.iterator.` |
| `generators` | `.generator.` |
| `analyzers` | `.analyzer.` |
| `inspectors` | `.inspector.` |
### Failure and reporting: operations
| folder | file tag |
| ----------- | ------------ |
| `errors` | `.error.` |
| `results` | `.result.` |
| `reporters` | `.reporter.` |
| `reports` | `.report.` |
| `taxonomy` | `.taxonomy.` |
### Runtime and product
| folder | file tag | layer |
| ------------- | -------------- | ------- |
| `entrypoints` | `.entrypoint.` | runtime |
| `runners` | `.runner.` | product |
| `fixtures` | `.fixture.` | product |
| `references` | `.reference.` | product |
| `templates` | `.template.` | product |
### Plurality
| form | folder | file tag | example |
| ----------------------------------------------- | -------- | ---------- | ---------------------------------------- |
| collection, where one file defines many members | plural | **plural** | `schemas/` ⇒ `record.schemas.ts` |
| single-unit, with one instance per file | plural | singular | `validators/` ⇒ `placement.validator.ts` |
| mass or uncountable | singular | singular | `config/`, `taxonomy/` |
The collection concerns here are `schemas`, `types`, `constants` and `strings`, and the mass concerns
are `config` and `taxonomy`. Everything else is single-unit.
## Covered by a meta concern, and not added
The rejected list is the useful half of a closed vocabulary. Each entry reads like a deployment
concern and is already an agnostic one.
| tempting tag | classify as | why |
| ------------------------------ | --------------------------------------- | ------------------------------------------ |
| `checker`, `linter` | `validator` | it decides valid or invalid |
| `scanner` | `analyzer` or `inspector` | it reads and derives, it does not judge |
| `parser`, `lexer`, `tokenizer` | `reader` | it turns a format into structure |
| `fixer`, `healer`, `repairer` | `transformer` | it maps input state to output state |
| `walker`, `crawler` | `iterator` | it yields members of a set |
| `gate` | `predicate` or `validator` | a gate is a decision, not a thing |
| `index` | `registry` | a lookup structure is a registry |
| `helper`, `util` | none, because the file has a real role | find it and name it |
| `manager` | `coordinator` or `service` | split by what it actually does |
| `handler` | `processor` or `coordinator` | it names stature, not role |
| `doc`, `guide`, `note` | `reference` | authored knowledge is a reference |
| `digest`, `summary` | `reference` or `rule` | by whether it informs or obliges |
| `checklist`, `plan` | `specification` | it declares required end state |
| `inventory` | `registry` | a named set of known members |
| `changelog` | none, because it is structurally exempt | history has one home, outside the taxonomy |
`digest` can mean a cryptographic hash or a rule summary. Declaring it would collide two meanings on
one tag, so it is declared neither way: a rule expansion is a `rule`, and a knowledge summary is a
`reference`.
## The subjects
**The subject array is the one slot whose members are a project's own nouns**, so it is not listed
here. It lives in the configuration, where a host adds what it has and nothing else. A subject list
transcribed into prose is a second vocabulary that disagrees with the compiled one the first time
either moves, and the compiled one is the copy the assertions check.
One rule decides what the array holds, and it is the same in every host: **a noun the host actually
has, excluding every word already a concern tag.** A word that names stature rather than substance,
such as a manager, a handler, a helper or a util, classifies nothing and is refused whatever the host.
The array is closed. An undeclared word is an approved edit to the configuration, never a naming choice
made at authoring time, and the cross-slot assertions compiled beside it reject a subject that shadows a
concern tag before a single file is placed.
## The variants
`comms` · `project` · `protocol`
A variant is present only on a genuine collision within one folder, or to name a facet the subject
alone does not. No collision and no facet means one compound kebab subject and no variant.