2026-08-07 — Documentation tags and the type layout
Two passes over the source ahead of the 1.0.0 tag, both structural rather than behavioural. No exported symbol changed:
lib/index.d.ts carries the same 42 names before and after.
Kind tags lead the block
Every doc block opened with its summary and carried its kind tag — @class, @interface, @typedef, @module,
@constant, @function — near the bottom, wedged between the last @typeParam and @author. The tag now comes first:
/**
* @class
*
* A limiter that counts nothing.
* ...
*/
54 files: the 52 under src/, plus eslint.config.ts and rollup.config.ts. Two blocks carried no kind tag at all —
eslint.config.ts's default export and rollup.config.ts's header — and were given @constant and @module.
The nine test/**/*.spec.ts files were left alone. Their top block documents a describe() call rather than an
exported declaration, and they sit outside both TypeDoc's entry points and ESLint's files list, so a tag there would
be inert.
Not enforced yet. The documentation plugin already carries kind-tag-without-argument, which checks that a kind tag
has no argument but not that one exists or leads the block. A fourth rule would close the gap; without one this holds
only as long as everyone remembers it, which is the same reason the other three exist.
types/ grouped into subdirectories
types/capabilities/ had grown to 21 flat files, over half of them supporting shapes rather than capabilities. A
capability that owns shapes now gets a directory and takes them with it:
| Directory | Contents |
|---|---|
object/ |
ObjectStore, StoredObject |
request/ |
RequestMetadata, RequestFacts |
sql/ |
DataStore, SqlConnectionProvider, SqlCredentials, SqlStatement, SqlTarget, SqlWriteResult |
telemetry/ |
TelemetrySink, RequestMetric |
vector/ |
VectorIndex, VectorMatch |
Capability stays at the root, along with the five capabilities that are a single interface each — CacheStore,
CoordinationStore, InferenceEngine, MessageQueue, RateLimiter. A subject with one shape to its name does not
earn a directory.
Membership follows what a shape belongs to rather than what it is named, which is worth stating because two of the placements read as wrong at a glance:
RequestMetricis undertelemetry/, not with the two types that share its prefix.TelemetrySinkis the only thing that accepts one, andrequest/is otherwise about deciding which header may be believed.DataStoreis undersql/. It is relational storage addressed with SQL and it importsSqlStatementandSqlWriteResult; leaving it flat would have split the SQL surface across two levels.
Under types/ itself, logging/ now holds LogLevel and LogContext. LoggingSettings stays at the root beside
SecuritySettings and SystemConfiguration — it is read through resolve('logging') like any other settings shape —
and is re-exported through logging/index.ts, so the grouping shows up in the barrel without splitting the
configuration shapes across two directories.
Each new directory has an index.ts with a @module block, matching core/noop/, and the parent barrels re-export
from the directory rather than reaching into files. SqlTarget's relative link to SqlCredentials survived the move
untouched; LogLevel's link to Logger needed a second ../.
SecuritySettings, SystemConfiguration, and Overrides are the one cluster left flat. A configuration/ directory
would finish the pattern and is deliberately deferred rather than forgotten.
Verification
npm run lint, npm run test:run (85 specs, nine suites), npm run build, and npm run build:docs all clean. The
docs build is the one that matters for a move of this size: typedoc.json sets treatWarningsAsErrors alongside
validation.invalidLink, so a relative link left pointing at an old path fails the build rather than shipping as a
dead link.