@orkestrel/scaffold 0.0.7 → 0.0.9

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.
@@ -134,6 +134,7 @@ From [`types.ts`](../../src/core/types.ts).
134
134
  | `SrcDefinition` | interface |
135
135
  | `AppDefinition` | interface |
136
136
  | `ViteMachinery` | interface |
137
+ | `ViteAxes` | interface |
137
138
  | `ViteProjectRegistration` | interface |
138
139
  | `Origin` | type |
139
140
  | `Group` | type |
@@ -191,6 +192,9 @@ single-file-component, HTML, and development-server machinery an application bro
191
192
  needs, and `output` for build-output containment. It never selects a boundary guarantee — those ship
192
193
  in every shape, as the compilers section sets out.
193
194
 
195
+ `ViteAxes` is the optional structural-project slice shared by every root Vite compiler:
196
+ `bin`, `integration`, and `service` each select their matching standalone project when `true`.
197
+
194
198
  `ViteProjectRegistration` carries one generated project factory identifier and its optional browser
195
199
  label. Root configuration renderers preserve that browser ownership as data through registration
196
200
  instead of inferring it from a project identifier.
@@ -210,19 +214,44 @@ interface Blueprint {
210
214
  readonly version: string
211
215
  readonly engines: string
212
216
  readonly overrides: readonly Override[]
213
- readonly engine: boolean
217
+ readonly bin: boolean
218
+ readonly integration: boolean
219
+ readonly service: boolean
214
220
  }
215
221
  ```
216
222
 
217
- `src` selects published library environments under `src`; `app` selects private runtime environments under
218
- `app`. The two axes are independent, so library-only, application-only, and mixed workspaces are
219
- all first class. `dependencies` and `peers` are runtime `@orkestrel/*` packages — a peer flagged
220
- `optional` also gets a `peerDependenciesMeta` entry. `extras` are package-specific development
221
- dependencies merged over the generated baseline, and may carry any valid npm package name. `engine`
222
- is structural, never inferred from a name: it is `true` only for a workspace that ships its own
223
- `src/bin`, and it alone turns on the self-hosting extras (a `bin` field, the `scaffold` script
224
- pointed at the built executable, the bin check, test, and build scripts, `build:host`, and the
225
- `src:bin` test project).
223
+ `src` selects published library environments under `src`; `app` selects private runtime
224
+ environments under `app`. The two axes are independent, so library-only, application-only, and
225
+ mixed workspaces are all first class. `dependencies` and `peers` are runtime `@orkestrel/*`
226
+ packages — a peer flagged `optional` also gets a `peerDependenciesMeta` entry. `extras` are
227
+ package-specific development dependencies merged over the generated baseline, and may carry any
228
+ valid npm package name.
229
+
230
+ `bin`, `integration`, and `service` are the three structural axes, and they obey one law: each is
231
+ `true` only when the workspace physically ships the directory that defines it — never because of
232
+ the workspace's name, and never because a sibling axis is set. `deriveBlueprint` probes exactly
233
+ those directories, so a fresh compile and an audit of a mature repository agree on what the
234
+ workspace is.
235
+
236
+ - **`bin`** — `src/bin/` exists. It alone turns on the self-hosting extras: the manifest's `bin`
237
+ entry, the `scaffold` script pointed at the built executable, the bin check, test, and build
238
+ scripts, `build:host`, the `configs/src/tsconfig.bin.json` and `configs/src/vite.bin.config.ts`
239
+ artifacts, and the `src:bin` test project.
240
+ - **`integration`** — `tests/integration/` exists. It records a slow, opt-in proof project over the
241
+ workspace's own built output, outside the default run: the generated root configuration registers
242
+ a standalone `integration` project including `tests/integration/**/*.test.ts`, and the manifest
243
+ emits `test:integration`.
244
+ - **`service`** — `tests/service/` exists. It records a slow, opt-in proof project against a foreign
245
+ running process, outside the default run: a standalone `service` project including
246
+ `tests/service/**/*.test.ts`, with `tests/setupService.ts` after the shared setup, and the
247
+ isolated `test:service` script.
248
+
249
+ A service workspace owes two companion files beside that directory, and derivation requires both
250
+ physically present: `tests/setupService.ts` and `scripts/service.sh`. Either missing companion is a
251
+ coded `TARGET` failure naming the missing path rather than a silent `service: false`. This package
252
+ emits neither: both are consumer-owned seams, and the generated-workspace section sets out what
253
+ each owes its workspace and which proof runs in which gate. Nothing here is inferred — the
254
+ executable axis turns on neither proof project, and neither proof project turns on the other.
226
255
 
227
256
  `Override` replaces a rendered artifact's content at a path, never partially merges it. `Member` is
228
257
  one declared public export of the scaffolded workspace, derived rather than authored.
@@ -327,8 +356,10 @@ From [`constants.ts`](../../src/core/constants.ts).
327
356
  | `FRESHNESS` | const |
328
357
  | `COMPILE_STAGES` | const |
329
358
  | `SRC_MATRIX` | const |
359
+ | `BIN_CONFIGS` | const |
330
360
  | `APP_MATRIX` | const |
331
361
  | `HOST_PATHS` | const |
362
+ | `SERVICE_SCRIPT_PATH` | const |
332
363
  | `NAME_PATTERN` | const |
333
364
  | `MAX_NAME_LENGTH` | const |
334
365
  | `MAX_DEPENDENCY_NAME_LENGTH` | const |
@@ -373,11 +404,13 @@ From [`constants.ts`](../../src/core/constants.ts).
373
404
  `ENVIRONMENTS`, `ORIGINS`, `GROUPS`, `CATEGORIES`, `FRESHNESS`, and `COMPILE_STAGES` are the frozen
374
405
  value lists behind their literal unions. `SRC_MATRIX` is the `src` environment matrix as
375
406
  data — each environment's `configs/src` files, test-project label, `exports` subpath, and build
376
- formats. `APP_MATRIX` is its application sibling, adding the runtime entry where an environment produces
377
- one (`app/browser/index.html`, `app/server/main.ts`). `HOST_PATHS` is the ordered list of
378
- byte-copied host artifacts, and it is the staging manifest rather than the per-plan carried set:
407
+ formats. `APP_MATRIX` is its application sibling, adding the runtime entry where an environment
408
+ produces one (`app/browser/index.html`, `app/server/main.ts`). `BIN_CONFIGS` is the executable
409
+ axis's computed `tsconfig` and Vite wrapper pair. `HOST_PATHS` is the ordered list of byte-copied
410
+ host artifacts, and it is the staging manifest rather than the per-plan carried set:
379
411
  `stageHost` vendors every path on it, while each plan carries the subset `selectHostPaths` selects
380
- for that one workspace.
412
+ for that one workspace. `SERVICE_SCRIPT_PATH` names the consumer-owned provisioner a service
413
+ workspace's audit expects.
381
414
 
382
415
  The bounds are public because they are part of the contract, not implementation trivia.
383
416
  `MAX_ARTIFACT_BYTES` caps one artifact at 5 MiB and `MAX_TOTAL_ARTIFACT_BYTES` caps one blueprint,
@@ -831,6 +864,7 @@ From [`helpers.ts`](../../src/server/helpers.ts).
831
864
  | Name | Kind |
832
865
  | -------------------------- | -------- |
833
866
  | `isRealDirectory` | function |
867
+ | `isRealFile` | function |
834
868
  | `digestFile` | function |
835
869
  | `digestHex` | function |
836
870
  | `digestText` | function |
@@ -893,7 +927,7 @@ so a file swapped mid-read is a failure rather than a silent wrong digest. `read
893
927
  strictly, rejecting invalid UTF-8. Manifest reads stop at `MAX_MANIFEST_BYTES`; catalog guide reads
894
928
  stop at `MAX_GUIDE_BYTES`. `listFiles` and `listDirectories` walk a real, unlinked root under the
895
929
  entry and depth bounds, returning sorted POSIX-relative paths and `[]` for an absent root.
896
- `isRealDirectory` is the physical-directory predicate they all lean on.
930
+ `isRealDirectory` and `isRealFile` are the physical path predicates they all lean on.
897
931
 
898
932
  The write-transaction helpers are the fail-closed mutation path. `createWriteDirectory` establishes
899
933
  a directory one segment at a time behind captured identities; `validateWriteAnchor`,
@@ -915,14 +949,17 @@ omitting an absent path entirely. `readManifest` reads `package.json` text, and
915
949
 
916
950
  `deriveBlueprint` is the faithful inverse an audit needs: it reconstructs a blueprint from an
917
951
  existing workspace so a mature package is diffed against its own would-be scaffold rather than a
918
- dependency-less stand-in. Environments come from `src/<environment>/` and `app/<environment>/`;
919
- `engine` is `true` only when `src/bin/` exists; dependencies and peers come from the manifest's
920
- scoped entries, with an optional peer recovered from `peerDependenciesMeta`; and `extras` is every
921
- development dependency minus the generated baseline and minus anything already declared as a
922
- dependency or peer, so a hand-added development dependency round-trips and stays audit-clean.
923
- Derivation yields no `overrides`: they are caller-time inputs, not repository state. A computed
924
- artifact that must differ reveals a gap in the canon; the blueprint grows an axis for that
925
- distinction rather than the repository forking the file.
952
+ dependency-less stand-in. Environments come from `src/<environment>/` and `app/<environment>/`, and
953
+ the three structural axes from the directory probes and the service companion law the blueprint
954
+ section states every one of them a reading of the filesystem, never of the name. Dependencies and
955
+ peers come from the manifest's scoped entries, with an optional peer recovered from
956
+ `peerDependenciesMeta`; and `extras` is every development dependency minus the complete set
957
+ `devDependenciesFor` emits for those environments and structural axes, and minus anything already
958
+ declared as a dependency or peer. An axis-emitted dependency is therefore never double-counted,
959
+ while a hand-added development dependency round-trips and stays audit-clean. Derivation yields no
960
+ `overrides`: they are caller-time inputs, not repository state. A computed artifact that must differ
961
+ reveals a gap in the canon; the blueprint grows an axis for that distinction rather than the
962
+ repository forking the file.
926
963
 
927
964
  `storagePath`, `stageHost`, `readHostManifest`, `locateHostSource`, `remapArtifactPath`, and
928
965
  `hydratePlan` are the vendored-host path. `storagePath` maps a repo-relative path to its un-dotted
@@ -961,44 +998,52 @@ ordered guide and version outcomes.
961
998
 
962
999
  From [`compilers.ts`](../../src/core/compilers.ts).
963
1000
 
964
- | Name | Kind |
965
- | ----------------------- | -------- |
966
- | `hostGroup` | function |
967
- | `fillArtifact` | function |
968
- | `srcVariant` | function |
969
- | `entryFields` | function |
970
- | `dualCondition` | function |
971
- | `exportsMap` | function |
972
- | `compareCodeUnit` | function |
973
- | `devDependenciesFor` | function |
974
- | `packageManifest` | function |
975
- | `rootTsconfig` | function |
976
- | `viteMachinery` | function |
977
- | `renderViteTest` | function |
978
- | `viteHeader` | function |
979
- | `policyViteProject` | function |
980
- | `singleSrcViteConfig` | function |
981
- | `rootViteConfig` | function |
982
- | `applicationViteConfig` | function |
983
- | `coreTsconfig` | function |
984
- | `coreViteConfig` | function |
985
- | `srcTsconfig` | function |
986
- | `srcViteConfig` | function |
987
- | `appTsconfig` | function |
988
- | `appViteConfig` | function |
989
- | `ciWorkflow` | function |
990
- | `configArtifacts` | function |
991
- | `sourceArtifacts` | function |
992
- | `applicationArtifacts` | function |
993
- | `paritySpecifiers` | function |
994
- | `testArtifacts` | function |
995
- | `guideMemberTable` | function |
996
- | `guideUsage` | function |
997
- | `guideMethods` | function |
998
- | `guideTests` | function |
999
- | `guideArtifacts` | function |
1000
- | `applyOverrides` | function |
1001
- | `blueprintToPlan` | function |
1001
+ | Name | Kind |
1002
+ | -------------------------- | -------- |
1003
+ | `hostGroup` | function |
1004
+ | `fillArtifact` | function |
1005
+ | `srcVariant` | function |
1006
+ | `entryFields` | function |
1007
+ | `dualCondition` | function |
1008
+ | `exportsMap` | function |
1009
+ | `compareCodeUnit` | function |
1010
+ | `devDependenciesFor` | function |
1011
+ | `packageManifest` | function |
1012
+ | `rootTsconfig` | function |
1013
+ | `viteMachinery` | function |
1014
+ | `renderViteTest` | function |
1015
+ | `viteHeader` | function |
1016
+ | `policyViteProject` | function |
1017
+ | `guidesViteProject` | function |
1018
+ | `binViteProject` | function |
1019
+ | `integrationViteProject` | function |
1020
+ | `serviceViteProject` | function |
1021
+ | `viteProjectRegistrations` | function |
1022
+ | `viteProjectDefinitions` | function |
1023
+ | `singleSrcViteConfig` | function |
1024
+ | `rootViteConfig` | function |
1025
+ | `applicationViteConfig` | function |
1026
+ | `coreTsconfig` | function |
1027
+ | `coreViteConfig` | function |
1028
+ | `srcTsconfig` | function |
1029
+ | `srcViteConfig` | function |
1030
+ | `binTsconfig` | function |
1031
+ | `binViteConfig` | function |
1032
+ | `appTsconfig` | function |
1033
+ | `appViteConfig` | function |
1034
+ | `ciWorkflow` | function |
1035
+ | `configArtifacts` | function |
1036
+ | `sourceArtifacts` | function |
1037
+ | `applicationArtifacts` | function |
1038
+ | `paritySpecifiers` | function |
1039
+ | `testArtifacts` | function |
1040
+ | `guideMemberTable` | function |
1041
+ | `guideUsage` | function |
1042
+ | `guideMethods` | function |
1043
+ | `guideTests` | function |
1044
+ | `guideArtifacts` | function |
1045
+ | `applyOverrides` | function |
1046
+ | `blueprintToPlan` | function |
1002
1047
 
1003
1048
  `blueprintToPlan` is the whole pure compilation: draft each selected group's artifacts, append the
1004
1049
  host set, apply overrides, and pin. Everything above it is an exported leaf of that drafting, each
@@ -1008,10 +1053,11 @@ independently callable and independently tested.
1008
1053
  several. `entryFields`, `dualCondition`, and `exportsMap` build the manifest entry fields and the
1009
1054
  `exports` map from that variant; a browser-only package exports a single module condition, while
1010
1055
  core and server src get dual import and require conditions with matching declaration files.
1011
- `devDependenciesFor` merges a blueprint's extras over the shared baseline, extras winning a name
1012
- collision, sorted by `compareCodeUnit` so ordering is stable across locales. `packageManifest`
1013
- assembles the whole file name, publication mode, files, scripts, dependencies, peers and their
1014
- optional metadata, and engines.
1056
+ `devDependenciesFor` emits the blueprint's complete development dependency set: the shared
1057
+ baseline, package extras, dev-installed peers, selected browser toolchains, and the bin axis's
1058
+ browser test provider. Extras and peers are sorted by `compareCodeUnit` so ordering is stable across
1059
+ locales. `packageManifest` assembles the whole file — name, publication mode, files, scripts,
1060
+ dependencies, peers and their optional metadata, and engines.
1015
1061
 
1016
1062
  `rootTsconfig` emits the root compiler options and one path alias per declared environment;
1017
1063
  `coreTsconfig`, `srcTsconfig`, and `appTsconfig` emit the scoped configurations that remove the
@@ -1047,17 +1093,36 @@ along the three `ViteMachinery` axes:
1047
1093
  An application of `app/core` alone is the sole shape that builds nothing, so it is the sole shape
1048
1094
  without output containment — and it still carries every boundary guarantee above.
1049
1095
 
1050
- `renderViteTest` is the single root-project renderer. It consumes ordered
1051
- `ViteProjectRegistration` data and emits either the plain project list or the browser gate, keeping
1052
- source and application root configurations byte-consistent without reconstructing browser ownership.
1053
-
1054
- `coreViteConfig`, `srcViteConfig`, and `appViteConfig` emit the thin per-target wrappers;
1055
- `rootViteConfig`, `singleSrcViteConfig`, and `applicationViteConfig` emit the root configuration for
1056
- a library-only, single non-core `src` environment, and application-bearing workspace respectively;
1057
- `policyViteProject` emits the dedicated Node-only repository-policy test project.
1096
+ `renderViteTest` is the single root-project renderer. It consumes ordered `ViteProjectRegistration`
1097
+ data and emits either the plain project list or the browser gate, keeping source and application
1098
+ root configurations byte-consistent without reconstructing browser ownership.
1099
+ `viteProjectRegistrations` is the one registration derivation every root shape consumes: it derives
1100
+ the selected source and application projects from the canonical environment order, then appends
1101
+ `policy`, `guides`, and the optional `srcBin`, `integration`, and `service` projects.
1102
+ `viteProjectDefinitions` renders the standalone proof and structural-axis definitions in that same
1103
+ order with one blank line between declarations. Both consume `ViteAxes`, so each optional project is
1104
+ controlled only by its matching `bin`, `integration`, or `service` blueprint axis.
1105
+
1106
+ `coreViteConfig`, `srcViteConfig`, `binViteConfig`, and `appViteConfig` emit the thin per-target
1107
+ wrappers, while `binTsconfig` emits the executable declaration scope; `rootViteConfig`,
1108
+ `singleSrcViteConfig`, and `applicationViteConfig` emit the root configuration for a library-only,
1109
+ single non-core `src` environment, and application-bearing workspace respectively; and
1110
+ `policyViteProject`, `guidesViteProject`, `integrationViteProject`, and `serviceViteProject` emit
1111
+ the standalone Node proof projects, with `binViteProject` the single executable-project emitter. A
1112
+ proof project is structurally derived from the directory holding its tests and never wraps a source
1113
+ or application environment project. The guides project therefore uses only `tests/setup.ts`, never
1114
+ `setupServer.ts`, `setupBrowser.ts`, or `setupService.ts`; and its `tests/src/**/*.test.ts` and
1115
+ `tests/app/**/*.test.ts` exclude rows are uniform across all root shapes by design, including
1116
+ core-only workspaces where one row cannot currently match. Integration and service use 120-second
1117
+ test and hook timeouts with file parallelism disabled, and service alone layers
1118
+ `tests/setupService.ts` onto the shared setup. Where a bin workspace also ships the integration
1119
+ project, that project wires `tests/setupIntegration.ts` as its global setup for the shared
1120
+ template-registry harness; bin-less integration workspaces do not.
1058
1121
 
1059
1122
  `configArtifacts`, `sourceArtifacts`, `applicationArtifacts`, `testArtifacts`, and `guideArtifacts`
1060
- are the per-group drafters. `paritySpecifiers` computes the self-specifier and module map the
1123
+ are the per-group drafters. When `bin` is selected, `configArtifacts` includes
1124
+ `configs/src/tsconfig.bin.json` and `configs/src/vite.bin.config.ts` beside the declared environment
1125
+ configuration pairs. `paritySpecifiers` computes the self-specifier and module map the
1061
1126
  generated parity suite resolves fence imports through. `guideMemberTable`, `guideUsage`,
1062
1127
  `guideMethods`, and `guideTests` render the generated guide's member tables, usage examples, method
1063
1128
  contract, and test inventory. `fillArtifact` fills one template entry into a `template`-origin
@@ -1286,13 +1351,13 @@ Audit semantics follow directly from that.
1286
1351
  - A target file the plan does not own is `foreign`, and `inferGroup` classifies it by its leading
1287
1352
  path segment.
1288
1353
 
1289
- The same ownership boundary is what makes mutation safe. **`repair` and `fleet` mutate host-origin
1290
- artifacts only.** Both scope the compiled plan to host origin before hydrating, diffing, or applying
1291
- anything, so a mature workspace's hand-written source, tests, guides, and manifest are never
1292
- overwritten with a stub. A consequence worth stating plainly: the generated
1293
- `.github/workflows/ci.yml` is a **computed** artifact, so **user-owned CI is never repaired**. Once
1294
- a workspace has its own workflow, that copy stands, and any change to it is an ordinary edit in that
1295
- workspace. Audit still compares it because computed artifacts are content-aware canon. A legitimate
1354
+ The same ownership boundary is what makes mutation safe. **`fleet` and default `repair` both scope
1355
+ the compiled plan to host origin before hydrating, diffing, or applying.** `--generated` widens that
1356
+ scoped plan to generated canon except `package.json`; template artifacts remain birth-only in
1357
+ either mode. A mature workspace's hand-written source, tests, guides, and manifest are therefore
1358
+ never overwritten with a stub. The generated `.github/workflows/ci.yml` is a **computed** artifact,
1359
+ so user-owned CI stands by default but is intentionally restored when `--generated` is passed.
1360
+ Audit always compares it because computed artifacts are content-aware canon. A legitimate
1296
1361
  difference that the blueprint cannot express is a canon gap: add the missing blueprint axis rather
1297
1362
  than forking the computed file in one repository.
1298
1363
 
@@ -1324,12 +1389,20 @@ An audit is a pure function of a plan and a snapshot, so the same engine that cr
1324
1389
  checks one. `readTarget` supplies the snapshot as exact bytes; `diffPlan` returns findings as data;
1325
1390
  `auditToReview` renders them for a human. Nothing in that path writes.
1326
1391
 
1392
+ The executable's physical unexpected-file scan treats exactly `scripts/service.sh` as an expected
1393
+ consumer-owned seam when the derived blueprint has `service: true`. That exclusion is warranted
1394
+ because a service blueprint cannot derive without the physical file: the companion-file law raises
1395
+ a `TARGET` failure first, so the scan removes a false positive and can never mask an absent
1396
+ provisioner. A non-service workspace still reports the same path as foreign.
1397
+
1327
1398
  `repair` turns those findings back into the narrowest possible write. It re-reads the target,
1328
1399
  re-diffs it, and refuses to proceed if the findings changed since the preview it was given — a
1329
1400
  target that moved under the caller is a `TARGET` failure, not a race to win. It then derives a write
1330
1401
  precondition per artifact from the audit itself: a `missing` finding requires the destination to
1331
1402
  still be absent, a `stale` finding requires it to still carry exactly the bytes that were observed.
1332
1403
  Those preconditions are checked again inside the write transaction before any promotion.
1404
+ An interactive audit repair hand-off forwards `--generated` into the repair invocation when the
1405
+ flag was present on `audit`.
1333
1406
 
1334
1407
  `prune` is the deletion arm, and it is deliberately narrow. Its candidate set comes from
1335
1408
  `pruneTargets`, which is also what the executable's audit and preview read, so what is reported and
@@ -1400,24 +1473,65 @@ configuration, and ships `dist/src` plus its README. An application-only workspa
1400
1473
  that builds its own executable additionally ships `dist/bin` and `dist/host`. Scripts are emitted in
1401
1474
  a fixed, interleaved order so aggregates sit immediately before their per-environment members:
1402
1475
 
1403
- - `clean`, `copy`, `scaffold`
1404
- - `lint` and `lint:check`, `format` and `format:check`
1476
+ - `clean`, `copy`, `scaffold`, `lint`
1405
1477
  - `check`, then `check:src` with one `check:src:<environment>` per published environment, then
1406
1478
  `check:app` with one `check:app:<environment>` per app environment — the browser app scope uses the
1407
1479
  Vue typechecker, every other scope uses plain `tsc`
1408
- - `test`, then `test:src` and its per-environment scopes, `test:app` and its per-environment scopes,
1409
- `test:policy`, and `test:guides`; an engine also receives the deliberately non-default
1410
- `test:integration` live installed-consumer gate and `test:equivalence` driver-reference proof
1480
+ - `format`, `format:check`, `lint:check`
1481
+ - `test`, then `test:src` and its per-environment scopes, the optional `test:integration`,
1482
+ `test:equivalence`, and `test:service` proofs, `test:app` and its per-environment scopes, then
1483
+ `test:policy` and `test:guides`
1411
1484
  - `build`, then `build:src` and its per-environment targets, `build:app` and its runtime targets, and
1412
- `build:host` for an engine workspace
1485
+ `build:host` for a bin workspace
1413
1486
  - `dev` when a browser application is selected; `serve` and `serve:build` when a server application
1414
1487
  is selected
1415
- - `prepublishOnly` chaining `format:check → lint:check → check → build → test`, followed by the
1416
- live generated-consumer integration gate for the scaffold engine itself
1417
-
1418
- Run `npm run test:equivalence` after changing the persistent boundary build driver. It reruns the
1488
+ - `prepublishOnly` chaining `format:check → lint:check → check → build → test`, followed by
1489
+ `test:integration` when the integration axis is selected
1490
+
1491
+ **Proof gating.** The opt-in proofs are predictable from the axes alone. `test:integration` rides
1492
+ the `integration` axis and `test:service` the `service` axis, while `test:equivalence` is emitted
1493
+ only where `bin` and `integration` are both set:
1494
+
1495
+ | Proof | `npm test` | `prepublishOnly` | CI |
1496
+ | ------------------ | ---------- | ---------------- | -------------------------- |
1497
+ | `test:integration` | no | yes, last | after the standard gates |
1498
+ | `test:equivalence` | no | no | no |
1499
+ | `test:service` | no | never | after `scripts/service.sh` |
1500
+
1501
+ No proof joins the default chain: `npm test` runs the source, application, policy, and guide
1502
+ projects, and nothing there needs a build artifact or a foreign process. Publication is the one
1503
+ asymmetry — `prepublishOnly` appends `test:integration`, because a package about to be published
1504
+ should prove itself against its own built output, while `test:service` is never in that chain.
1505
+ Neither default testing nor publication starts or requires a foreign process.
1506
+
1507
+ When a prerequisite is absent the proof fails rather than skipping. `test:integration` reads the
1508
+ workspace's own built output, so it belongs after `build` — which is exactly where `prepublishOnly`
1509
+ and CI put it. `test:service` refuses to start against an unprovisioned service: its setup throws at
1510
+ module load, which is why CI runs `bash scripts/service.sh` immediately before it. And a script the
1511
+ axes do not emit is simply not there: `test:equivalence` in a workspace that is not both `bin` and
1512
+ `integration` is an unknown script rather than a quietly passing one.
1513
+
1514
+ The equivalence proof is a dual-path re-run rather than a separate suite. Run
1515
+ `npm run test:equivalence` after changing the persistent boundary build driver; it invokes the
1419
1516
  integration project in dual-path mode and proves each programmatic driver verdict against the
1420
- spawned npm-script reference; ordinary integration runs keep the faster driver-only path.
1517
+ spawned npm-script reference. Ordinary integration runs keep the faster driver-only path.
1518
+
1519
+ **Consumer-owned service seams.** The service axis is the one place canon stops at the boundary:
1520
+ there is no template for a proof project and neither companion path is on `HOST_PATHS`, so a
1521
+ service workspace owns both of its seams outright. They come as a pair.
1522
+
1523
+ - `tests/setupService.ts` is the readiness seam. It probes the foreign process and warms it before
1524
+ any test runs, and throws at module load — naming the `service` project — when that process is
1525
+ unreachable, so an unprovisioned run fails loudly instead of passing an empty suite. Only the
1526
+ `service` project loads it.
1527
+ - `scripts/service.sh` is the provisioning seam, named once by `SERVICE_SCRIPT_PATH`. It brings that
1528
+ process up idempotently — a second run against an already-provisioned service is a no-op rather
1529
+ than a second instance — and exits nonzero when it cannot, which is what makes CI's
1530
+ `bash scripts/service.sh` step a gate rather than a hint.
1531
+
1532
+ The audit expects the script rather than reporting it foreign, on the derive-time warrant the audit
1533
+ section gives. Repair pruning applies the same exclusion, so it never proposes or removes that
1534
+ required consumer-owned provisioner.
1421
1535
 
1422
1536
  **Environment isolation.** Scoped TypeScript projects remove the wrong host's globals from each
1423
1537
  environment: core scopes carry the WHATWG web-interop surface and no host at all — no DOM, no Node,
@@ -1575,7 +1689,8 @@ Node `22.12.0` and `26`** with fail-fast disabled. Checkout and Node setup are p
1575
1689
  action commits, and checkout does not persist credentials. Dependencies install with
1576
1690
  `npm ci --ignore-scripts`; Chromium is installed only when the workspace selects a browser environment
1577
1691
  or builds its own executable. The gates then run in order: `format:check`, `lint:check`, `check`,
1578
- `build`, `test`; engine workspaces then run the separate live installed-consumer integration gate.
1692
+ `build`, `test`, and the workspace's selected proofs follow as their own named steps, in the order
1693
+ the proof-gating table gives them.
1579
1694
 
1580
1695
  **Agent orchestration files.** The session hooks in the generated `.claude/settings.json` run the
1581
1696
  dependency, model, and external-tool readiness scripts at session start. The **`Stop` hook runs only
@@ -1604,7 +1719,7 @@ no module API of its own. Six verbs:
1604
1719
  | `new` | scaffold a workspace into `./<name>` |
1605
1720
  | `pull` | refresh vendored guides and versions, report drift |
1606
1721
  | `audit` | whole-plan conformance report |
1607
- | `repair` | restore the shared host-owned set |
1722
+ | `repair` | restore host-owned files and optional generated canon |
1608
1723
  | `fleet` | audit or repair every workspace under the cwd's children |
1609
1724
  | `catalog` | regenerate the fleet package-catalog table |
1610
1725
 
@@ -1625,8 +1740,10 @@ declared dependency mirror is considered.
1625
1740
  `--groups a,b` scopes an audit to artifact groups. `--live` adds an upstream freshness check to an
1626
1741
  audit. `--strict` makes a pull throw on a network fault. `--offline` restricts a catalog to local
1627
1742
  sources. `--prune` opts a repair or fleet run into deleting unexpected files under the three prune
1628
- directories. `--json` emits one machine-readable value. `--apply` writes, `--yes` skips the
1629
- confirmation, and `-h` or `--help` prints usage.
1743
+ directories. `--generated` opts a repair or fleet run into restoring generated canon except
1744
+ `package.json`; on `audit`, it is inherited if the interactive repair hand-off is accepted.
1745
+ `--json` emits one machine-readable value. `--apply` writes, `--yes` skips the confirmation, and
1746
+ `-h` or `--help` prints usage.
1630
1747
 
1631
1748
  **Safety model.** Every verb is a dry run by default. On a terminal a write asks for confirmation
1632
1749
  first, defaulting to no; in a script, `--apply` writes and `--yes` skips the question. Every write is
@@ -1636,8 +1753,9 @@ non-interactive session without `--apply` or `--yes` skips pruning rather than g
1636
1753
  operates on the immediate children of the working directory and never on the directory itself, and
1637
1754
  it has no root flag at all — `repair` is the single-workspace tool.
1638
1755
 
1639
- Both `repair` and `fleet` are scoped to host-origin artifacts, and the executable states that scope
1640
- in its own output: starter and generated files are never touched.
1756
+ `fleet` and default `repair` are scoped to host-origin artifacts. `repair` states its selected scope
1757
+ in the output; `--generated` widens both verbs to generated files while still excluding starter
1758
+ files and `package.json`.
1641
1759
 
1642
1760
  **Catalog markers.** `catalog` rewrites the block between `<!-- catalog:start -->` and
1643
1761
  `<!-- catalog:end -->` in `.claude/agents/orkestrel.md`. **Ambiguous markers fail before any
@@ -1990,7 +2108,7 @@ srcVariant(['core', 'server']) // 'multi'
1990
2108
  entryFields(['browser']).main // './dist/src/browser/index.js'
1991
2109
  dualCondition('./dist/src/core/index')
1992
2110
  exportsMap(['core'])['.']
1993
- devDependenciesFor(spec.extras).typescript
2111
+ devDependenciesFor(spec).typescript
1994
2112
  packageManifest(spec) // the whole manifest, newline-terminated
1995
2113
 
1996
2114
  configArtifacts(spec).length
@@ -2020,17 +2138,23 @@ import {
2020
2138
  appTsconfig,
2021
2139
  appViteConfig,
2022
2140
  applicationViteConfig,
2141
+ binViteProject,
2023
2142
  coreTsconfig,
2024
2143
  coreViteConfig,
2144
+ guidesViteProject,
2145
+ integrationViteProject,
2025
2146
  policyViteProject,
2026
2147
  renderViteTest,
2027
2148
  rootTsconfig,
2028
2149
  rootViteConfig,
2150
+ serviceViteProject,
2029
2151
  singleSrcViteConfig,
2030
2152
  srcTsconfig,
2031
2153
  srcViteConfig,
2032
2154
  viteHeader,
2033
2155
  viteMachinery,
2156
+ viteProjectDefinitions,
2157
+ viteProjectRegistrations,
2034
2158
  } from '@orkestrel/scaffold'
2035
2159
 
2036
2160
  rootTsconfig(['core'], ['core', 'server'])
@@ -2046,8 +2170,15 @@ coreViteConfig()
2046
2170
  srcViteConfig('browser')
2047
2171
  appViteConfig('server')
2048
2172
  policyViteProject()
2049
-
2050
- rootViteConfig(['core', 'server'])
2173
+ guidesViteProject()
2174
+ binViteProject()
2175
+ integrationViteProject({ bin: true, integration: true })
2176
+ serviceViteProject()
2177
+ viteProjectDefinitions({ integration: true }).includes('export const integration =') // true
2178
+ viteProjectRegistrations(['core'], [], { integration: true }).map(({ project }) => project)
2179
+ // ['srcCore', 'policy', 'guides', 'integration']
2180
+
2181
+ rootViteConfig(['core', 'server'], { bin: true })
2051
2182
  singleSrcViteConfig('server').includes('srcServer') // true
2052
2183
  applicationViteConfig([], ['core', 'server']).includes('appServer') // true
2053
2184
  ```
@@ -2152,6 +2283,7 @@ import {
2152
2283
  discoverPackages,
2153
2284
  guideToDescription,
2154
2285
  isRealDirectory,
2286
+ isRealFile,
2155
2287
  listDirectories,
2156
2288
  listFiles,
2157
2289
  pruneTargets,
@@ -2166,6 +2298,7 @@ deriveBlueprint('./packages/router') // the faithful inverse an audit diffs agai
2166
2298
  selectOrkestrelEntries({ '@orkestrel/contract': '^0.0.7', vite: '^8.1.5' })
2167
2299
 
2168
2300
  isRealDirectory('./packages/router')
2301
+ isRealFile('./packages/router/package.json')
2169
2302
  listFiles('./packages/router/.claude/agents')
2170
2303
  listDirectories('./packages/router/.claude')
2171
2304