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

2.8 KiB

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 nameAccessControl for both the schema constant and the inferred type (relies on TypeScript's value/type namespace separation)
  2. Different namesAccessControlSchema for the schema constant, AccessControl for the inferred type

Decision

Use the Schema suffix for schema constants. The inferred type uses the bare name.

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 ambiguityAccessControl 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