@ontrails/core 1.0.0-beta.42 → 1.0.0-beta.45

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,41 @@
1
1
  # @ontrails/core
2
2
 
3
+ ## 1.0.0-beta.45
4
+
5
+ ### Patch Changes
6
+
7
+ - [`f9533a4`](https://github.com/outfitter-dev/trails/commit/f9533a4ef7392201c71d7f751361b4f7177eeacb): Keep public error projection shared and redacted while using transport-neutral CLI vocabulary and preserving safe topo diagnostics in structured output.
8
+
9
+ ## 1.0.0-beta.44
10
+
11
+ ### Patch Changes
12
+
13
+ - [`b1fbe57`](https://github.com/outfitter-dev/trails/commit/b1fbe574e6f44d1fecb5e3a000270955c0a77b7b): Publish Bun-validated package tarballs through an npm trusted-publishing adapter
14
+ binding, add exact repository metadata for each public workspace package, and
15
+ correct the native Bun release descriptor to its pack-only runtime boundary.
16
+
17
+ ## 1.0.0-beta.43
18
+
19
+ ### Minor Changes
20
+
21
+ - [`88a6a62`](https://github.com/outfitter-dev/trails/commit/88a6a62a9e9e230ca6d368fa78dc3ece6c816204): Complete the v1 classification-first cutover from projection/project vocabulary
22
+ to derive/derived for contract-owned fact production and render/rendered for
23
+ surface presentation. Public type, helper, rule, relation, and report names move
24
+ without compatibility aliases; ordinary repository/project nouns remain
25
+ explicit preserves or structured review inventory.
26
+
27
+ ### Patch Changes
28
+
29
+ - [`113aed6`](https://github.com/outfitter-dev/trails/commit/113aed62d20041e35b0cf9d6c1b1a18df4b88f57): Rename the dependency-light observability owner from `@ontrails/observe` to
30
+ `@ontrails/observability` as a pre-v1 hard cut. Update dependent packages,
31
+ documentation, package discovery, and the governed Regrade route; no
32
+ compatibility package or old import route is retained.
33
+ - [`0938e7b`](https://github.com/outfitter-dev/trails/commit/0938e7badc0c5470d194139d642b673658d099e0): Fold the removed `@ontrails/tracing` package into the truthful existing
34
+ owners: intrinsic trace contracts remain in core, developer-state tooling now
35
+ lives at `@ontrails/observability/dev`, and the dependency-light OTel adapter
36
+ lives at `@ontrails/observability/otel`. There is intentionally no root-package
37
+ compatibility redirect because the former root had more than one owner.
38
+
3
39
  ## 1.0.0-beta.42
4
40
 
5
41
  ## 1.0.0-beta.41
package/README.md CHANGED
@@ -139,7 +139,7 @@ Dynamic classes:
139
139
  - `RetryExhaustedError` inherits category and surface codes from its wrapped `TrailsError`; retryable is always No.
140
140
  <!-- error-taxonomy:end -->
141
141
 
142
- Public surface projections redact sensitive substrings before exposing a non-internal `TrailsError` message. Internal-category `TrailsError` instances and unknown native errors project with the generic message `Internal server error`; diagnostics and serialized payloads keep their useful structure while redacting messages, context, and stack strings.
142
+ Public surfaces share one redacted rendering contract before applying surface codes. Sensitive substrings are removed from non-internal `TrailsError` messages. Internal-category `TrailsError` instances and unknown native errors remain opaque: HTTP, MCP, and library boundaries use `Internal server error`, while CLI uses the transport-neutral `Internal error`. Diagnostics and serialized payloads keep their useful structure while redacting messages, context, and stack strings.
143
143
 
144
144
  The developer returns `Result.err(new NotFoundError(...))`. The framework maps it to the right code on every surface.
145
145
 
@@ -161,9 +161,9 @@ The developer returns `Result.err(new NotFoundError(...))`. The framework maps i
161
161
 
162
162
  The root package also exposes a few low-level contracts that other framework packages build on:
163
163
 
164
- - **Intrinsic tracing** -- `TraceRecord`, `TraceSink`, `TraceContext`, and the sink registry helpers are the core-owned execution record shape shared by `@ontrails/observe`, `@ontrails/tracing`, and adapters.
164
+ - **Intrinsic tracing** -- `TraceRecord`, `TraceSink`, `TraceContext`, and the sink registry helpers are the core-owned execution record shape shared by `@ontrails/observability` and adapters.
165
165
  - **Trails DB** -- `deriveTrailsDbPath`, `deriveTrailsStateDir`, `deriveTrailsStateHome`, `deriveTrailsProjectKey`, `deriveTrailsDir`, `ensureSubsystemSchema`, `openReadTrailsDb`, and `openWriteTrailsDb` are the generic database primitive used by framework subsystems.
166
- - **Surface projection helpers** -- safe error projection, layer field projection, compose-batch validation, late-bound signal references, and Zod default-wrapper stripping are stable root exports for first-party surfaces, store helpers, and tests.
166
+ - **Surface rendering helpers** -- safe error rendering, layer field rendering, compose-batch validation, late-bound signal references, and Zod default-wrapper stripping are stable root exports for first-party surfaces, store helpers, and tests.
167
167
 
168
168
  See the [API Reference](../../docs/api-reference.md) for the full list.
169
169
 
package/package.json CHANGED
@@ -1,6 +1,11 @@
1
1
  {
2
2
  "name": "@ontrails/core",
3
- "version": "1.0.0-beta.42",
3
+ "version": "1.0.0-beta.45",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "git+https://github.com/outfitter-dev/trails.git",
7
+ "directory": "packages/core"
8
+ },
4
9
  "files": [
5
10
  "src/**/*.ts",
6
11
  "!src/**/__tests__/**",
@@ -3,7 +3,7 @@ import { zodToJsonSchema } from './validation.js';
3
3
 
4
4
  type ZodSchemaInput = Parameters<typeof zodToJsonSchema>[0];
5
5
 
6
- export type ActivationSourceProjection = Readonly<Record<string, unknown>> & {
6
+ export type ActivationSourceFacts = Readonly<Record<string, unknown>> & {
7
7
  readonly id: string;
8
8
  readonly key: string;
9
9
  readonly kind: string;
@@ -113,9 +113,9 @@ const normalizeWebhookMethod = (method: string | undefined): string =>
113
113
 
114
114
  const normalizeWebhookPath = (path: string): string => path.trim();
115
115
 
116
- export const projectActivationSourceDeclaration = (
116
+ export const deriveActivationSourceFacts = (
117
117
  source: ActivationSource
118
- ): ActivationSourceProjection => {
118
+ ): ActivationSourceFacts => {
119
119
  const record: Record<string, unknown> = {
120
120
  id: source.id,
121
121
  key: activationSourceKey(source),
@@ -172,7 +172,7 @@ export const projectActivationSourceDeclaration = (
172
172
  record['hasVerify'] = true;
173
173
  }
174
174
 
175
- return sortKeys(record) as ActivationSourceProjection;
175
+ return sortKeys(record) as ActivationSourceFacts;
176
176
  };
177
177
 
178
178
  /**
@@ -182,8 +182,8 @@ export const projectActivationSourceDeclaration = (
182
182
  * returned token captures the function's reference identity so it changes when
183
183
  * the verifier function changes.
184
184
  *
185
- * The token is intentionally kept out of {@link projectActivationSourceDeclaration}
186
- * so that the persisted topo-store projection remains stable and free of
185
+ * The token is intentionally kept out of {@link deriveActivationSourceFacts}
186
+ * so that the persisted topo-store facts remains stable and free of
187
187
  * nondeterministic function identity. Use this only for in-memory comparisons
188
188
  * (validation, conflict detection).
189
189
  */
@@ -218,10 +218,10 @@ const verifierIdentityToken = (
218
218
  export const activationSourceDeclarationSignature = (
219
219
  source: ActivationSource
220
220
  ): string => {
221
- const projection = projectActivationSourceDeclaration(source);
221
+ const facts = deriveActivationSourceFacts(source);
222
222
  const verifyToken = verifierIdentityToken(source);
223
223
  if (verifyToken === undefined) {
224
- return JSON.stringify(projection);
224
+ return JSON.stringify(facts);
225
225
  }
226
- return JSON.stringify({ projection, verify: verifyToken });
226
+ return JSON.stringify({ facts, verify: verifyToken });
227
227
  };
package/src/blob-ref.ts CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  import { z } from 'zod';
6
6
 
7
- /** Metadata key used to recognize BlobRef schemas during JSON Schema projection. */
7
+ /** Metadata key used to recognize BlobRef schemas during JSON Schema derivation. */
8
8
  export const BLOB_REF_SCHEMA_META_KEY = 'ontrails/blob-ref';
9
9
 
10
10
  /** Immutable reference to a blob of binary data. */
@@ -15,7 +15,7 @@ export interface BlobRef {
15
15
  readonly data: Uint8Array | ReadableStream<Uint8Array>;
16
16
  }
17
17
 
18
- /** Schema-projected metadata for a BlobRef value. */
18
+ /** Schema-derived metadata for a BlobRef value. */
19
19
  export interface BlobRefDescriptor {
20
20
  readonly kind: 'blob';
21
21
  readonly mimeType: string;
@@ -74,7 +74,7 @@ export const isBlobRef = (value: unknown): value is BlobRef => {
74
74
  );
75
75
  };
76
76
 
77
- /** Zod schema for runtime BlobRef values with metadata for descriptor projection. */
77
+ /** Zod schema for runtime BlobRef values with metadata for descriptor derivation. */
78
78
  export const blobRefSchema = z
79
79
  .custom<BlobRef>(isBlobRef, { error: 'Expected BlobRef' })
80
80
  .meta({ [BLOB_REF_SCHEMA_META_KEY]: true });
package/src/derive.ts CHANGED
@@ -51,7 +51,7 @@ export interface FieldOverride {
51
51
  }
52
52
 
53
53
  // ---------------------------------------------------------------------------
54
- // CLI command route projection
54
+ // CLI command route rendering
55
55
  // ---------------------------------------------------------------------------
56
56
 
57
57
  /** Authored CLI command path shape. Strings are split on whitespace. */
@@ -71,8 +71,8 @@ export type CliCommandRouteSource = 'derived' | 'trail' | 'surface';
71
71
  /** Whether a resolved CLI command route is canonical or an alias. */
72
72
  export type CliCommandRouteKind = 'alias' | 'canonical';
73
73
 
74
- /** Trail-authored CLI projection metadata. */
75
- export interface TrailCliProjection {
74
+ /** Trail-authored CLI rendering metadata. */
75
+ export interface TrailCliRendering {
76
76
  readonly aliases?: readonly CliCommandAliasInput[] | undefined;
77
77
  readonly path?: CliCommandPathInput | undefined;
78
78
  }
@@ -85,18 +85,18 @@ export interface CliCommandRoute {
85
85
  readonly target: string;
86
86
  }
87
87
 
88
- /** Resolved CLI projection for one trail. */
89
- export interface TrailCliCommandProjection {
88
+ /** Resolved CLI rendering for one trail. */
89
+ export interface TrailCliCommandRendering {
90
90
  readonly path: readonly string[];
91
91
  readonly routes: readonly CliCommandRoute[];
92
92
  }
93
93
 
94
- interface TrailCliProjectionInput {
95
- readonly cli?: CliCommandPathInput | TrailCliProjection | undefined;
94
+ interface TrailCliRenderingInput {
95
+ readonly cli?: CliCommandPathInput | TrailCliRendering | undefined;
96
96
  readonly id: string;
97
97
  }
98
98
 
99
- export interface DeriveTrailCliCommandProjectionOptions {
99
+ export interface DeriveTrailCliCommandOptions {
100
100
  readonly aliases?: readonly CliCommandAliasInput[] | undefined;
101
101
  readonly aliasSource?: Extract<CliCommandRouteSource, 'surface' | 'trail'>;
102
102
  }
@@ -306,38 +306,38 @@ export const normalizeCliCommandPath = (
306
306
  ? splitCliPathString(value, context)
307
307
  : value.map((segment) => validateCliSegment(segment, context));
308
308
 
309
- const isTrailCliProjection = (
310
- value: CliCommandPathInput | TrailCliProjection
311
- ): value is TrailCliProjection =>
309
+ const isTrailCliRendering = (
310
+ value: CliCommandPathInput | TrailCliRendering
311
+ ): value is TrailCliRendering =>
312
312
  typeof value !== 'string' &&
313
313
  !Array.isArray(value) &&
314
314
  value !== null &&
315
315
  typeof value === 'object';
316
316
 
317
- const trailCliProjectionFor = (
318
- trail: TrailCliProjectionInput
319
- ): TrailCliProjection | undefined => {
317
+ const trailCliRenderingFor = (
318
+ trail: TrailCliRenderingInput
319
+ ): TrailCliRendering | undefined => {
320
320
  if (trail.cli === undefined) {
321
321
  return undefined;
322
322
  }
323
- return isTrailCliProjection(trail.cli) ? trail.cli : { path: trail.cli };
323
+ return isTrailCliRendering(trail.cli) ? trail.cli : { path: trail.cli };
324
324
  };
325
325
 
326
326
  const deriveCanonicalCliRoute = (
327
- trail: TrailCliProjectionInput
327
+ trail: TrailCliRenderingInput
328
328
  ): CliCommandRoute => {
329
- const projection = trailCliProjectionFor(trail);
329
+ const rendering = trailCliRenderingFor(trail);
330
330
  const path =
331
- projection?.path === undefined
331
+ rendering?.path === undefined
332
332
  ? deriveCliPath(trail.id)
333
333
  : normalizeCliCommandPath(
334
- projection.path,
334
+ rendering.path,
335
335
  `CLI command path for trail "${trail.id}"`
336
336
  );
337
337
  return {
338
338
  kind: 'canonical',
339
339
  path,
340
- source: projection?.path === undefined ? 'derived' : 'trail',
340
+ source: rendering?.path === undefined ? 'derived' : 'trail',
341
341
  target: trail.id,
342
342
  };
343
343
  };
@@ -387,7 +387,7 @@ const normalizeCliAlias = ({
387
387
  *
388
388
  * MCP tool names must be `[a-z0-9_]+`: the app name prefixes the trail id,
389
389
  * dots and hyphens collapse to underscores, and everything lowercases. This
390
- * is the one owner for the projection — the MCP surface renders tools with
390
+ * is the one owner for the rendering — the MCP surface renders tools with
391
391
  * it and Warden checks binding-name collisions against it, so the two
392
392
  * readers cannot drift.
393
393
  *
@@ -404,14 +404,14 @@ export const deriveMcpToolName = (appName: string, trailId: string): string => {
404
404
  };
405
405
 
406
406
  /** Derive resolved CLI command routes for one trail. */
407
- export const deriveTrailCliCommandProjection = (
408
- trail: TrailCliProjectionInput,
409
- options?: DeriveTrailCliCommandProjectionOptions
410
- ): TrailCliCommandProjection => {
407
+ export const deriveTrailCliCommandRendering = (
408
+ trail: TrailCliRenderingInput,
409
+ options?: DeriveTrailCliCommandOptions
410
+ ): TrailCliCommandRendering => {
411
411
  const canonical = deriveCanonicalCliRoute(trail);
412
- const projection = trailCliProjectionFor(trail);
412
+ const rendering = trailCliRenderingFor(trail);
413
413
  const trailAliases =
414
- projection?.aliases?.map((alias) =>
414
+ rendering?.aliases?.map((alias) =>
415
415
  normalizeCliAlias({
416
416
  alias,
417
417
  canonicalPath: canonical.path,
package/src/detours.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Hard upper bound for detour recovery attempts.
3
3
  *
4
- * Execution and derived surface/topo projections both clamp declared detour
4
+ * Execution and derived surface/topo facts both clamp declared detour
5
5
  * attempts to this value so runtime behavior and inspectable contracts stay in
6
6
  * lockstep.
7
7
  */
@@ -6,7 +6,7 @@ const errorRedactor = createRedactor();
6
6
 
7
7
  export const INTERNAL_ERROR_PUBLIC_MESSAGE = 'Internal server error';
8
8
 
9
- export interface ErrorDiagnosticsProjection {
9
+ export interface ErrorDiagnosticsRendering {
10
10
  readonly category?: ErrorCategory | undefined;
11
11
  readonly context?: Record<string, unknown> | undefined;
12
12
  readonly message: string;
@@ -15,6 +15,13 @@ export interface ErrorDiagnosticsProjection {
15
15
  readonly stack?: string | undefined;
16
16
  }
17
17
 
18
+ export interface PublicErrorRendering {
19
+ readonly category: ErrorCategory;
20
+ readonly message: string;
21
+ readonly name: string;
22
+ readonly retryable: boolean;
23
+ }
24
+
18
25
  export const redactErrorString = (value: string): string =>
19
26
  errorRedactor.redact(value);
20
27
 
@@ -28,9 +35,9 @@ export const redactErrorStack = (
28
35
  ): string | undefined =>
29
36
  stack === undefined ? undefined : redactErrorString(stack);
30
37
 
31
- export const projectErrorDiagnostics = (
38
+ export const renderErrorDiagnostics = (
32
39
  error: Error
33
- ): ErrorDiagnosticsProjection => {
40
+ ): ErrorDiagnosticsRendering => {
34
41
  const context = isTrailsError(error)
35
42
  ? redactErrorContext(error.context)
36
43
  : undefined;
@@ -49,3 +56,32 @@ export const projectErrorDiagnostics = (
49
56
  ...(stack === undefined ? {} : { stack }),
50
57
  };
51
58
  };
59
+
60
+ /**
61
+ * Project an error through the shared public redaction policy.
62
+ *
63
+ * @example
64
+ * ```ts
65
+ * const rendering = renderPublicError(new NotFoundError('missing'));
66
+ * ```
67
+ */
68
+ export const renderPublicError = (error: Error): PublicErrorRendering => {
69
+ if (isTrailsError(error)) {
70
+ return {
71
+ category: error.category,
72
+ message:
73
+ error.category === 'internal'
74
+ ? INTERNAL_ERROR_PUBLIC_MESSAGE
75
+ : redactErrorString(error.message),
76
+ name: error.name,
77
+ retryable: error.retryable,
78
+ };
79
+ }
80
+
81
+ return {
82
+ category: 'internal',
83
+ message: INTERNAL_ERROR_PUBLIC_MESSAGE,
84
+ name: 'InternalError',
85
+ retryable: false,
86
+ };
87
+ };
package/src/errors.ts CHANGED
@@ -282,7 +282,7 @@ export type ErrorClassRegistryEntry =
282
282
  /**
283
283
  * Authored registry of concrete TrailsError classes.
284
284
  *
285
- * JavaScript cannot enumerate subclasses at runtime, so rule and projection
285
+ * JavaScript cannot enumerate subclasses at runtime, so rule and derivation
286
286
  * tooling should walk this owner-held list instead of hardcoding parallel
287
287
  * class-name tables. `RetryExhaustedError` is marked dynamic because it
288
288
  * inherits its runtime category from the wrapped error rather than always
package/src/execute.ts CHANGED
@@ -158,19 +158,19 @@ export interface ExecuteTrailOptions {
158
158
  * Per-layer runtime input keyed by `Layer.name`.
159
159
  *
160
160
  * Surfaces (CLI, MCP, HTTP) parse their native idiom into a per-layer
161
- * input object — usually projected from each layer's `input` schema —
161
+ * input object — usually derived from each layer's `input` schema —
162
162
  * and pass it here. The executor merges these into
163
163
  * `ctx.extensions[LAYER_INPUTS_KEY]` so layers can read their own slot
164
164
  * via `ctx.extensions?.[LAYER_INPUTS_KEY]?.[layer.name]`.
165
165
  *
166
- * @see TRL-473 for the CLI projection contract.
166
+ * @see TRL-473 for the CLI rendering contract.
167
167
  */
168
168
  readonly layerInputs?: Readonly<Record<string, unknown>> | undefined;
169
169
  /**
170
170
  * Execute a specific live trail version.
171
171
  *
172
172
  * Omit for the current top-level contract. Number and numeric-string
173
- * references select authored versions; marker references select projected
173
+ * references select authored versions; marker references select derived
174
174
  * content-addressed markers by unambiguous prefix.
175
175
  */
176
176
  readonly version?: TrailVersionReference | undefined;
package/src/fire.ts CHANGED
@@ -36,7 +36,7 @@ import {
36
36
  import type { ActivationProvenance } from './activation-provenance.js';
37
37
  import type { ActivationWhereSpec } from './activation-source.js';
38
38
  import { getActivationWherePredicate } from './activation-source.js';
39
- import { activationSourceKey } from './activation-source-projection.js';
39
+ import { activationSourceKey } from './activation-source-derivation.js';
40
40
  import { NotFoundError, TrailsError, ValidationError } from './errors.js';
41
41
  import { forkCtx } from './internal/fork-ctx.js';
42
42
  import {
package/src/index.ts CHANGED
@@ -45,29 +45,33 @@ export type {
45
45
  export {
46
46
  createSurfaceErrorMapper,
47
47
  mapSurfaceError,
48
- projectErrorClassSurface,
49
- projectPublicSurfaceError,
50
- projectSurfaceError,
48
+ renderErrorClassSurface,
49
+ renderPublicSurfaceError,
50
+ renderSurfaceError,
51
51
  surfaceErrorMap,
52
52
  surfaceErrorRegistry,
53
53
  surfaceNames,
54
54
  } from './transport-error-map.js';
55
55
  export type {
56
- ErrorClassSurfaceProjection,
56
+ ErrorClassSurfaceRendering,
57
57
  SurfaceErrorCode,
58
58
  SurfaceErrorMapper,
59
59
  SurfaceErrorMappings,
60
- SurfaceErrorProjection,
60
+ SurfaceErrorRendering,
61
61
  SurfaceName,
62
62
  } from './transport-error-map.js';
63
63
  export {
64
64
  INTERNAL_ERROR_PUBLIC_MESSAGE,
65
- projectErrorDiagnostics,
65
+ renderErrorDiagnostics,
66
+ renderPublicError,
66
67
  redactErrorContext,
67
68
  redactErrorStack,
68
69
  redactErrorString,
69
- } from './error-projection.js';
70
- export type { ErrorDiagnosticsProjection } from './error-projection.js';
70
+ } from './error-rendering.js';
71
+ export type {
72
+ ErrorDiagnosticsRendering,
73
+ PublicErrorRendering,
74
+ } from './error-rendering.js';
71
75
  export type {
72
76
  DiagnosticBase,
73
77
  DiagnosticSeverity,
@@ -186,9 +190,9 @@ export type {
186
190
  export {
187
191
  activationSourceDeclarationSignature,
188
192
  activationSourceKey,
189
- projectActivationSourceDeclaration,
190
- } from './activation-source-projection.js';
191
- export type { ActivationSourceProjection } from './activation-source-projection.js';
193
+ deriveActivationSourceFacts,
194
+ } from './activation-source-derivation.js';
195
+ export type { ActivationSourceFacts } from './activation-source-derivation.js';
192
196
  export {
193
197
  deriveSupportedTrailVersions,
194
198
  forkVersion,
@@ -260,8 +264,8 @@ export {
260
264
  shouldIncludeTrailForSurface,
261
265
  } from './surface-filter.js';
262
266
  export type { SurfaceFilterOptions } from './surface-filter.js';
263
- export { deriveSurfaceTrailVersionProjections } from './surface-versioning.js';
264
- export type { SurfaceTrailVersionProjection } from './surface-versioning.js';
267
+ export { deriveSurfaceTrailVersionRenderings } from './surface-versioning.js';
268
+ export type { SurfaceTrailVersionRendering } from './surface-versioning.js';
265
269
  export {
266
270
  shouldValidateSurfaceTopo,
267
271
  validateSurfaceTopo,
@@ -502,23 +506,23 @@ export {
502
506
  collectAttachedTypedLayers,
503
507
  LAYER_FIELD_RESERVED_NAMES,
504
508
  LAYER_FIELD_RESERVED_NAMES_KEBAB,
505
- projectLayerFieldName,
506
- } from './layer-projection.js';
509
+ renderLayerFieldName,
510
+ } from './layer-field-rendering.js';
507
511
  export type {
508
512
  AttachedLayerScope,
509
513
  AttachedTypedLayer,
510
- LayerFieldProjection,
514
+ LayerFieldRendering,
511
515
  LayerFieldRenameReason,
512
- ProjectedLayerField,
513
- RenamedLayerFieldProjection,
514
- } from './layer-projection.js';
516
+ RenderedLayerField,
517
+ RenamedLayerFieldRendering,
518
+ } from './layer-field-rendering.js';
515
519
 
516
520
  // Derive
517
521
  export {
518
522
  deriveCliPath,
519
523
  deriveFields,
520
524
  deriveMcpToolName,
521
- deriveTrailCliCommandProjection,
525
+ deriveTrailCliCommandRendering,
522
526
  normalizeCliCommandPath,
523
527
  } from './derive.js';
524
528
  export type {
@@ -527,11 +531,11 @@ export type {
527
531
  CliCommandRoute,
528
532
  CliCommandRouteKind,
529
533
  CliCommandRouteSource,
530
- DeriveTrailCliCommandProjectionOptions,
534
+ DeriveTrailCliCommandOptions,
531
535
  Field,
532
536
  FieldOverride,
533
- TrailCliCommandProjection,
534
- TrailCliProjection,
537
+ TrailCliCommandRendering,
538
+ TrailCliRendering,
535
539
  } from './derive.js';
536
540
 
537
541
  // Compose schema
@@ -1,25 +1,25 @@
1
1
  /**
2
- * Shared, surface-agnostic helpers for projecting typed layer `input` schemas
2
+ * Shared, surface-agnostic helpers for rendering typed layer `input` schemas
3
3
  * onto a surface's native idiom.
4
4
  *
5
- * Layer projection has two halves:
5
+ * Layer rendering has two halves:
6
6
  * 1. **Collection** — walk the trail's effective layers (topo → surface →
7
7
  * trail) and keep only the ones that declare an `input` schema. These
8
- * are the layers a surface needs to project.
9
- * 2. **Naming/collision policy** — when a layer field's projected name
8
+ * are the layers a surface needs to render.
9
+ * 2. **Naming/collision policy** — when a layer field's rendered name
10
10
  * collides with a name already claimed by the trail, by another layer,
11
11
  * or by a surface-reserved name, the field is renamed using the
12
12
  * deterministic `<layerName>-<originalField>` rule. The collision-detection
13
- * logic itself is surface-agnostic; the *shape* of the projected name
13
+ * logic itself is surface-agnostic; the *shape* of the rendered name
14
14
  * (kebab-case CLI flag, camelCase MCP parameter, HTTP request field)
15
15
  * stays per-surface.
16
16
  *
17
17
  * This module owns the surface-agnostic half. CLI/MCP/HTTP each layer their
18
- * own projection on top: see `@ontrails/cli/build`, `@ontrails/mcp/build`,
18
+ * own rendering on top: see `@ontrails/cli/build`, `@ontrails/mcp/build`,
19
19
  * and `@ontrails/http/build`.
20
20
  *
21
- * @see TRL-473 for the CLI projection that introduced this contract.
22
- * @see TRL-474 for the MCP and HTTP projections that lifted these helpers.
21
+ * @see TRL-473 for the CLI rendering that introduced this contract.
22
+ * @see TRL-474 for the MCP and HTTP renderings that lifted these helpers.
23
23
  */
24
24
 
25
25
  import type { Layer } from './layer.js';
@@ -71,10 +71,10 @@ export interface AttachedTypedLayer {
71
71
  /**
72
72
  * Collect every typed layer attached to a trail in the same composition order
73
73
  * the executor uses (topo → surface → trail). Layers without an `input`
74
- * schema are skipped — they have nothing to project onto a surface.
74
+ * schema are skipped — they have nothing to render onto a surface.
75
75
  *
76
76
  * @param graph - The topo carrying topo-scope layers.
77
- * @param trail - The trail whose effective layers we are projecting.
77
+ * @param trail - The trail whose effective layers we are rendering.
78
78
  * @param surfaceLayers - Layers attached at surface scope (`options.layers`
79
79
  * on the surface builder).
80
80
  */
@@ -109,15 +109,15 @@ export const collectAttachedTypedLayers = (
109
109
  // ---------------------------------------------------------------------------
110
110
 
111
111
  /**
112
- * Reason a layer field was renamed during projection.
112
+ * Reason a layer field was renamed during rendering.
113
113
  *
114
114
  * Surfaces map this onto their own warning/error idiom. CLI emits a stderr
115
- * warning, while MCP/HTTP rely on the projected schema as the source of truth.
115
+ * warning, while MCP/HTTP rely on the rendered schema as the source of truth.
116
116
  */
117
117
  export type LayerFieldRenameReason = 'reserved-name' | 'flag-collision';
118
118
 
119
119
  /**
120
- * Outcome of projecting a single layer field's name.
120
+ * Outcome of rendering a single layer field's name.
121
121
  *
122
122
  * `claimedName` is the name the surface will publish to consumers; it is the
123
123
  * field name when no collision was detected, or `<layerName>-<fieldName>` (or
@@ -125,13 +125,13 @@ export type LayerFieldRenameReason = 'reserved-name' | 'flag-collision';
125
125
  * a collision required a rename. `routingTarget` is the original field name
126
126
  * the value should be assigned back to inside the layer's runtime input.
127
127
  */
128
- export interface LayerFieldProjection {
128
+ export interface LayerFieldRendering {
129
129
  readonly claimedName: string;
130
130
  readonly routingTarget: string;
131
131
  readonly renamed: false;
132
132
  }
133
133
 
134
- export interface RenamedLayerFieldProjection {
134
+ export interface RenamedLayerFieldRendering {
135
135
  readonly claimedName: string;
136
136
  readonly routingTarget: string;
137
137
  readonly renamed: true;
@@ -139,40 +139,40 @@ export interface RenamedLayerFieldProjection {
139
139
  readonly reason: LayerFieldRenameReason;
140
140
  }
141
141
 
142
- export type ProjectedLayerField =
143
- | LayerFieldProjection
144
- | RenamedLayerFieldProjection;
142
+ export type RenderedLayerField =
143
+ | LayerFieldRendering
144
+ | RenamedLayerFieldRendering;
145
145
 
146
146
  /**
147
- * Apply the deterministic collision rename rule to a single projected layer
147
+ * Apply the deterministic collision rename rule to a single rendered layer
148
148
  * field name.
149
149
  *
150
150
  * @param layerName - The layer's logical name (used as the rename prefix).
151
151
  * @param originalName - The layer field's name as authored on its schema.
152
- * @param projectedName - The candidate name in the surface's native idiom
152
+ * @param renderedName - The candidate name in the surface's native idiom
153
153
  * (e.g. kebab-case for CLI, camelCase for MCP, request field for HTTP).
154
154
  * @param renamedName - The fallback name applied when a collision is detected.
155
155
  * Surfaces compute this with their own casing rule.
156
156
  * @param claimedNames - Names already taken by the trail's input or by
157
- * previous layer projections. Updated in place when a name is claimed.
157
+ * previous layer renderings. Updated in place when a name is claimed.
158
158
  * @param reservedNames - Framework-owned names that force a rename across
159
- * surface projections.
159
+ * surface renderings.
160
160
  */
161
- export const projectLayerFieldName = (
161
+ export const renderLayerFieldName = (
162
162
  _layerName: string,
163
163
  originalName: string,
164
- projectedName: string,
164
+ renderedName: string,
165
165
  renamedName: string,
166
166
  claimedNames: Set<string>,
167
167
  reservedNames: ReadonlySet<string>
168
- ): ProjectedLayerField => {
169
- const collidesWithClaimed = claimedNames.has(projectedName);
170
- const collidesWithReserved = reservedNames.has(projectedName);
168
+ ): RenderedLayerField => {
169
+ const collidesWithClaimed = claimedNames.has(renderedName);
170
+ const collidesWithReserved = reservedNames.has(renderedName);
171
171
 
172
172
  if (!collidesWithClaimed && !collidesWithReserved) {
173
- claimedNames.add(projectedName);
173
+ claimedNames.add(renderedName);
174
174
  return {
175
- claimedName: projectedName,
175
+ claimedName: renderedName,
176
176
  renamed: false,
177
177
  routingTarget: originalName,
178
178
  };
@@ -185,7 +185,7 @@ export const projectLayerFieldName = (
185
185
  claimedNames.add(claimedName);
186
186
  return {
187
187
  claimedName,
188
- originalName: projectedName,
188
+ originalName: renderedName,
189
189
  reason: collidesWithReserved ? 'reserved-name' : 'flag-collision',
190
190
  renamed: true,
191
191
  routingTarget: originalName,