Files
operations/docs/architecture/decisions/004-schema-const-naming.md
glm-5.1 29f0dd7af0 Initial package implementation: operations registry, call protocol, and adapters
Extracted from alkhub_ts packages/core/operations/ and packages/core/mcp/.
- Runtime-agnostic (injected fs/env deps, no Deno globals)
- Direct @logtape/logtape import instead of logger wrapper
- PendingRequestMap with pubsub-wired call protocol
- Peer-dep isolation for MCP adapter (sub-path export)
- Schema const naming convention (XSchema + X type alias)
- 68 tests passing, build + lint + test all green
2026-04-30 12:34:26 +00:00

50 lines
2.8 KiB
Markdown

# ADR-004: Schema Const Naming Convention
**Status**: Accepted
**Date**: 2026-04-30
## Context
TypeBox schemas and their inferred types need different names but represent the same concept. For example, the `AccessControl` schema defines the runtime shape and the `AccessControl` type provides the TypeScript interface. Using the same name for both creates a naming collision.
Two naming conventions are common in TypeBox codebases:
1. **Same name**`AccessControl` for both the schema constant and the inferred type (relies on TypeScript's value/type namespace separation)
2. **Different names**`AccessControlSchema` for the schema constant, `AccessControl` for the inferred type
## Decision
Use the `Schema` suffix for schema constants. The inferred type uses the bare name.
```ts
export const AccessControlSchema = Type.Object({ ... })
export type AccessControl = Static<typeof AccessControlSchema>
export const OperationSpecSchema = Type.Object({ ... })
export type OperationSpec = Static<typeof OperationSpecSchema>
export const ErrorDefinitionSchema = Type.Object({ ... })
export type ErrorDefinition = Static<typeof ErrorDefinitionSchema>
export const OperationDefinitionSchema = Type.Object({ ... })
export interface IOperationDefinition<...> extends OperationSpec<...> { ... }
```
## Rationale
1. **No ambiguity**`AccessControl` always refers to the type, `AccessControlSchema` always refers to the runtime schema. No mental overhead to distinguish them.
2. **TypeScript namespace separation is fragile** — while TypeScript technically allows the same name for a value and a type (they occupy different namespaces), this creates confusion when reading code. `const ac: AccessControl = ...` — which `AccessControl`? The schema or the type? With the `Schema` suffix, it's immediately clear.
3. **Consistent with TypeBox conventions** — TypeBox's own `Type.*` factory functions produce schema objects. Naming the const with a `Schema` suffix aligns with the mental model that these are schema definitions, not data instances.
4. **Export clarity** — in `index.ts`, both are exported. Having distinct names means `import { AccessControlSchema, AccessControl }` is immediately clear: one is a runtime value, one is a type.
5. **Existing pattern** — this convention is already used in `OperationDefinitionSchema` vs `IOperationDefinition` and `OperationSpecSchema` vs `OperationSpec` in the codebase.
## Consequences
- All schema const names end in `Schema`
- All type names are the bare concept name (or prefixed with `I` for interfaces)
- This applies to `AccessControlSchema`/`AccessControl`, `ErrorDefinitionSchema`/`ErrorDefinition`, `OperationContextSchema`/`OperationContext`, `OperationSpecSchema`/`OperationSpec`, `OperationDefinitionSchema`/`IOperationDefinition`
- When adding new schemas, follow this convention: `FooSchema` for the const, `Foo` for the type