@orkestrel/scaffold 0.0.27 → 0.0.28

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.
@@ -104,7 +104,7 @@ export declare const ARTIFACT_TEMPLATES: Readonly<{
104
104
  readme: "# Guides\n\n## By concept\n\n- Package\n - Spec: Not created. Create this file when the workspace has a public surface:\n `guides/{{guide}}.md`\n - Source:\n{{source}}\n - Tests:\n{{tests}}\n\n## By directory\n\n{{directories}}\n";
105
105
  }>;
106
106
  orchestration: Readonly<{
107
- service: "#!/usr/bin/env sh\nset -eu\n\nprintf '%s\\n' \\\n{{services}}\n";
107
+ service: "#!/usr/bin/env sh\nset -eu\n\nprintf '%s\\n' \\\n{{vendors}}\n";
108
108
  }>;
109
109
  }>;
110
110
 
@@ -235,14 +235,22 @@ export declare const BIN_ENTRY_PATH = "src/bin/main.ts";
235
235
  * application-only, and mixed workspaces are all first class. `dependencies`
236
236
  * and `peers` are runtime `@orkestrel/*` packages; `extras` are
237
237
  * package-specific development dependencies and may carry any valid npm name.
238
- * `bin`, `integration`, `services`, `global`, and `showcase` are structural
239
- * facts: each is set only when the workspace physically ships the directory or
240
- * exact-case file that defines it, never because of the workspace's name and
241
- * never because a sibling fact is set. An axis-dependent fact projects nothing
242
- * when its required axis is absent: `integration` projects only a published
243
- * `src`, and `showcase` projects only a browser `app`. The gate answers that case
244
- * with a non-blocking question, so a caller that set the flag learns it emitted
245
- * nothing and the compile still completes.
238
+ * `bin`, `integration`, `conformance`, `service`, `vendors`, `global`, and
239
+ * `showcase` are structural facts: each is set only when the workspace
240
+ * physically ships the directory or exact-case file that defines it, never
241
+ * because of the workspace's name and never because a sibling fact is set. An
242
+ * axis-dependent fact projects nothing when its required axis is absent:
243
+ * `integration` projects only a published `src`, and `showcase` projects only a
244
+ * browser `app`. The gate answers that case with a non-blocking question, so a
245
+ * caller that set the flag learns it emitted nothing and the compile still
246
+ * completes.
247
+ *
248
+ * `service` says the workspace runs a live-service Vitest project over
249
+ * `tests/service`, and it alone registers that project. `vendors` names each
250
+ * external service the workspace drives and emits the provisioner skeleton that
251
+ * starts them. Neither is derivable from the other: a workspace may declare
252
+ * vendors before it writes a suite, and a suite may drive a service the skeleton
253
+ * does not start.
246
254
  */
247
255
  export declare interface Blueprint {
248
256
  readonly name: string;
@@ -258,7 +266,9 @@ export declare interface Blueprint {
258
266
  readonly overrides: readonly Override[];
259
267
  readonly bin: boolean;
260
268
  readonly integration: boolean;
261
- readonly services: readonly string[];
269
+ readonly conformance: boolean;
270
+ readonly service: boolean;
271
+ readonly vendors: readonly string[];
262
272
  readonly global: boolean;
263
273
  readonly showcase: boolean;
264
274
  }
@@ -401,10 +411,10 @@ export declare function blueprintToManifest(blueprint: Blueprint): string;
401
411
  * Compile the blueprint-dependent orchestration artifacts.
402
412
  *
403
413
  * @param blueprint - The workspace specification.
404
- * @returns A service inventory script when services are declared, otherwise none.
414
+ * @returns A vendor inventory script when vendors are declared, otherwise none.
405
415
  *
406
416
  * @remarks
407
- * A service name does not describe startup, readiness, or cleanup. The script
417
+ * A vendor name does not describe startup, readiness, or cleanup. The script
408
418
  * therefore records only the declared inventory and does not invent a service
409
419
  * runner or test project.
410
420
  */
@@ -499,8 +509,14 @@ export declare function blueprintToRootVite(blueprint: Blueprint): string;
499
509
  * to the axes the blueprint declares: a check and a test script per declared
500
510
  * environment, an aggregate over each axis, the policy and configuration
501
511
  * proofs every workspace can pass before it has a public API, and one build per
502
- * target that actually builds. The isolated installed-package integration
503
- * proof stays out of `test` and runs from `prepublishOnly` instead.
512
+ * target that actually builds.
513
+ *
514
+ * A proof leaves `test` when a real service or a real install answers it. The
515
+ * installed-package integration proof and the live-service proof therefore run
516
+ * from `prepublishOnly` instead. The conformance proof stays in `test`, because
517
+ * it measures this package against official tooling and drives nothing external:
518
+ * a conformance run may start a server, but it starts its own and reaches it
519
+ * over loopback, so the run stays hermetic.
504
520
  *
505
521
  * The configuration paths interpolated here are the same ones `SRC_MATRIX` and
506
522
  * `APP_MATRIX` list as each environment's configuration files, so a rename in
@@ -556,6 +572,12 @@ export declare function blueprintToSourceArtifacts(blueprint: Blueprint): readon
556
572
  * workspace and therefore follows the `src` axis as well as its structural
557
573
  * flag.
558
574
  *
575
+ * The conformance proof is not emitted either, for the reason the guide proof
576
+ * is not: it names an official artifact only the package knows, so a generated
577
+ * placeholder would read as a proof while measuring nothing. `service` emits its
578
+ * readiness setup alone, because the root configuration names that module by
579
+ * path.
580
+ *
559
581
  * @example
560
582
  * ```ts
561
583
  * import { blueprintToTestArtifacts, createBlueprint } from '@orkestrel/scaffold'
@@ -1021,6 +1043,8 @@ export declare class Compiler implements CompilerInterface {
1021
1043
  policy: "export const policy = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\ttest: {\n\t\t\t\tname: { label: 'policy', color: 'white' },\n\t\t\t\tinclude: ['tests/policy.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts'],\n\t\t\t\tenvironment: 'node',\n\t\t\t\tbrowser: { enabled: false },\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1022
1044
  config: "export const config = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\ttest: {\n\t\t\t\tname: { label: 'config', color: 'yellow' },\n\t\t\t\tinclude: ['tests/config.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts'],\n\t\t\t\tenvironment: 'node',\n\t\t\t\tbrowser: { enabled: false },\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1023
1045
  guides: "export const guides = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\ttest: {\n\t\t\t\tname: { label: 'guides', color: 'green' },\n\t\t\t\tinclude: ['tests/guides.test.ts'],\n\t\t\t\texclude: ['tests/src/**/*.test.ts', 'tests/app/**/*.test.ts', 'tests/setup.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts'],\n\t\t\t\tenvironment: 'node',\n\t\t\t\tbrowser: { enabled: false },\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1046
+ conformance: "// Where this package drifts from the official tooling it stays compatible with.\n// The subject is this package, so the proof is hermetic and stays in `npm test`.\nexport const conformance = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\ttest: {\n\t\t\t\tname: { label: 'conformance', color: 'magenta' },\n\t\t\t\tinclude: ['tests/conformance.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts'],\n\t\t\t\tenvironment: 'node',\n\t\t\t\tbrowser: { enabled: false },\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1047
+ service: "// The live external services this package drives. It starts nothing itself:\n// `scripts/service.sh` provisions, `tests/setupService.ts` proves readiness, and\n// the project stays out of `npm test` because a real service answers it.\nexport const service = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\ttest: {\n\t\t\t\tname: { label: 'service', color: 'red' },\n\t\t\t\tinclude: ['tests/service/**/*.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts', './tests/setupService.ts'],\n\t\t\t\tenvironment: 'node',\n\t\t\t\tbrowser: { enabled: false },\n\t\t\t\ttestTimeout: 120_000,\n\t\t\t\thookTimeout: 120_000,\n\t\t\t\tfileParallelism: false,\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1024
1048
  probe: "// A workbench, not a proof. No gate selects this project.\nexport const probe = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\ttest: {\n\t\t\t\tname: { label: 'probe', color: 'gray' },\n\t\t\t\tinclude: ['tmp/probe/**/*.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts'],\n\t\t\t\tenvironment: 'node',\n\t\t\t\tbrowser: { enabled: false },\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1025
1049
  integration: "export const integration = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\ttest: {\n\t\t\t\tname: { label: 'integration', color: 'blue' },\n\t\t\t\tinclude: ['tests/integration.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts'],\n{{global}}\t\t\t\tenvironment: 'node',\n\t\t\t\ttestTimeout: 120_000,\n\t\t\t\thookTimeout: 120_000,\n\t\t\t\tfileParallelism: false,\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1026
1050
  }>;
@@ -1052,6 +1076,9 @@ export declare class Compiler implements CompilerInterface {
1052
1076
  }>;
1053
1077
  }>;
1054
1078
 
1079
+ /** The official-tooling drift proof whose presence makes a workspace `conformance`. */
1080
+ export declare const CONFORMANCE_TEST_PATH = "tests/conformance.test.ts";
1081
+
1055
1082
  /** A text file produced by the template or computed compilation path. */
1056
1083
  export declare interface ContentArtifact extends ArtifactBase {
1057
1084
  readonly origin: 'template' | 'computed';
@@ -1094,8 +1121,8 @@ export declare class Compiler implements CompilerInterface {
1094
1121
  * blueprint.
1095
1122
  *
1096
1123
  * @remarks
1097
- * A blueprint is a closed record of sixteen fields, and most of them have one
1098
- * sensible starting value: an empty list, a cleared flag, `DEFAULT_VERSION`, and
1124
+ * A blueprint is a closed record, and most of its fields have one sensible
1125
+ * starting value: an empty list, a cleared flag, `DEFAULT_VERSION`, and
1099
1126
  * `DEFAULT_ENGINES`. Filling them here is what lets a caller state only what its
1100
1127
  * workspace actually declares.
1101
1128
  *
@@ -2588,6 +2615,12 @@ export declare class Compiler implements CompilerInterface {
2588
2615
  /** The provisioner skeleton a workspace with declared service vendors is given once. */
2589
2616
  export declare const SERVICE_SCRIPT_PATH = "scripts/service.sh";
2590
2617
 
2618
+ /** The live-service readiness module whose presence makes a workspace `service`. */
2619
+ export declare const SERVICE_SETUP_PATH = "tests/setupService.ts";
2620
+
2621
+ /** The include the live-service project covers, which is a directory rather than one proof. */
2622
+ export declare const SERVICE_TEST_INCLUDE = "tests/service/**/*.test.ts";
2623
+
2591
2624
  /** The Vite wrapper whose presence makes a workspace `showcase`. */
2592
2625
  export declare const SHOWCASE_CONFIG_PATH = "configs/app/vite.showcase.config.ts";
2593
2626
 
@@ -104,7 +104,7 @@ export declare const ARTIFACT_TEMPLATES: Readonly<{
104
104
  readme: "# Guides\n\n## By concept\n\n- Package\n - Spec: Not created. Create this file when the workspace has a public surface:\n `guides/{{guide}}.md`\n - Source:\n{{source}}\n - Tests:\n{{tests}}\n\n## By directory\n\n{{directories}}\n";
105
105
  }>;
106
106
  orchestration: Readonly<{
107
- service: "#!/usr/bin/env sh\nset -eu\n\nprintf '%s\\n' \\\n{{services}}\n";
107
+ service: "#!/usr/bin/env sh\nset -eu\n\nprintf '%s\\n' \\\n{{vendors}}\n";
108
108
  }>;
109
109
  }>;
110
110
 
@@ -235,14 +235,22 @@ export declare const BIN_ENTRY_PATH = "src/bin/main.ts";
235
235
  * application-only, and mixed workspaces are all first class. `dependencies`
236
236
  * and `peers` are runtime `@orkestrel/*` packages; `extras` are
237
237
  * package-specific development dependencies and may carry any valid npm name.
238
- * `bin`, `integration`, `services`, `global`, and `showcase` are structural
239
- * facts: each is set only when the workspace physically ships the directory or
240
- * exact-case file that defines it, never because of the workspace's name and
241
- * never because a sibling fact is set. An axis-dependent fact projects nothing
242
- * when its required axis is absent: `integration` projects only a published
243
- * `src`, and `showcase` projects only a browser `app`. The gate answers that case
244
- * with a non-blocking question, so a caller that set the flag learns it emitted
245
- * nothing and the compile still completes.
238
+ * `bin`, `integration`, `conformance`, `service`, `vendors`, `global`, and
239
+ * `showcase` are structural facts: each is set only when the workspace
240
+ * physically ships the directory or exact-case file that defines it, never
241
+ * because of the workspace's name and never because a sibling fact is set. An
242
+ * axis-dependent fact projects nothing when its required axis is absent:
243
+ * `integration` projects only a published `src`, and `showcase` projects only a
244
+ * browser `app`. The gate answers that case with a non-blocking question, so a
245
+ * caller that set the flag learns it emitted nothing and the compile still
246
+ * completes.
247
+ *
248
+ * `service` says the workspace runs a live-service Vitest project over
249
+ * `tests/service`, and it alone registers that project. `vendors` names each
250
+ * external service the workspace drives and emits the provisioner skeleton that
251
+ * starts them. Neither is derivable from the other: a workspace may declare
252
+ * vendors before it writes a suite, and a suite may drive a service the skeleton
253
+ * does not start.
246
254
  */
247
255
  export declare interface Blueprint {
248
256
  readonly name: string;
@@ -258,7 +266,9 @@ export declare interface Blueprint {
258
266
  readonly overrides: readonly Override[];
259
267
  readonly bin: boolean;
260
268
  readonly integration: boolean;
261
- readonly services: readonly string[];
269
+ readonly conformance: boolean;
270
+ readonly service: boolean;
271
+ readonly vendors: readonly string[];
262
272
  readonly global: boolean;
263
273
  readonly showcase: boolean;
264
274
  }
@@ -401,10 +411,10 @@ export declare function blueprintToManifest(blueprint: Blueprint): string;
401
411
  * Compile the blueprint-dependent orchestration artifacts.
402
412
  *
403
413
  * @param blueprint - The workspace specification.
404
- * @returns A service inventory script when services are declared, otherwise none.
414
+ * @returns A vendor inventory script when vendors are declared, otherwise none.
405
415
  *
406
416
  * @remarks
407
- * A service name does not describe startup, readiness, or cleanup. The script
417
+ * A vendor name does not describe startup, readiness, or cleanup. The script
408
418
  * therefore records only the declared inventory and does not invent a service
409
419
  * runner or test project.
410
420
  */
@@ -499,8 +509,14 @@ export declare function blueprintToRootVite(blueprint: Blueprint): string;
499
509
  * to the axes the blueprint declares: a check and a test script per declared
500
510
  * environment, an aggregate over each axis, the policy and configuration
501
511
  * proofs every workspace can pass before it has a public API, and one build per
502
- * target that actually builds. The isolated installed-package integration
503
- * proof stays out of `test` and runs from `prepublishOnly` instead.
512
+ * target that actually builds.
513
+ *
514
+ * A proof leaves `test` when a real service or a real install answers it. The
515
+ * installed-package integration proof and the live-service proof therefore run
516
+ * from `prepublishOnly` instead. The conformance proof stays in `test`, because
517
+ * it measures this package against official tooling and drives nothing external:
518
+ * a conformance run may start a server, but it starts its own and reaches it
519
+ * over loopback, so the run stays hermetic.
504
520
  *
505
521
  * The configuration paths interpolated here are the same ones `SRC_MATRIX` and
506
522
  * `APP_MATRIX` list as each environment's configuration files, so a rename in
@@ -556,6 +572,12 @@ export declare function blueprintToSourceArtifacts(blueprint: Blueprint): readon
556
572
  * workspace and therefore follows the `src` axis as well as its structural
557
573
  * flag.
558
574
  *
575
+ * The conformance proof is not emitted either, for the reason the guide proof
576
+ * is not: it names an official artifact only the package knows, so a generated
577
+ * placeholder would read as a proof while measuring nothing. `service` emits its
578
+ * readiness setup alone, because the root configuration names that module by
579
+ * path.
580
+ *
559
581
  * @example
560
582
  * ```ts
561
583
  * import { blueprintToTestArtifacts, createBlueprint } from '@orkestrel/scaffold'
@@ -1021,6 +1043,8 @@ export declare class Compiler implements CompilerInterface {
1021
1043
  policy: "export const policy = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\ttest: {\n\t\t\t\tname: { label: 'policy', color: 'white' },\n\t\t\t\tinclude: ['tests/policy.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts'],\n\t\t\t\tenvironment: 'node',\n\t\t\t\tbrowser: { enabled: false },\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1022
1044
  config: "export const config = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\ttest: {\n\t\t\t\tname: { label: 'config', color: 'yellow' },\n\t\t\t\tinclude: ['tests/config.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts'],\n\t\t\t\tenvironment: 'node',\n\t\t\t\tbrowser: { enabled: false },\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1023
1045
  guides: "export const guides = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\ttest: {\n\t\t\t\tname: { label: 'guides', color: 'green' },\n\t\t\t\tinclude: ['tests/guides.test.ts'],\n\t\t\t\texclude: ['tests/src/**/*.test.ts', 'tests/app/**/*.test.ts', 'tests/setup.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts'],\n\t\t\t\tenvironment: 'node',\n\t\t\t\tbrowser: { enabled: false },\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1046
+ conformance: "// Where this package drifts from the official tooling it stays compatible with.\n// The subject is this package, so the proof is hermetic and stays in `npm test`.\nexport const conformance = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\ttest: {\n\t\t\t\tname: { label: 'conformance', color: 'magenta' },\n\t\t\t\tinclude: ['tests/conformance.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts'],\n\t\t\t\tenvironment: 'node',\n\t\t\t\tbrowser: { enabled: false },\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1047
+ service: "// The live external services this package drives. It starts nothing itself:\n// `scripts/service.sh` provisions, `tests/setupService.ts` proves readiness, and\n// the project stays out of `npm test` because a real service answers it.\nexport const service = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\ttest: {\n\t\t\t\tname: { label: 'service', color: 'red' },\n\t\t\t\tinclude: ['tests/service/**/*.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts', './tests/setupService.ts'],\n\t\t\t\tenvironment: 'node',\n\t\t\t\tbrowser: { enabled: false },\n\t\t\t\ttestTimeout: 120_000,\n\t\t\t\thookTimeout: 120_000,\n\t\t\t\tfileParallelism: false,\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1024
1048
  probe: "// A workbench, not a proof. No gate selects this project.\nexport const probe = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\ttest: {\n\t\t\t\tname: { label: 'probe', color: 'gray' },\n\t\t\t\tinclude: ['tmp/probe/**/*.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts'],\n\t\t\t\tenvironment: 'node',\n\t\t\t\tbrowser: { enabled: false },\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1025
1049
  integration: "export const integration = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\ttest: {\n\t\t\t\tname: { label: 'integration', color: 'blue' },\n\t\t\t\tinclude: ['tests/integration.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts'],\n{{global}}\t\t\t\tenvironment: 'node',\n\t\t\t\ttestTimeout: 120_000,\n\t\t\t\thookTimeout: 120_000,\n\t\t\t\tfileParallelism: false,\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1026
1050
  }>;
@@ -1052,6 +1076,9 @@ export declare class Compiler implements CompilerInterface {
1052
1076
  }>;
1053
1077
  }>;
1054
1078
 
1079
+ /** The official-tooling drift proof whose presence makes a workspace `conformance`. */
1080
+ export declare const CONFORMANCE_TEST_PATH = "tests/conformance.test.ts";
1081
+
1055
1082
  /** A text file produced by the template or computed compilation path. */
1056
1083
  export declare interface ContentArtifact extends ArtifactBase {
1057
1084
  readonly origin: 'template' | 'computed';
@@ -1094,8 +1121,8 @@ export declare class Compiler implements CompilerInterface {
1094
1121
  * blueprint.
1095
1122
  *
1096
1123
  * @remarks
1097
- * A blueprint is a closed record of sixteen fields, and most of them have one
1098
- * sensible starting value: an empty list, a cleared flag, `DEFAULT_VERSION`, and
1124
+ * A blueprint is a closed record, and most of its fields have one sensible
1125
+ * starting value: an empty list, a cleared flag, `DEFAULT_VERSION`, and
1099
1126
  * `DEFAULT_ENGINES`. Filling them here is what lets a caller state only what its
1100
1127
  * workspace actually declares.
1101
1128
  *
@@ -2588,6 +2615,12 @@ export declare class Compiler implements CompilerInterface {
2588
2615
  /** The provisioner skeleton a workspace with declared service vendors is given once. */
2589
2616
  export declare const SERVICE_SCRIPT_PATH = "scripts/service.sh";
2590
2617
 
2618
+ /** The live-service readiness module whose presence makes a workspace `service`. */
2619
+ export declare const SERVICE_SETUP_PATH = "tests/setupService.ts";
2620
+
2621
+ /** The include the live-service project covers, which is a directory rather than one proof. */
2622
+ export declare const SERVICE_TEST_INCLUDE = "tests/service/**/*.test.ts";
2623
+
2591
2624
  /** The Vite wrapper whose presence makes a workspace `showcase`. */
2592
2625
  export declare const SHOWCASE_CONFIG_PATH = "configs/app/vite.showcase.config.ts";
2593
2626
 
@@ -200,6 +200,12 @@ var GLOBAL_SETUP_PATH = "tests/setupGlobal.ts";
200
200
  var GUIDES_TEST_PATH = "tests/guides.test.ts";
201
201
  /** The installed-package proof whose presence makes a workspace `integration`. */
202
202
  var INTEGRATION_TEST_PATH = "tests/integration.test.ts";
203
+ /** The official-tooling drift proof whose presence makes a workspace `conformance`. */
204
+ var CONFORMANCE_TEST_PATH = "tests/conformance.test.ts";
205
+ /** The live-service readiness module whose presence makes a workspace `service`. */
206
+ var SERVICE_SETUP_PATH = "tests/setupService.ts";
207
+ /** The include the live-service project covers, which is a directory rather than one proof. */
208
+ var SERVICE_TEST_INCLUDE = "tests/service/**/*.test.ts";
203
209
  /** The Vite wrapper whose presence makes a workspace `showcase`. */
204
210
  var SHOWCASE_CONFIG_PATH = "configs/app/vite.showcase.config.ts";
205
211
  /** The bare workspace name syntax: lowercase alphanumeric with hyphens, letter first. */
@@ -283,7 +289,7 @@ var DEFAULT_ENGINES = `>=${MINIMUM_NODE_VERSION}`;
283
289
  var BASE_DEV_DEPENDENCIES = Object.freeze({
284
290
  "@microsoft/api-extractor": "^7.58.12",
285
291
  "@orkestrel/guide": "^0.0.10",
286
- "@orkestrel/scaffold": "^0.0.27",
292
+ "@orkestrel/scaffold": "^0.0.28",
287
293
  "@types/node": "^26.2.0",
288
294
  oxfmt: "^0.62.0",
289
295
  oxlint: "^1.77.0",
@@ -675,6 +681,44 @@ export function appBrowser(...options: never[]): UserConfig {
675
681
  },
676
682
  options ?? {},
677
683
  )
684
+ `,
685
+ conformance: `// Where this package drifts from the official tooling it stays compatible with.
686
+ // The subject is this package, so the proof is hermetic and stays in \`npm test\`.
687
+ export const conformance = (options?: UserConfig): UserConfig =>
688
+ mergeConfig(
689
+ {
690
+ resolve,
691
+ test: {
692
+ name: { label: 'conformance', color: 'magenta' },
693
+ include: ['${CONFORMANCE_TEST_PATH}'],
694
+ setupFiles: ['./tests/setup.ts'],
695
+ environment: 'node',
696
+ browser: { enabled: false },
697
+ },
698
+ },
699
+ options ?? {},
700
+ )
701
+ `,
702
+ service: `// The live external services this package drives. It starts nothing itself:
703
+ // \`scripts/service.sh\` provisions, \`tests/setupService.ts\` proves readiness, and
704
+ // the project stays out of \`npm test\` because a real service answers it.
705
+ export const service = (options?: UserConfig): UserConfig =>
706
+ mergeConfig(
707
+ {
708
+ resolve,
709
+ test: {
710
+ name: { label: 'service', color: 'red' },
711
+ include: ['${SERVICE_TEST_INCLUDE}'],
712
+ setupFiles: ['./tests/setup.ts', './tests/setupService.ts'],
713
+ environment: 'node',
714
+ browser: { enabled: false },
715
+ testTimeout: 120_000,
716
+ hookTimeout: 120_000,
717
+ fileParallelism: false,
718
+ },
719
+ },
720
+ options ?? {},
721
+ )
678
722
  `,
679
723
  probe: `// A workbench, not a proof. No gate selects this project.
680
724
  export const probe = (options?: UserConfig): UserConfig =>
@@ -1149,7 +1193,7 @@ npm test
1149
1193
  set -eu
1150
1194
 
1151
1195
  printf '%s\\n' \\
1152
- {{services}}
1196
+ {{vendors}}
1153
1197
  ` })
1154
1198
  });
1155
1199
  //#endregion
@@ -1436,7 +1480,9 @@ var isBlueprint = recordOf({
1436
1480
  overrides: andOf(isCollection, arrayOf(isOverride)),
1437
1481
  bin: isBoolean,
1438
1482
  integration: isBoolean,
1439
- services: andOf(isCollection, arrayOf(isString)),
1483
+ conformance: isBoolean,
1484
+ service: isBoolean,
1485
+ vendors: andOf(isCollection, arrayOf(isString)),
1440
1486
  global: isBoolean,
1441
1487
  showcase: isBoolean
1442
1488
  }, ["description"]);
@@ -2672,8 +2718,14 @@ function blueprintToDevDependencies(blueprint) {
2672
2718
  * to the axes the blueprint declares: a check and a test script per declared
2673
2719
  * environment, an aggregate over each axis, the policy and configuration
2674
2720
  * proofs every workspace can pass before it has a public API, and one build per
2675
- * target that actually builds. The isolated installed-package integration
2676
- * proof stays out of `test` and runs from `prepublishOnly` instead.
2721
+ * target that actually builds.
2722
+ *
2723
+ * A proof leaves `test` when a real service or a real install answers it. The
2724
+ * installed-package integration proof and the live-service proof therefore run
2725
+ * from `prepublishOnly` instead. The conformance proof stays in `test`, because
2726
+ * it measures this package against official tooling and drives nothing external:
2727
+ * a conformance run may start a server, but it starts its own and reaches it
2728
+ * over loopback, so the run stays hermetic.
2677
2729
  *
2678
2730
  * The configuration paths interpolated here are the same ones `SRC_MATRIX` and
2679
2731
  * `APP_MATRIX` list as each environment's configuration files, so a rename in
@@ -2720,7 +2772,8 @@ function blueprintToScripts(blueprint) {
2720
2772
  ...compiles ? ["npm run test:src"] : [],
2721
2773
  ...blueprint.app.length > 0 ? ["npm run test:app"] : [],
2722
2774
  "npm run test:policy",
2723
- "npm run test:config"
2775
+ "npm run test:config",
2776
+ ...blueprint.conformance ? ["npm run test:conformance"] : []
2724
2777
  ].join(" && ");
2725
2778
  if (compiles) {
2726
2779
  scripts["test:src"] = [
@@ -2737,8 +2790,10 @@ function blueprintToScripts(blueprint) {
2737
2790
  }
2738
2791
  scripts["test:policy"] = `${vitest} --project policy`;
2739
2792
  scripts["test:config"] = `${vitest} --project config`;
2793
+ if (blueprint.conformance) scripts["test:conformance"] = `${vitest} --project conformance`;
2740
2794
  scripts["test:probe"] = "vitest run --config vite.config.ts --no-cache --reporter=verbose --project probe";
2741
2795
  if (integrates) scripts["test:integration"] = `${vitest} --project integration`;
2796
+ if (blueprint.service) scripts["test:service"] = `${vitest} --project service`;
2742
2797
  scripts.build = [
2743
2798
  "npm run clean",
2744
2799
  ...compiles ? ["npm run build:src"] : [],
@@ -2768,7 +2823,11 @@ function blueprintToScripts(blueprint) {
2768
2823
  scripts.serve = "node dist/app/server/main.cjs";
2769
2824
  scripts["serve:build"] = "npm run build:app:server && npm run serve";
2770
2825
  }
2771
- scripts.prepublishOnly = ["npm run format:check && npm run lint:check && npm run check && npm run build && npm test", ...integrates ? ["npm run test:integration"] : []].join(" && ");
2826
+ scripts.prepublishOnly = [
2827
+ "npm run format:check && npm run lint:check && npm run check && npm run build && npm test",
2828
+ ...integrates ? ["npm run test:integration"] : [],
2829
+ ...blueprint.service ? ["npm run test:service"] : []
2830
+ ].join(" && ");
2772
2831
  return scripts;
2773
2832
  }
2774
2833
  /**
@@ -3050,6 +3109,14 @@ export function appShowcase(...options: never[]): UserConfig {
3050
3109
  projects.push("config");
3051
3110
  factories.push(CONFIG_TEMPLATES.factories.guides);
3052
3111
  projects.push(`...(isExactCaseFile(resolveWorkspacePath('${GUIDES_TEST_PATH}')) ? [guides] : [])`);
3112
+ if (blueprint.conformance) {
3113
+ factories.push(CONFIG_TEMPLATES.factories.conformance);
3114
+ projects.push("conformance");
3115
+ }
3116
+ if (blueprint.service) {
3117
+ factories.push(CONFIG_TEMPLATES.factories.service);
3118
+ projects.push("service");
3119
+ }
3053
3120
  if (blueprint.src.length > 0 && blueprint.integration) {
3054
3121
  factories.push(fillTemplate(CONFIG_TEMPLATES.factories.integration, { global: blueprint.global ? " globalSetup: ['./tests/setupGlobal.ts'],\n" : "" }));
3055
3122
  projects.push("integration");
@@ -3270,6 +3337,12 @@ function blueprintToSourceArtifacts(blueprint) {
3270
3337
  * workspace and therefore follows the `src` axis as well as its structural
3271
3338
  * flag.
3272
3339
  *
3340
+ * The conformance proof is not emitted either, for the reason the guide proof
3341
+ * is not: it names an official artifact only the package knows, so a generated
3342
+ * placeholder would read as a proof while measuring nothing. `service` emits its
3343
+ * readiness setup alone, because the root configuration names that module by
3344
+ * path.
3345
+ *
3273
3346
  * @example
3274
3347
  * ```ts
3275
3348
  * import { blueprintToTestArtifacts, createBlueprint } from '@orkestrel/scaffold'
@@ -3303,6 +3376,13 @@ function blueprintToTestArtifacts(blueprint) {
3303
3376
  environment: "server",
3304
3377
  content: ARTIFACT_TEMPLATES.tests.setup
3305
3378
  });
3379
+ if (blueprint.service) artifacts.push({
3380
+ path: SERVICE_SETUP_PATH,
3381
+ group: "tests",
3382
+ ownership: "birth",
3383
+ origin: "template",
3384
+ content: ARTIFACT_TEMPLATES.tests.setup
3385
+ });
3306
3386
  if (blueprint.global) artifacts.push({
3307
3387
  path: GLOBAL_SETUP_PATH,
3308
3388
  group: "tests",
@@ -3416,22 +3496,22 @@ function blueprintToDocumentArtifacts(blueprint) {
3416
3496
  * Compile the blueprint-dependent orchestration artifacts.
3417
3497
  *
3418
3498
  * @param blueprint - The workspace specification.
3419
- * @returns A service inventory script when services are declared, otherwise none.
3499
+ * @returns A vendor inventory script when vendors are declared, otherwise none.
3420
3500
  *
3421
3501
  * @remarks
3422
- * A service name does not describe startup, readiness, or cleanup. The script
3502
+ * A vendor name does not describe startup, readiness, or cleanup. The script
3423
3503
  * therefore records only the declared inventory and does not invent a service
3424
3504
  * runner or test project.
3425
3505
  */
3426
3506
  function blueprintToOrchestrationArtifacts(blueprint) {
3427
- if (blueprint.services.length === 0) return [];
3428
- const services = blueprint.services.map((service, index) => `\t'${service}'${index === blueprint.services.length - 1 ? "" : " \\"}`).join("\n");
3507
+ if (blueprint.vendors.length === 0) return [];
3508
+ const vendors = blueprint.vendors.map((vendor, index) => `\t'${vendor}'${index === blueprint.vendors.length - 1 ? "" : " \\"}`).join("\n");
3429
3509
  return [{
3430
3510
  path: SERVICE_SCRIPT_PATH,
3431
3511
  group: "orchestration",
3432
3512
  ownership: "birth",
3433
3513
  origin: "template",
3434
- content: fillTemplate(ARTIFACT_TEMPLATES.orchestration.service, { services })
3514
+ content: fillTemplate(ARTIFACT_TEMPLATES.orchestration.service, { vendors })
3435
3515
  }];
3436
3516
  }
3437
3517
  /**
@@ -3787,19 +3867,19 @@ function blueprintToQuestions(blueprint) {
3787
3867
  message: "integration projects a published src, and this workspace declares none, so it emits nothing.",
3788
3868
  blocking: false
3789
3869
  });
3790
- const services = /* @__PURE__ */ new Set();
3791
- for (const service of blueprint.services) {
3792
- if (!NAME_PATTERN.test(service)) questions.push({
3793
- field: "services",
3794
- message: `${service} is not a lowercase alphanumeric service name starting with a letter.`,
3870
+ const vendors = /* @__PURE__ */ new Set();
3871
+ for (const vendor of blueprint.vendors) {
3872
+ if (!NAME_PATTERN.test(vendor)) questions.push({
3873
+ field: "vendors",
3874
+ message: `${vendor} is not a lowercase alphanumeric vendor name starting with a letter.`,
3795
3875
  blocking: true
3796
3876
  });
3797
- else if (services.has(service)) questions.push({
3798
- field: "services",
3799
- message: `${service} is declared more than once on services.`,
3877
+ else if (vendors.has(vendor)) questions.push({
3878
+ field: "vendors",
3879
+ message: `${vendor} is declared more than once on vendors.`,
3800
3880
  blocking: true
3801
3881
  });
3802
- services.add(service);
3882
+ vendors.add(vendor);
3803
3883
  }
3804
3884
  if (blueprint.showcase && !blueprint.app.includes("browser")) questions.push({
3805
3885
  field: "showcase",
@@ -4267,8 +4347,8 @@ var Compiler = class {
4267
4347
  * blueprint.
4268
4348
  *
4269
4349
  * @remarks
4270
- * A blueprint is a closed record of sixteen fields, and most of them have one
4271
- * sensible starting value: an empty list, a cleared flag, `DEFAULT_VERSION`, and
4350
+ * A blueprint is a closed record, and most of its fields have one sensible
4351
+ * starting value: an empty list, a cleared flag, `DEFAULT_VERSION`, and
4272
4352
  * `DEFAULT_ENGINES`. Filling them here is what lets a caller state only what its
4273
4353
  * workspace actually declares.
4274
4354
  *
@@ -4309,7 +4389,9 @@ function createBlueprint(name, input) {
4309
4389
  overrides: input?.overrides ?? [],
4310
4390
  bin: input?.bin ?? false,
4311
4391
  integration: input?.integration ?? false,
4312
- services: input?.services ?? [],
4392
+ conformance: input?.conformance ?? false,
4393
+ service: input?.service ?? false,
4394
+ vendors: input?.vendors ?? [],
4313
4395
  global: input?.global ?? false,
4314
4396
  showcase: input?.showcase ?? false
4315
4397
  }));
@@ -4336,6 +4418,6 @@ function createCompiler(options) {
4336
4418
  return new Compiler(options);
4337
4419
  }
4338
4420
  //#endregion
4339
- export { APP_BROWSER_DEV_DEPENDENCIES, APP_DEV_DEPENDENCIES, APP_MATRIX, APP_SERVER_DEV_DEPENDENCIES, ARTIFACT_TEMPLATES, BASE_DEV_DEPENDENCIES, BIN_CONFIGS, BIN_ENTRY_PATH, CATALOG_AGENT_PATH, CONFIG_TEMPLATES, CONTROL_CHARACTER_PATTERN, Compiler, DEFAULT_ENGINES, DEFAULT_VERSION, DEPENDENCY_NAME_PATTERN, ENGINES_PATTERN, ENVIRONMENTS, EXECUTABLE_PATHS, EXTRA_NAME_PATTERN, EXTRA_RANGE_PATTERN, GLOBAL_SETUP_PATH, GROUPS, GUIDES_TEST_PATH, HEX_PATTERN, HOST_PATHS, INTEGRATION_TEST_PATH, INVALID_PATH_CHARACTER_PATTERN, MAX_ARTIFACT_BYTES, MAX_ARTIFACT_HEX_LENGTH, MAX_AUDIT_FINDINGS, MAX_COLLECTION_ITEMS, MAX_DEPENDENCY_NAME_LENGTH, MAX_MANIFEST_BYTES, MAX_NAME_LENGTH, MAX_PATH_LENGTH, MAX_RANGE_LENGTH, MAX_TOTAL_ARTIFACT_BYTES, MINIMUM_NODE_VERSION, NAME_PATTERN, ORCHESTRATION_PATH_NAMES, ORCHESTRATION_PATH_PREFIXES, ORKESTREL_RANGE_PATTERN, SERVICE_SCRIPT_PATH, SHOWCASE_CONFIG_PATH, SHOWCASE_DEV_DEPENDENCIES, SOURCE_BROWSER_DEV_DEPENDENCIES, SRC_MATRIX, ScaffoldError, VERSION_PATTERN, applyOverrides, artifactToFinding, artifactToHex, artifactsToQuestions, blueprintToConfigArtifacts, blueprintToDevDependencies, blueprintToDocumentArtifacts, blueprintToGuideArtifacts, blueprintToMachinery, blueprintToManifest, blueprintToOrchestrationArtifacts, blueprintToQuestions, blueprintToRootTsconfig, blueprintToRootVite, blueprintToScripts, blueprintToSourceArtifacts, blueprintToTestArtifacts, bytesToHex, catalogToLayers, cloneValue, compareVersions, computeBytes, computeHash, contentToHex, createBlueprint, createCompiler, dependenciesToQuestions, extractVersion, inferDrift, inferGroup, isArtifact, isAudit, isBlueprint, isCatalogEntry, isCollection, isCompilerHooks, isCompilerOptions, isContent, isDependency, isDependencyName, isEnvironment, isFinding, isGroup, isGroups, isHex, isMirror, isOverride, isPath, isPlan, isQuestion, isScaffoldError, isSnapshot, manifestToDependencies, manifestToName, matchesDriftReachability, matchesEngines, matchesOrchestrationPath, matchesRange, nameToGuide, nameToHostArtifacts, overridesToQuestions, parseBlueprint, parseCompilerOptions, parseGroups, parseSnapshot, pathToCondition, planToFindings, planToHash, planToSummary, selectGroups, selectHostPaths, serializeTypeScriptString, srcToEntry, srcToExports, srcToRoot };
4421
+ export { APP_BROWSER_DEV_DEPENDENCIES, APP_DEV_DEPENDENCIES, APP_MATRIX, APP_SERVER_DEV_DEPENDENCIES, ARTIFACT_TEMPLATES, BASE_DEV_DEPENDENCIES, BIN_CONFIGS, BIN_ENTRY_PATH, CATALOG_AGENT_PATH, CONFIG_TEMPLATES, CONFORMANCE_TEST_PATH, CONTROL_CHARACTER_PATTERN, Compiler, DEFAULT_ENGINES, DEFAULT_VERSION, DEPENDENCY_NAME_PATTERN, ENGINES_PATTERN, ENVIRONMENTS, EXECUTABLE_PATHS, EXTRA_NAME_PATTERN, EXTRA_RANGE_PATTERN, GLOBAL_SETUP_PATH, GROUPS, GUIDES_TEST_PATH, HEX_PATTERN, HOST_PATHS, INTEGRATION_TEST_PATH, INVALID_PATH_CHARACTER_PATTERN, MAX_ARTIFACT_BYTES, MAX_ARTIFACT_HEX_LENGTH, MAX_AUDIT_FINDINGS, MAX_COLLECTION_ITEMS, MAX_DEPENDENCY_NAME_LENGTH, MAX_MANIFEST_BYTES, MAX_NAME_LENGTH, MAX_PATH_LENGTH, MAX_RANGE_LENGTH, MAX_TOTAL_ARTIFACT_BYTES, MINIMUM_NODE_VERSION, NAME_PATTERN, ORCHESTRATION_PATH_NAMES, ORCHESTRATION_PATH_PREFIXES, ORKESTREL_RANGE_PATTERN, SERVICE_SCRIPT_PATH, SERVICE_SETUP_PATH, SERVICE_TEST_INCLUDE, SHOWCASE_CONFIG_PATH, SHOWCASE_DEV_DEPENDENCIES, SOURCE_BROWSER_DEV_DEPENDENCIES, SRC_MATRIX, ScaffoldError, VERSION_PATTERN, applyOverrides, artifactToFinding, artifactToHex, artifactsToQuestions, blueprintToConfigArtifacts, blueprintToDevDependencies, blueprintToDocumentArtifacts, blueprintToGuideArtifacts, blueprintToMachinery, blueprintToManifest, blueprintToOrchestrationArtifacts, blueprintToQuestions, blueprintToRootTsconfig, blueprintToRootVite, blueprintToScripts, blueprintToSourceArtifacts, blueprintToTestArtifacts, bytesToHex, catalogToLayers, cloneValue, compareVersions, computeBytes, computeHash, contentToHex, createBlueprint, createCompiler, dependenciesToQuestions, extractVersion, inferDrift, inferGroup, isArtifact, isAudit, isBlueprint, isCatalogEntry, isCollection, isCompilerHooks, isCompilerOptions, isContent, isDependency, isDependencyName, isEnvironment, isFinding, isGroup, isGroups, isHex, isMirror, isOverride, isPath, isPlan, isQuestion, isScaffoldError, isSnapshot, manifestToDependencies, manifestToName, matchesDriftReachability, matchesEngines, matchesOrchestrationPath, matchesRange, nameToGuide, nameToHostArtifacts, overridesToQuestions, parseBlueprint, parseCompilerOptions, parseGroups, parseSnapshot, pathToCondition, planToFindings, planToHash, planToSummary, selectGroups, selectHostPaths, serializeTypeScriptString, srcToEntry, srcToExports, srcToRoot };
4340
4422
 
4341
4423
  //# sourceMappingURL=index.js.map