@ontrails/core 1.0.0-beta.41 → 1.0.0-beta.43

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/src/observe.ts CHANGED
@@ -210,10 +210,10 @@ const stringifyDefaultConsoleRecord = (record: LogRecord): string => {
210
210
  };
211
211
 
212
212
  /**
213
- * In-core mirror of `@ontrails/observe`'s `createConsoleSink` shape, kept
213
+ * In-core mirror of `@ontrails/observability`'s `createConsoleSink` shape, kept
214
214
  * minimal and private to avoid a reverse dependency from `@ontrails/core`
215
- * onto `@ontrails/observe`. It mirrors the console level mapping in
216
- * `packages/observe/src/sinks.ts:50` and emits each record as a single-line
215
+ * onto `@ontrails/observability`. It mirrors the console level mapping in
216
+ * `packages/observability/src/sinks.ts:50` and emits each record as a single-line
217
217
  * JSON object written to the matching `console.{debug|info|warn|error}` method.
218
218
  *
219
219
  * @remarks
@@ -231,7 +231,7 @@ const createDefaultConsoleSink = (): LogSink => ({
231
231
  return;
232
232
  }
233
233
  const payload = stringifyDefaultConsoleRecord(record);
234
- // oxlint-disable-next-line trails-local/no-console-in-packages -- ADR 0041 mandates a default console logger in core; this is the single sanctioned console boundary, mirroring `@ontrails/observe`'s `createConsoleSink`.
234
+ // oxlint-disable-next-line trails-local/no-console-in-packages -- ADR 0041 mandates a default console logger in core; this is the single sanctioned console boundary, mirroring `@ontrails/observability`'s `createConsoleSink`.
235
235
  console[method](payload);
236
236
  },
237
237
  });
@@ -251,8 +251,8 @@ export const normalizeObserve = (
251
251
  if (observe === undefined) {
252
252
  // ADR 0041 promises a non-null `ctx.logger` with zero configuration.
253
253
  // Returning the default config here lets the existing topo → adapter
254
- // path project this log sink into `ctx.logger` without a second
255
- // resolution point or a reverse dependency on `@ontrails/observe`.
254
+ // path renders this log sink into `ctx.logger` without a second
255
+ // resolution point or a reverse dependency on `@ontrails/observability`.
256
256
  return DEFAULT_OBSERVE_CONFIG;
257
257
  }
258
258
 
package/src/resource.ts CHANGED
@@ -52,7 +52,7 @@ export interface ResourceSpec<T, C = unknown> {
52
52
  readonly description?: string | undefined;
53
53
  /** Arbitrary meta for tooling and filtering. */
54
54
  readonly meta?: Readonly<Record<string, unknown>> | undefined;
55
- /** Signals projected or owned by this resource. */
55
+ /** Signals derived or owned by this resource. */
56
56
  readonly signals?: readonly AnySignal[] | undefined;
57
57
  /** Reserved for future resource-specific design; trail versioning is trail-only. */
58
58
  readonly version?: never;
@@ -1,5 +1,5 @@
1
1
  import type { ActivationEntry } from './activation-source.js';
2
- import { activationSourceKey } from './activation-source-projection.js';
2
+ import { activationSourceKey } from './activation-source-derivation.js';
3
3
  import {
4
4
  buildActivationProvenanceTraceAttrs,
5
5
  withActivationProvenance,
@@ -26,7 +26,7 @@ import {
26
26
  redactErrorContext,
27
27
  redactErrorStack,
28
28
  redactErrorString,
29
- } from './error-projection.js';
29
+ } from './error-rendering.js';
30
30
  import { Result } from './result.js';
31
31
 
32
32
  // ---------------------------------------------------------------------------
@@ -40,7 +40,7 @@ export interface StructuredSignalExample {
40
40
  // `Date`, `RegExp`, `Map`, and `Set` are objects (`typeof === 'object'`),
41
41
  // so they would pass the structural walk and reach `JSON.stringify`, which
42
42
  // silently coerces them: a `Date` becomes its ISO string, a `RegExp` and
43
- // any `Map`/`Set` become `{}`. Either way the projected shape diverges
43
+ // any `Map`/`Set` become `{}`. Either way the derived shape diverges
44
44
  // from the example author's declared input. Treat them as non-serializable
45
45
  // leaves so the example is dropped rather than misrepresented to MCP
46
46
  // clients.
@@ -107,7 +107,7 @@ const signalIdFromAssertion = (
107
107
  : undefined;
108
108
  };
109
109
 
110
- const projectSignalAssertion = (
110
+ const deriveSignalAssertion = (
111
111
  assertion: TrailExampleSignalAssertion
112
112
  ): StructuredTrailExampleSignalAssertion | undefined => {
113
113
  const signalId = signalIdFromAssertion(assertion);
@@ -115,43 +115,43 @@ const projectSignalAssertion = (
115
115
  return undefined;
116
116
  }
117
117
 
118
- const projected: Record<string, unknown> = { signalId };
118
+ const derived: Record<string, unknown> = { signalId };
119
119
  if (assertion.payload !== undefined) {
120
120
  const payload = toJsonSerializable(assertion.payload);
121
121
  if (payload === undefined) {
122
122
  return undefined;
123
123
  }
124
- projected['payload'] = payload;
124
+ derived['payload'] = payload;
125
125
  }
126
126
  if (assertion.payloadMatch !== undefined) {
127
127
  const payloadMatch = toJsonSerializable(assertion.payloadMatch);
128
128
  if (payloadMatch === undefined) {
129
129
  return undefined;
130
130
  }
131
- projected['payloadMatch'] = payloadMatch;
131
+ derived['payloadMatch'] = payloadMatch;
132
132
  }
133
133
  if (assertion.times !== undefined) {
134
- projected['times'] = assertion.times;
134
+ derived['times'] = assertion.times;
135
135
  }
136
136
  return Object.freeze(
137
- projected
137
+ derived
138
138
  ) as unknown as StructuredTrailExampleSignalAssertion;
139
139
  };
140
140
 
141
- const projectSignalAssertions = (
141
+ const deriveSignalAssertions = (
142
142
  assertions: readonly TrailExampleSignalAssertion[] | undefined
143
143
  ): readonly StructuredTrailExampleSignalAssertion[] | undefined => {
144
144
  if (assertions === undefined) {
145
145
  return undefined;
146
146
  }
147
- const projected = assertions.map(projectSignalAssertion);
148
- if (projected.some((assertion) => assertion === undefined)) {
147
+ const derived = assertions.map(deriveSignalAssertion);
148
+ if (derived.some((assertion) => assertion === undefined)) {
149
149
  return undefined;
150
150
  }
151
- return Object.freeze(projected as StructuredTrailExampleSignalAssertion[]);
151
+ return Object.freeze(derived as StructuredTrailExampleSignalAssertion[]);
152
152
  };
153
153
 
154
- const projectExample = (
154
+ const deriveExample = (
155
155
  example: TrailExample<unknown, unknown>,
156
156
  provenance: StructuredTrailExampleProvenance
157
157
  ): StructuredTrailExample | undefined => {
@@ -160,7 +160,7 @@ const projectExample = (
160
160
  return undefined;
161
161
  }
162
162
 
163
- const projected: Record<string, unknown> = {
163
+ const derived: Record<string, unknown> = {
164
164
  input,
165
165
  kind: example.error === undefined ? 'success' : 'error',
166
166
  name: example.name,
@@ -168,37 +168,37 @@ const projectExample = (
168
168
  };
169
169
 
170
170
  if (example.description !== undefined) {
171
- projected['description'] = example.description;
171
+ derived['description'] = example.description;
172
172
  }
173
173
  if (example.expected !== undefined) {
174
174
  const expected = toJsonSerializable(example.expected);
175
175
  if (expected === undefined) {
176
176
  return undefined;
177
177
  }
178
- projected['expected'] = expected;
178
+ derived['expected'] = expected;
179
179
  }
180
180
  if (example.expectedMatch !== undefined) {
181
181
  const expectedMatch = toJsonSerializable(example.expectedMatch);
182
182
  if (expectedMatch === undefined) {
183
183
  return undefined;
184
184
  }
185
- projected['expectedMatch'] = expectedMatch;
185
+ derived['expectedMatch'] = expectedMatch;
186
186
  }
187
187
  if (example.error !== undefined) {
188
- projected['error'] = example.error;
188
+ derived['error'] = example.error;
189
189
  }
190
190
  if (example.signals !== undefined) {
191
- const signals = projectSignalAssertions(example.signals);
191
+ const signals = deriveSignalAssertions(example.signals);
192
192
  if (signals === undefined) {
193
193
  return undefined;
194
194
  }
195
- projected['signals'] = signals;
195
+ derived['signals'] = signals;
196
196
  }
197
197
 
198
- return Object.freeze(projected) as unknown as StructuredTrailExample;
198
+ return Object.freeze(derived) as unknown as StructuredTrailExample;
199
199
  };
200
200
 
201
- const projectSignalExample = (
201
+ const deriveSignalExample = (
202
202
  payload: unknown
203
203
  ): StructuredSignalExample | undefined => {
204
204
  const serializablePayload = toJsonSerializable(payload);
@@ -222,13 +222,13 @@ export const deriveStructuredTrailExamples = (
222
222
  }
223
223
 
224
224
  const provenance = options?.provenance ?? { source: 'trail.examples' };
225
- const projected = examples
226
- .map((example) => projectExample(example, provenance))
225
+ const derived = examples
226
+ .map((example) => deriveExample(example, provenance))
227
227
  .filter(
228
228
  (example): example is StructuredTrailExample => example !== undefined
229
229
  );
230
230
 
231
- return projected.length > 0 ? Object.freeze(projected) : undefined;
231
+ return derived.length > 0 ? Object.freeze(derived) : undefined;
232
232
  };
233
233
 
234
234
  export const deriveStructuredSignalExamples = (
@@ -238,11 +238,11 @@ export const deriveStructuredSignalExamples = (
238
238
  return undefined;
239
239
  }
240
240
 
241
- const projected = examples
242
- .map(projectSignalExample)
241
+ const derived = examples
242
+ .map(deriveSignalExample)
243
243
  .filter(
244
244
  (example): example is StructuredSignalExample => example !== undefined
245
245
  );
246
246
 
247
- return projected.length > 0 ? Object.freeze(projected) : undefined;
247
+ return derived.length > 0 ? Object.freeze(derived) : undefined;
248
248
  };
@@ -21,7 +21,7 @@ export interface SurfaceSelectionOptions {
21
21
  }
22
22
 
23
23
  export interface SurfaceValidationOptions {
24
- /** Set to `false` to skip established-topo validation during projection. */
24
+ /** Set to `false` to skip established-topo validation during derivation. */
25
25
  readonly validate?: boolean | undefined;
26
26
  }
27
27
 
@@ -33,7 +33,7 @@ export const SURFACES_OVERLAY_NAMESPACE = 'surfaces' as const;
33
33
  /**
34
34
  * Who authored an overlay envelope.
35
35
  *
36
- * `'adapter-derived'` marks facts an adapter projects from the topo;
36
+ * `'adapter-derived'` marks facts an adapter renders from the topo;
37
37
  * `'app-authored'` marks bindings the app wrote by hand. Surfaces obey
38
38
  * app-authored overlays only — adapters contribute facts, never bindings.
39
39
  *
@@ -242,7 +242,7 @@ export interface SurfaceOverlay {
242
242
  /** The bindings schema, enforced again on the compile path. */
243
243
  readonly schema: z.ZodType;
244
244
  /**
245
- * Project the overlay facts. Ignores the topo — bindings are authored —
245
+ * Derive the overlay facts. Ignores the topo — bindings are authored —
246
246
  * so the parameter is optional; the signature stays structurally
247
247
  * assignable to the adapter-kit `Overlay` contract's `(topo) => unknown`.
248
248
  */
@@ -313,7 +313,7 @@ export interface OverlayEnvelopeLike {
313
313
  readonly provenance?: OverlayProvenance | undefined;
314
314
  /** The envelope's fact schema. */
315
315
  readonly schema: z.ZodType;
316
- /** Project the envelope's facts. */
316
+ /** Derive the envelope's facts. */
317
317
  derive(topo?: Topo): unknown;
318
318
  /**
319
319
  * Static surface bindings, when the envelope carries them directly.
@@ -575,11 +575,11 @@ const assertMcpSynonymBindingName = (name: string): void => {
575
575
 
576
576
  /**
577
577
  * Derive the deterministic default description for an MCP grouped entry
578
- * projected from the `surfaces` overlay.
578
+ * rendered from the `surfaces` overlay.
579
579
  *
580
580
  * Both the MCP surface (the runtime tool description) and Topography (the
581
581
  * lock's trailhead entry description) read this helper, so the authored
582
- * binding projects one description everywhere.
582
+ * binding renders one description everywhere.
583
583
  *
584
584
  * @example
585
585
  * ```ts
@@ -5,7 +5,7 @@ import {
5
5
  } from './trail.js';
6
6
  import { deriveTrailVersionMarkers } from './version-marker.js';
7
7
 
8
- export interface SurfaceTrailVersionProjection {
8
+ export interface SurfaceTrailVersionRendering {
9
9
  readonly current: boolean;
10
10
  readonly deprecated: boolean;
11
11
  readonly marker?: string | undefined;
@@ -13,9 +13,9 @@ export interface SurfaceTrailVersionProjection {
13
13
  readonly version: number;
14
14
  }
15
15
 
16
- export const deriveSurfaceTrailVersionProjections = (
16
+ export const deriveSurfaceTrailVersionRenderings = (
17
17
  trail: AnyTrail
18
- ): readonly SurfaceTrailVersionProjection[] | undefined => {
18
+ ): readonly SurfaceTrailVersionRendering[] | undefined => {
19
19
  if (trail.version === undefined) {
20
20
  return undefined;
21
21
  }
package/src/tracing.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  * This module is the home for the trace record type, the sink interface,
5
5
  * the sink registry, and the helpers `executeTrail` uses to create root
6
6
  * trace records and child spans. Core keeps this minimal contract public so
7
- * `@ontrails/observe`, `@ontrails/tracing`, adapters, and tests share the
7
+ * `@ontrails/observability`, adapters, and tests share the
8
8
  * same intrinsic execution record shape.
9
9
  *
10
10
  * Tracing is intrinsic: every `executeTrail` call automatically produces a
@@ -58,8 +58,8 @@ export interface TraceRecord {
58
58
  /**
59
59
  * Minimal shape a tracing sink must satisfy.
60
60
  *
61
- * Kept intentionally tiny so adapters in `@ontrails/tracing`,
62
- * `@ontrails/observe`, and user code can all satisfy it without
61
+ * Kept intentionally tiny so adapters in `@ontrails/observability`,
62
+ * `@ontrails/observability`, and user code can all satisfy it without
63
63
  * additional dependencies.
64
64
  */
65
65
  export interface TraceSink {
package/src/trail.ts CHANGED
@@ -15,7 +15,7 @@ import type { AnyEntity } from './entity.js';
15
15
  import type {
16
16
  FieldOverride,
17
17
  CliCommandPathInput,
18
- TrailCliProjection,
18
+ TrailCliRendering,
19
19
  } from './derive.js';
20
20
  import type { Layer } from './layer.js';
21
21
  import type { Result } from './result.js';
@@ -504,13 +504,13 @@ export interface TrailSpec<
504
504
  * `topo → surface → trail → implementation` (outermost-first).
505
505
  *
506
506
  * Layers are typed and inspectable. Omit `input` for surface-invisible
507
- * wrappers that do not project any fields.
507
+ * wrappers that do not render any fields.
508
508
  */
509
509
  readonly layers?: readonly Layer[] | undefined;
510
510
  /** Per-field overrides for deriveFields() (labels, hints, options) */
511
511
  readonly fields?: Readonly<Record<string, FieldOverride>> | undefined;
512
- /** CLI projection metadata for canonical command path overrides and aliases. */
513
- readonly cli?: CliCommandPathInput | TrailCliProjection | undefined;
512
+ /** CLI rendering metadata for canonical command path overrides and aliases. */
513
+ readonly cli?: CliCommandPathInput | TrailCliRendering | undefined;
514
514
  /** Entities this trail operates on. */
515
515
  readonly entities?: readonly AnyEntity[] | undefined;
516
516
  /** IDs or trail objects of downstream trails this trail may invoke via ctx.compose() */
@@ -548,13 +548,13 @@ export interface TrailSpec<
548
548
  | undefined;
549
549
  /** Auth requirement: scopes object, 'public', or omitted (undeclared) */
550
550
  readonly permit?: PermitRequirement | undefined;
551
- /** Primary input fields and their order. CLI projects as positional args. */
551
+ /** Primary input fields and their order. CLI derives as positional args. */
552
552
  readonly args?: readonly string[] | false | undefined;
553
553
  /** Current trail version number. Omit for current-only unversioned trails. */
554
554
  readonly version?: number | undefined;
555
555
  /** Explicit historical trail versions. Current stays top-level. */
556
556
  readonly versions?: TrailVersions<I, O> | undefined;
557
- /** Version markers are projected into the resolved graph, not authored. */
557
+ /** Version markers are derived into the resolved graph, not authored. */
558
558
  readonly marker?: never;
559
559
  }
560
560
 
@@ -976,12 +976,12 @@ const normalizeVersionEntry = <CurrentInput, CurrentOutput>(
976
976
 
977
977
  if (hasOwn(raw, 'kind')) {
978
978
  throw new ValidationError(
979
- `Trail "${trailId}" version ${version} must not author kind; it is projected`
979
+ `Trail "${trailId}" version ${version} must not author kind; it is derived`
980
980
  );
981
981
  }
982
982
  if (hasOwn(raw, 'marker')) {
983
983
  throw new ValidationError(
984
- `Trail "${trailId}" version ${version} must not author marker; it is projected`
984
+ `Trail "${trailId}" version ${version} must not author marker; it is derived`
985
985
  );
986
986
  }
987
987
 
@@ -1286,7 +1286,7 @@ export function trail<
1286
1286
 
1287
1287
  if (hasOwn(rawSpec, 'marker')) {
1288
1288
  throw new ValidationError(
1289
- `Trail "${resolved.id}" must not author marker; it is projected`
1289
+ `Trail "${resolved.id}" must not author marker; it is derived`
1290
1290
  );
1291
1291
  }
1292
1292
 
@@ -760,7 +760,7 @@ const synthesizeDefaultImplementation = <
760
760
  };
761
761
 
762
762
  /**
763
- * Mechanically project one CRUD-shaped trail from a entity declaration.
763
+ * Mechanically derive one CRUD-shaped trail from a entity declaration.
764
764
  *
765
765
  * When `spec.implementation` is omitted and the call declares a single resource, the
766
766
  * helper derives a default implementation that dispatches to the resource accessor
@@ -16,7 +16,7 @@ import {
16
16
  import {
17
17
  INTERNAL_ERROR_PUBLIC_MESSAGE,
18
18
  redactErrorString,
19
- } from './error-projection.js';
19
+ } from './error-rendering.js';
20
20
 
21
21
  export const surfaceNames = ['cli', 'http', 'jsonRpc', 'mcp'] as const;
22
22
 
@@ -48,7 +48,7 @@ export type SurfaceErrorMappings<T> = Record<ErrorCategory, T>;
48
48
  export type SurfaceErrorCode =
49
49
  (typeof codesByCategory)[ErrorCategory][(typeof surfaceCodeKeys)[SurfaceName]];
50
50
 
51
- export interface SurfaceErrorProjection {
51
+ export interface SurfaceErrorRendering {
52
52
  readonly category: ErrorCategory;
53
53
  readonly code: SurfaceErrorCode;
54
54
  readonly message: string;
@@ -57,7 +57,7 @@ export interface SurfaceErrorProjection {
57
57
  readonly surface: SurfaceName;
58
58
  }
59
59
 
60
- export interface ErrorClassSurfaceProjection {
60
+ export interface ErrorClassSurfaceRendering {
61
61
  readonly category: ErrorCategory;
62
62
  readonly code: SurfaceErrorCode;
63
63
  readonly name: string;
@@ -102,10 +102,10 @@ export const mapSurfaceError = (
102
102
  ): SurfaceErrorCode =>
103
103
  codesByCategory[error.category][surfaceCodeKeys[surface]];
104
104
 
105
- export const projectSurfaceError = (
105
+ export const renderSurfaceError = (
106
106
  surface: SurfaceName,
107
107
  error: TrailsError
108
- ): SurfaceErrorProjection => ({
108
+ ): SurfaceErrorRendering => ({
109
109
  category: error.category,
110
110
  code: mapSurfaceError(surface, error),
111
111
  message: error.message,
@@ -114,18 +114,18 @@ export const projectSurfaceError = (
114
114
  surface,
115
115
  });
116
116
 
117
- export const projectPublicSurfaceError = (
117
+ export const renderPublicSurfaceError = (
118
118
  surface: SurfaceName,
119
119
  error: Error
120
- ): SurfaceErrorProjection => {
120
+ ): SurfaceErrorRendering => {
121
121
  if (isTrailsError(error)) {
122
- const projection = projectSurfaceError(surface, error);
122
+ const rendering = renderSurfaceError(surface, error);
123
123
  return {
124
- ...projection,
124
+ ...rendering,
125
125
  message:
126
- projection.category === 'internal'
126
+ rendering.category === 'internal'
127
127
  ? INTERNAL_ERROR_PUBLIC_MESSAGE
128
- : redactErrorString(projection.message),
128
+ : redactErrorString(rendering.message),
129
129
  };
130
130
  }
131
131
 
@@ -151,15 +151,15 @@ const fixedErrorClassByName: ReadonlyMap<string, FixedErrorClassRegistryEntry> =
151
151
  );
152
152
 
153
153
  /**
154
- * Project a known error class name onto a surface without constructing it.
154
+ * Render a known error class name onto a surface without constructing it.
155
155
  *
156
156
  * Dynamic-category errors such as `RetryExhaustedError` return `undefined`
157
157
  * because their surface code depends on the wrapped runtime error.
158
158
  */
159
- export const projectErrorClassSurface = (
159
+ export const renderErrorClassSurface = (
160
160
  surface: SurfaceName,
161
161
  errorName: string
162
- ): ErrorClassSurfaceProjection | undefined => {
162
+ ): ErrorClassSurfaceRendering | undefined => {
163
163
  const entry = fixedErrorClassByName.get(errorName);
164
164
  if (entry === undefined) {
165
165
  return undefined;
package/src/types.ts CHANGED
@@ -215,13 +215,13 @@ export const SURFACE_LAYER_NAMES_KEY = '__trails_surface_layer_names' as const;
215
215
  /**
216
216
  * Context extension key carrying per-layer runtime input.
217
217
  *
218
- * Surfaces (CLI, MCP, HTTP) project each typed layer's `input` schema onto
218
+ * Surfaces (CLI, MCP, HTTP) render each typed layer's `input` schema onto
219
219
  * their native idioms (flags, tool params, query strings). At execute time
220
220
  * the parsed values are partitioned per layer and stored under this key as
221
221
  * `Record<layerName, unknown>`. Layers that need runtime input read their
222
222
  * own slot via `ctx.extensions?.[LAYER_INPUTS_KEY]?.[layer.name]`.
223
223
  *
224
- * @see TRL-473 for the CLI projection contract.
224
+ * @see TRL-473 for the CLI derivation contract.
225
225
  */
226
226
  export const LAYER_INPUTS_KEY = '__trails_layer_inputs' as const;
227
227
 
@@ -5,7 +5,7 @@ import { validateDraftFreeTopo } from './draft.js';
5
5
  import type { TopoDiagnostic } from './validate-topo.js';
6
6
  import { validateTopo } from './validate-topo.js';
7
7
 
8
- const PROJECTION_BLOCKING_RULES = new Set([
8
+ const DERIVATION_BLOCKING_RULES = new Set([
9
9
  'compose-cycle',
10
10
  'compose-exists',
11
11
  'no-self-compose',
@@ -20,12 +20,12 @@ const PROJECTION_BLOCKING_RULES = new Set([
20
20
  'signal-origin-exists',
21
21
  ]);
22
22
 
23
- const isProjectionBlockingIssue = (issue: TopoDiagnostic): boolean =>
24
- PROJECTION_BLOCKING_RULES.has(issue.rule) ||
23
+ const isDerivationBlockingIssue = (issue: TopoDiagnostic): boolean =>
24
+ DERIVATION_BLOCKING_RULES.has(issue.rule) ||
25
25
  (issue.rule === 'activation-source-input-compatible' &&
26
26
  issue.sourceKind === 'queue');
27
27
 
28
- const keepProjectionBlockingIssues = (
28
+ const keepDerivationBlockingIssues = (
29
29
  result: ReturnType<typeof validateTopo>
30
30
  ) => {
31
31
  if (result.isOk()) {
@@ -35,7 +35,7 @@ const keepProjectionBlockingIssues = (
35
35
  const issues = (
36
36
  result.error.context as { issues?: readonly TopoDiagnostic[] } | undefined
37
37
  )?.issues;
38
- const remainingIssues = issues?.filter(isProjectionBlockingIssue);
38
+ const remainingIssues = issues?.filter(isDerivationBlockingIssue);
39
39
 
40
40
  if (remainingIssues === undefined || remainingIssues.length === 0) {
41
41
  return Result.ok();
@@ -59,7 +59,7 @@ const keepProjectionBlockingIssues = (
59
59
  * valid, and they must also reject any remaining draft state.
60
60
  */
61
61
  export const validateEstablishedTopo = (topo: Topo) => {
62
- const structural = keepProjectionBlockingIssues(validateTopo(topo));
62
+ const structural = keepDerivationBlockingIssues(validateTopo(topo));
63
63
  if (structural.isErr()) {
64
64
  return structural;
65
65
  }
@@ -11,7 +11,7 @@ import { getActivationSourceInputCompatibilityIssues } from './activation-source
11
11
  import {
12
12
  activationSourceDeclarationSignature,
13
13
  activationSourceKey,
14
- } from './activation-source-projection.js';
14
+ } from './activation-source-derivation.js';
15
15
  import type { AnyEntity } from './entity.js';
16
16
  import { getEntityReferences } from './entity.js';
17
17
  import { ValidationError } from './errors.js';
package/src/validation.ts CHANGED
@@ -84,9 +84,9 @@ const getSchemaJsonSchemaOverride = (
84
84
  };
85
85
 
86
86
  /**
87
- * Whether a schema has a deterministic JSON-schema override projection (for
87
+ * Whether a schema has a deterministic JSON-schema override derivation (for
88
88
  * example `blobRefSchema`, a `z.custom(...)` carrying the descriptor metadata).
89
- * Such schemas project to a canonical descriptor regardless of their underlying
89
+ * Such schemas derive to a canonical descriptor regardless of their underlying
90
90
  * Zod internals, so marker derivation can treat them as supported.
91
91
  */
92
92
  export const schemaHasJsonSchemaOverride = (schema: z.ZodType): boolean =>
@@ -131,7 +131,7 @@ const wrappedMarkerSchemaTypes = new Set([
131
131
  'readonly',
132
132
  ]);
133
133
 
134
- // Schemas with a deterministic JSON-schema override (e.g. blobRefSchema) project
134
+ // Schemas with a deterministic JSON-schema override (e.g. blobRefSchema) derive
135
135
  // to a canonical descriptor, so the preflight accepts them without inspecting
136
136
  // the underlying custom Zod internals once runtime-only checks have been ruled
137
137
  // out.
@@ -176,7 +176,7 @@ const assertMarkerLiteralSupported = (
176
176
  def: Readonly<Record<string, unknown>>,
177
177
  path: readonly string[]
178
178
  ): void => {
179
- // The JSON-schema projection only emits the first literal value, so a
179
+ // The JSON-schema derivation only emits the first literal value, so a
180
180
  // multi-value literal (z.literal(['a', 'b'])) would hash identically to a
181
181
  // single-value literal and silently collide.
182
182
  const { values } = def;
@@ -345,7 +345,7 @@ const assertMarkerContentSupported = (
345
345
  const keys = Object.keys(record);
346
346
  if (keys.length === 0 && path.at(-1) !== 'properties') {
347
347
  throw new ValidationError(
348
- `Trail version marker content at ${markerValuePath(path)} contains an unsupported empty schema projection`
348
+ `Trail version marker content at ${markerValuePath(path)} contains an unsupported empty schema derivation`
349
349
  );
350
350
  }
351
351
 
@@ -428,14 +428,14 @@ export const deriveTrailVersionMarker = (content: unknown): string => {
428
428
  return hasher.digest('hex').slice(0, TRAIL_VERSION_MARKER_LENGTH);
429
429
  };
430
430
 
431
- const projectSchema = (schema: unknown, path: readonly string[]): unknown => {
431
+ const deriveSchema = (schema: unknown, path: readonly string[]): unknown => {
432
432
  assertMarkerSchemaSupported(schema, path);
433
433
  return canonicalizeTrailVersionMarkerContent(
434
434
  zodToJsonSchema(schema as never)
435
435
  );
436
436
  };
437
437
 
438
- const projectVersionDetours = (
438
+ const deriveVersionDetours = (
439
439
  entry: unknown
440
440
  ): readonly Record<string, unknown>[] | undefined => {
441
441
  const raw = entry as unknown as Record<string, unknown>;
@@ -459,7 +459,7 @@ const projectVersionDetours = (
459
459
  });
460
460
  };
461
461
 
462
- const projectVersionRuntimeRefs = (
462
+ const deriveVersionRuntimeRefs = (
463
463
  entry: unknown,
464
464
  field: 'composes' | 'resources'
465
465
  ): readonly string[] | undefined => {
@@ -494,16 +494,16 @@ export const deriveCurrentTrailVersionMarkerContent = (
494
494
  >
495
495
  ): Readonly<Record<string, unknown>> => {
496
496
  const content: Record<string, unknown> = {
497
- input: projectSchema(trail.input, ['input']),
497
+ input: deriveSchema(trail.input, ['input']),
498
498
  kind: 'current',
499
499
  ...(trail.output === undefined
500
500
  ? {}
501
- : { output: projectSchema(trail.output, ['output']) }),
501
+ : { output: deriveSchema(trail.output, ['output']) }),
502
502
  };
503
503
 
504
- const composes = projectVersionRuntimeRefs(trail, 'composes');
505
- const resources = projectVersionRuntimeRefs(trail, 'resources');
506
- const detours = projectVersionDetours(trail);
504
+ const composes = deriveVersionRuntimeRefs(trail, 'composes');
505
+ const resources = deriveVersionRuntimeRefs(trail, 'resources');
506
+ const detours = deriveVersionDetours(trail);
507
507
  if (composes !== undefined) {
508
508
  content['composes'] = composes;
509
509
  }
@@ -522,9 +522,9 @@ export const deriveTrailVersionEntryMarkerContent = (
522
522
  ): Readonly<Record<string, unknown>> => {
523
523
  const kind = getTrailVersionEntryKind(entry);
524
524
  const content: Record<string, unknown> = {
525
- input: projectSchema(entry.input, ['input']),
525
+ input: deriveSchema(entry.input, ['input']),
526
526
  kind,
527
- output: projectSchema(entry.output, ['output']),
527
+ output: deriveSchema(entry.output, ['output']),
528
528
  };
529
529
 
530
530
  if (kind === 'revision' && entry.transpose !== undefined) {
@@ -532,9 +532,9 @@ export const deriveTrailVersionEntryMarkerContent = (
532
532
  }
533
533
 
534
534
  if (kind === 'fork') {
535
- const composes = projectVersionRuntimeRefs(entry, 'composes');
536
- const resources = projectVersionRuntimeRefs(entry, 'resources');
537
- const detours = projectVersionDetours(entry);
535
+ const composes = deriveVersionRuntimeRefs(entry, 'composes');
536
+ const resources = deriveVersionRuntimeRefs(entry, 'resources');
537
+ const detours = deriveVersionDetours(entry);
538
538
  if (composes !== undefined) {
539
539
  content['composes'] = composes;
540
540
  }
@@ -599,7 +599,7 @@ export const assertUniqueTrailVersionMarkers = (
599
599
  for (const [marker, versions] of byMarker) {
600
600
  if (versions.length > 1) {
601
601
  throw new ValidationError(
602
- `Trail "${trailId}" versions ${versions.join(', ')} project the same marker ${marker}`
602
+ `Trail "${trailId}" versions ${versions.join(', ')} derive the same marker ${marker}`
603
603
  );
604
604
  }
605
605
  }