@orkestrel/scaffold 0.0.6 → 0.0.7

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.
@@ -212,7 +212,7 @@ verifies its CLI is present before running and stops with a deviation report nam
212
212
  fallback when it is not. Benches are cross-provider reach only: a model native to the running
213
213
  harness never crosses a bridge.
214
214
 
215
- Three bench laws apply to every external engine:
215
+ Four bench laws apply to every external engine:
216
216
 
217
217
  - **Transport by work class.** A short interactive exchange (one bounded question or a
218
218
  follow-up on a live thread, expected to finish in about two minutes) may use an MCP
@@ -221,19 +221,27 @@ Three bench laws apply to every external engine:
221
221
  session invisibly, while a journal survives any client-side failure.
222
222
  - **Journal first.** Every bench invocation leaves a tailable on-disk record under
223
223
  `tmp/<bench>/` (`tmp/codex/`, `tmp/cursor/`): the brief as a file, the event stream or
224
- output log, and the final answer. The user tails the journal for live progress; the
225
- journal's mtime is the liveness signal; the session id in the journal head is the recovery
226
- handle. Briefs never travel as fragile shell arguments.
224
+ output log, and the final answer. Every long exec also carries exactly one Monitor on its
225
+ journal a filtered tail that emits milestones (commands run, files changed, agent
226
+ messages, terminal states) and never the raw event firehose — so progress arrives in the
227
+ conversation while the journal stays tailable for depth. The filter exits on the exec's
228
+ terminal event, so the monitor's lifecycle matches the exec's and no watcher outlives its
229
+ subject. The journal's mtime is the liveness signal; the session id in the journal head is
230
+ the recovery handle. Briefs never travel as fragile shell arguments.
231
+ - **Tracked, never loose.** Every bench unit is registered in the session task registry at
232
+ launch — subject, journal path, session id — and completed there at acceptance, so "what is
233
+ running" always has a first-class answer instead of a recollection of a command.
227
234
  - **Ephemeral journals.** Everything under `tmp/` is unit evidence, never committed. Bridges
228
235
  never delete journals; the Orchestrator sweeps `tmp/codex/` and `tmp/cursor/` once at
229
236
  campaign acceptance, after the final gate evidence is recorded. A journal surviving past
230
237
  its campaign is residue.
231
238
 
232
- For a long-running bridge exec the Orchestrator arms a stall watcher on the journal
233
- (file-exists on the final answer, mtime-stall threshold of a few minutes) instead of trusting
234
- the bridge to report failure a wedged bridge is silent, and silence must never read as
235
- progress. A stalled journal follows the deviation ladder, with the session id from the
236
- journal head as the recovery handle.
239
+ Every long bench exec is launched by the Orchestrator as a harness-tracked background command
240
+ under a hard time cap, never detached from inside a bridge agent: the harness owns the
241
+ lifecycle, completion re-invokes the session, and the cap kills a wedged bench loudly instead
242
+ of trusting the bridge to report its own failure. A wedged bridge is silent, and silence must
243
+ never read as progress. A stalled journal or a cap-killed exec follows the deviation ladder,
244
+ with the session id from the journal head as the recovery handle.
237
245
 
238
246
  ### Cursor Grok
239
247
 
@@ -244,6 +252,10 @@ journal head as the recovery handle.
244
252
  `"$LOCALAPPDATA/cursor-agent/agent.cmd"` — verified with `--version` before first use. Long
245
253
  briefs are written to `tmp/cursor/<unit>-brief.md` and the prompt points at the file. The
246
254
  tee'd log is the bench's journal.
255
+ - A long ask-mode run obeys the same launch, stream, and ledger discipline as a Codex exec:
256
+ the Orchestrator starts it as a harness-tracked background command under a time cap,
257
+ registers the unit in the task registry, and arms one Monitor on the tee'd log for
258
+ milestones. The `grok` bridge drafts the brief; it never detaches a run and ends its turn.
247
259
  - Read-only. `--force` never appears. Nothing it returns is applied.
248
260
  - Read the exact model id from `agent models` and store it in `CURSOR_GROK_MODEL`. Never guess
249
261
  or substitute.
@@ -260,11 +272,12 @@ journal head as the recovery handle.
260
272
  - Reached from Claude Code only through the `codex` role, on journaled, resumable
261
273
  `codex exec`; in a Codex session these are native agents.
262
274
  - **Every run is journaled and resumable.** `--json` streams the event log to
263
- `tmp/codex/<unit>.jsonl` (gitignored; the user tails it live for progress nobody polls),
264
- `--output-last-message` captures the final answer as a file, and the session id from the
265
- journal head goes in every bridge report so follow-ups continue the same session via
266
- `codex exec resume <session-id>` with context intact. `--output-schema` is available when
267
- the Orchestrator wants a machine-checkable return shape.
275
+ `tmp/codex/<unit>.jsonl` (gitignored; the Monitor emits its milestones and the user tails it
276
+ for depth — nobody polls), `--output-last-message` captures the final answer as a file, and
277
+ the session id from the journal head goes in the unit's task registry entry and every bridge
278
+ report so follow-ups continue the same session via `codex exec resume <session-id>` with
279
+ context intact. `--output-schema` is available when the Orchestrator wants a
280
+ machine-checkable return shape.
268
281
  - **Transport is chosen by work class.** The MCP wiring (`.mcp.json` registers
269
282
  `codex mcp-server`; verified tools `codex` to start a session, `codex-reply` to continue
270
283
  one; settings enable project MCP servers without prompting, so the wiring works headless —
@@ -272,19 +285,27 @@ journal head as the recovery handle.
272
285
  short interactive exchanges only, and the bridge persists the thread id to
273
286
  `tmp/codex/<unit>.session` the moment a response carries it — an interrupted MCP call with
274
287
  no persisted id is unrecoverable and treated as failed. Long-running work (audits,
275
- implementation units) always uses the journaled CLI: the brief at
276
- `tmp/codex/<unit>-brief.md`, one `codex exec --json` streaming to `tmp/codex/<unit>.jsonl`
277
- with `--output-last-message`, foreground when it fits the shell cap, backgrounded with the
278
- turn ended when it may not the harness re-invocation is the wait; placeholder loops and
279
- wait-promise reports are deviations. Every exec names its working directory with `-C`, and an
280
- exec rooted outside a trusted git repository dies at launch unless `--skip-git-repo-check` is
281
- passed, so cross-repo and fleet-container work rooted outside a checkout always passes it. A
282
- launch is not a launch until the journal grows past its header: the bridge confirms the event
283
- stream advanced beyond the session-configured head
284
- before it reports the exec started, and treats an instantly-dead journal as a failed launch
285
- whose tail is the evidence. Recovery ladder on interruption: persisted-id
286
- `codex-reply` re-emission fresh CLI session with the same brief file for an interrupted
287
- CLI exec, the journal survives and the Orchestrator chooses resume or fresh.
288
+ implementation units) always uses the journaled CLI, and the Orchestrator — never a bridge
289
+ agent launches it as a harness-tracked background command: the brief at
290
+ `tmp/codex/<unit>-brief.md`, then one
291
+ `timeout <cap> codex exec --json < /dev/null > tmp/codex/<unit>.jsonl` with
292
+ `--output-last-message`, started through the shell's background-task mechanism so the exec
293
+ appears in the session's task list, its completion re-invokes the session, and the cap kills
294
+ a wedged bench loudly. Stdin is always closed with `< /dev/null`: a background-launched exec
295
+ can inherit an open stdin pipe and wedge forever at "Reading additional input from stdin..."
296
+ before its first event, and a cap kill is the only thing that would ever surface it.
297
+ The journal remains the durable, resumable record and the session id the recovery handle. A
298
+ bridge that backgrounds an exec and ends its turn orphans it — no owner, no completion
299
+ signal, no death notice so bridges keep two jobs only: drafting briefs and short MCP
300
+ exchanges. Placeholder wait loops and wait-promise reports are deviations. Every exec names
301
+ its working directory with `-C`, and an exec rooted outside a trusted git repository dies at
302
+ launch unless `--skip-git-repo-check` is passed, so cross-repo and fleet-container work
303
+ rooted outside a checkout always passes it. A launch is not a launch until the journal grows
304
+ past its header: the Orchestrator confirms the event stream advanced beyond the
305
+ session-configured head before recording the exec started, and treats an instantly-dead
306
+ journal as a failed launch whose tail is the evidence. Recovery ladder on interruption:
307
+ persisted-id `codex-reply` re-emission → fresh CLI session with the same brief file → for an
308
+ interrupted CLI exec, the journal survives and the Orchestrator chooses resume or fresh.
288
309
  - **The inverse bridge exists too:** Claude Code exposes `claude mcp serve`, registered in
289
310
  Codex's global config (`codex mcp add claude -- claude mcp serve`) so Codex-primary
290
311
  sessions reach Claude/Opus as first-class MCP tools instead of shelling to the CLI.
@@ -294,6 +315,11 @@ journal head as the recovery handle.
294
315
  - `implementer` runs `gpt-5.6-sol` at high effort with `--sandbox workspace-write` in the
295
316
  main checkout as the sole writer from a clean committed baseline, for bounded
296
317
  implementation.
318
+ - **The exec sandbox denies network** (`--unshare-net`). Any unit that needs the registry or
319
+ any other remote endpoint — lockfile generation, real installs, live fetches — belongs to
320
+ the Orchestrator's own tracked commands or a network-capable native agent, never to a Codex
321
+ exec. A Sol exec observed hanging on `npm` until its cap fires is the signature of this
322
+ misroute, not of a slow bench.
297
323
  - Raise the analyst to `xhigh` only for a stated hard reasoning need. `gpt-5.6-terra` serves
298
324
  only explicitly mechanical, taste-free roles. `gpt-5.6-luna` requires a proven repeatable,
299
325
  high-volume workload.
@@ -127,49 +127,50 @@ plan.artifacts.some((artifact) => artifact.path === 'app/server/main.ts') // tru
127
127
 
128
128
  From [`types.ts`](../../src/core/types.ts).
129
129
 
130
- | Name | Kind |
131
- | ---------------------- | --------- |
132
- | `Environment` | type |
133
- | `BuildFormat` | type |
134
- | `SrcDefinition` | interface |
135
- | `AppDefinition` | interface |
136
- | `ViteMachinery` | interface |
137
- | `Origin` | type |
138
- | `Group` | type |
139
- | `Category` | type |
140
- | `CatalogEntry` | interface |
141
- | `Drift` | type |
142
- | `Freshness` | type |
143
- | `CompileStage` | type |
144
- | `ScaffoldErrorCode` | type |
145
- | `Dependency` | interface |
146
- | `Override` | interface |
147
- | `Blueprint` | interface |
148
- | `Member` | interface |
149
- | `ArtifactBase` | interface |
150
- | `HostArtifact` | interface |
151
- | `ContentArtifact` | interface |
152
- | `Artifact` | type |
153
- | `Snapshot` | type |
154
- | `Plan` | interface |
155
- | `Finding` | interface |
156
- | `Audit` | interface |
157
- | `Question` | interface |
158
- | `Validation` | interface |
159
- | `GuideSync` | interface |
160
- | `VersionSync` | interface |
161
- | `SyncReport` | interface |
162
- | `PlanSummary` | interface |
163
- | `CompileRecord` | interface |
164
- | `CompileFailure` | interface |
165
- | `Scaffolding` | interface |
166
- | `PlanRecord` | interface |
167
- | `CompilerEventMap` | type |
168
- | `CompilerOptions` | interface |
169
- | `CompilerInterface` | interface |
170
- | `PlanManagerEventMap` | type |
171
- | `PlanManagerOptions` | interface |
172
- | `PlanManagerInterface` | interface |
130
+ | Name | Kind |
131
+ | ------------------------- | --------- |
132
+ | `Environment` | type |
133
+ | `BuildFormat` | type |
134
+ | `SrcDefinition` | interface |
135
+ | `AppDefinition` | interface |
136
+ | `ViteMachinery` | interface |
137
+ | `ViteProjectRegistration` | interface |
138
+ | `Origin` | type |
139
+ | `Group` | type |
140
+ | `Category` | type |
141
+ | `CatalogEntry` | interface |
142
+ | `Drift` | type |
143
+ | `Freshness` | type |
144
+ | `CompileStage` | type |
145
+ | `ScaffoldErrorCode` | type |
146
+ | `Dependency` | interface |
147
+ | `Override` | interface |
148
+ | `Blueprint` | interface |
149
+ | `Member` | interface |
150
+ | `ArtifactBase` | interface |
151
+ | `HostArtifact` | interface |
152
+ | `ContentArtifact` | interface |
153
+ | `Artifact` | type |
154
+ | `Snapshot` | type |
155
+ | `Plan` | interface |
156
+ | `Finding` | interface |
157
+ | `Audit` | interface |
158
+ | `Question` | interface |
159
+ | `Validation` | interface |
160
+ | `GuideSync` | interface |
161
+ | `VersionSync` | interface |
162
+ | `SyncReport` | interface |
163
+ | `PlanSummary` | interface |
164
+ | `CompileRecord` | interface |
165
+ | `CompileFailure` | interface |
166
+ | `Scaffolding` | interface |
167
+ | `PlanRecord` | interface |
168
+ | `CompilerEventMap` | type |
169
+ | `CompilerOptions` | interface |
170
+ | `CompilerInterface` | interface |
171
+ | `PlanManagerEventMap` | type |
172
+ | `PlanManagerOptions` | interface |
173
+ | `PlanManagerInterface` | interface |
173
174
 
174
175
  The closed vocabularies are small and total. `Environment` is `'core' | 'browser' | 'server'`.
175
176
  `BuildFormat` is `'es' | 'cjs'`. `Origin` is `'host' | 'template' | 'computed'`. `Group` is
@@ -190,6 +191,10 @@ single-file-component, HTML, and development-server machinery an application bro
190
191
  needs, and `output` for build-output containment. It never selects a boundary guarantee — those ship
191
192
  in every shape, as the compilers section sets out.
192
193
 
194
+ `ViteProjectRegistration` carries one generated project factory identifier and its optional browser
195
+ label. Root configuration renderers preserve that browser ownership as data through registration
196
+ instead of inferring it from a project identifier.
197
+
193
198
  `Blueprint` is the closed input spec:
194
199
 
195
200
  ```ts
@@ -969,6 +974,7 @@ From [`compilers.ts`](../../src/core/compilers.ts).
969
974
  | `packageManifest` | function |
970
975
  | `rootTsconfig` | function |
971
976
  | `viteMachinery` | function |
977
+ | `renderViteTest` | function |
972
978
  | `viteHeader` | function |
973
979
  | `policyViteProject` | function |
974
980
  | `singleSrcViteConfig` | function |
@@ -1027,7 +1033,8 @@ emits `environmentBoundary`, its `resolveId` / `load` / `buildEnd` walks, the mo
1027
1033
  plus its `environmentPathError` / `environmentSourceError` clauses). Those enforce owner-independent
1028
1034
  laws: core stays host-independent whatever else the workspace declares, a server module never
1029
1035
  imports a stylesheet, and a `@vite-ignore` dynamic import — which `resolveId` never sees and the
1030
- module graph never records — has no other enforcement point. Only host-specific pipelines vary,
1036
+ module graph never records — has no other enforcement point in workspace-owned source. Dependency
1037
+ and toolchain modules are outside that ownership boundary. Only host-specific pipelines vary,
1031
1038
  along the three `ViteMachinery` axes:
1032
1039
 
1033
1040
  | Machinery | Emitted when |
@@ -1040,6 +1047,10 @@ along the three `ViteMachinery` axes:
1040
1047
  An application of `app/core` alone is the sole shape that builds nothing, so it is the sole shape
1041
1048
  without output containment — and it still carries every boundary guarantee above.
1042
1049
 
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
+
1043
1054
  `coreViteConfig`, `srcViteConfig`, and `appViteConfig` emit the thin per-target wrappers;
1044
1055
  `rootViteConfig`, `singleSrcViteConfig`, and `applicationViteConfig` emit the root configuration for
1045
1056
  a library-only, single non-core `src` environment, and application-bearing workspace respectively;
@@ -1396,7 +1407,7 @@ a fixed, interleaved order so aggregates sit immediately before their per-enviro
1396
1407
  Vue typechecker, every other scope uses plain `tsc`
1397
1408
  - `test`, then `test:src` and its per-environment scopes, `test:app` and its per-environment scopes,
1398
1409
  `test:policy`, and `test:guides`; an engine also receives the deliberately non-default
1399
- `test:integration` live installed-consumer gate
1410
+ `test:integration` live installed-consumer gate and `test:equivalence` driver-reference proof
1400
1411
  - `build`, then `build:src` and its per-environment targets, `build:app` and its runtime targets, and
1401
1412
  `build:host` for an engine workspace
1402
1413
  - `dev` when a browser application is selected; `serve` and `serve:build` when a server application
@@ -1404,6 +1415,10 @@ a fixed, interleaved order so aggregates sit immediately before their per-enviro
1404
1415
  - `prepublishOnly` chaining `format:check → lint:check → check → build → test`, followed by the
1405
1416
  live generated-consumer integration gate for the scaffold engine itself
1406
1417
 
1418
+ Run `npm run test:equivalence` after changing the persistent boundary build driver. It reruns the
1419
+ 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.
1421
+
1407
1422
  **Environment isolation.** Scoped TypeScript projects remove the wrong host's globals from each
1408
1423
  environment: core scopes carry the WHATWG web-interop surface and no host at all — no DOM, no Node,
1409
1424
  no `vite/client`; browser scopes carry DOM and no Node; server scopes carry Node and no DOM. The
@@ -1451,10 +1466,10 @@ application's module graph through `import.meta.env` instead.
1451
1466
  Asset URLs that force `?inline` are rejected before Vite can read them outside that auditable output
1452
1467
  graph. Dynamic imports must use a static quoted string or expression-free template string; even
1453
1468
  `/* @vite-ignore */` static values repeat the same environment and containment checks inside the
1454
- transform boundary, including inline HTML proxy modules and trusted dependency modules. Trusted
1455
- dependency modules also pass through a bounded, no-follow, identity-checked load inspection before
1456
- Vite transforms or tree-shakes their raw source, so dependency-side asset references cannot escape
1457
- the physical package root by disappearing from the later graph.
1469
+ transform boundary, including inline HTML proxy modules. The transform, load, resolution, emitted
1470
+ asset, and finished-module-graph passes apply that law only to workspace-owned `src/*` and `app/*`
1471
+ modules. Resolved ids under any `node_modules` segment, Vite/Vitest virtual ids, and tooling client
1472
+ injections remain owned by their toolchain and are exempt.
1458
1473
 
1459
1474
  Browser application scripts are modules. Vite's parsed HTML asset callback rejects a classic
1460
1475
  external `<script src>` before resolution and directs the author to `type="module"`. A module
@@ -1469,9 +1484,9 @@ path remains Vite-owned and passes through the environment resolver, which rejec
1469
1484
  ASCII control range and every non-Node URL scheme before loading or output. No second HTML parser or global
1470
1485
  reference rewrite is involved, so comments, text, non-script attributes, and entity-spelled asset
1471
1486
  filenames retain Vite's native parsing and resolution behavior.
1472
- The resolver leaves NUL-prefixed Rolldown/Vite virtual module IDs to the tool that owns that
1473
- namespace; author module and asset URLs are extracted and validated before they reach that resolver
1474
- exception.
1487
+ The resolver leaves NUL-prefixed and `virtual:` Rolldown/Vite module IDs, tooling client injections,
1488
+ and every resolved `node_modules` module to the tool that owns that namespace; author module and
1489
+ asset URLs are extracted and validated before they reach those resolver exceptions.
1475
1490
  SVG script `href` and `xlink:href` attributes are parsed too and rejected as classic script loads.
1476
1491
  Inline module scripts enter Vite's HTML proxy graph and receive the same Oxc boundary analysis as
1477
1492
  module files. Classic inline scripts cannot enter that graph, so the required security prologue places
@@ -1511,11 +1526,7 @@ What it rejects is equally deliberate:
1511
1526
  browser or server package subpath;
1512
1527
  - a browser module reaching a Node builtin or a server subpath;
1513
1528
  - a server module reaching a stylesheet, Vue, or a browser subpath;
1514
- - a workspace-relative import that resolves outside the workspace, or a dependency import that
1515
- escapes the exact physical package root established by the nearest bounded, unlinked
1516
- `package.json` whose own `name` exactly matches the resolved dependency;
1517
- - a package `#imports` mapping that resolves outside both the declaring package and another exact
1518
- physical package root;
1529
+ - a workspace-relative import that resolves outside the workspace;
1519
1530
  - an HTML reference carrying `vite-ignore` that violates the same environment or containment law
1520
1531
  as an ordinary reference, a Vite `%ENV%` HTML substitution, a classic external script, or a
1521
1532
  computed dynamic import in the module graph that would bypass graph resolution;
@@ -1549,11 +1560,14 @@ host-origin file and run it as a dedicated Node-only `policy` test project over
1549
1560
  **Real browser capability.** Browser test projects are gated on the real executable: the generated
1550
1561
  configuration and the generated policy test both probe `existsSync(chromium.executablePath())`. A
1551
1562
  browser suite runs when a real Chromium is installed and is skipped honestly when it is not, rather
1552
- than being faked. The gate is applied at registration, not only inside the project: without a
1553
- Chromium the browser project is left out of the emitted `projects` list entirely, so the runner
1554
- never has to reconcile a registered project whose include set resolves to nothing, and one printed
1555
- warning names every omitted project label. A machine with a browser runs the browser suite; a
1556
- machine without one runs the remaining projects and says so.
1563
+ than being faked. The gate is applied at registration, not inside the real browser project: without
1564
+ Chromium, each browser factory is replaced by a same-label Node/no-test placeholder, so generated
1565
+ `--project <label>` and `--project=<label>` filters still resolve while no browser code runs. The
1566
+ root permits an empty run only when every recognized exact project filter names one of those gated
1567
+ placeholders; an unreadable or mixed filter keeps the ordinary no-test failure semantics for its
1568
+ Node projects. One printed warning names every gated project label. A machine with a browser
1569
+ registers and runs the real browser suites unchanged; a machine without one runs the remaining
1570
+ projects and says so.
1557
1571
 
1558
1572
  **Continuous integration.** The generated workflow runs on push and pull request, on
1559
1573
  `ubuntu-latest`, with read-only contents permission, a 60-minute timeout, and a matrix that **tests
@@ -2009,6 +2023,7 @@ import {
2009
2023
  coreTsconfig,
2010
2024
  coreViteConfig,
2011
2025
  policyViteProject,
2026
+ renderViteTest,
2012
2027
  rootTsconfig,
2013
2028
  rootViteConfig,
2014
2029
  singleSrcViteConfig,
@@ -2025,6 +2040,7 @@ appTsconfig('browser', true)
2025
2040
 
2026
2041
  viteMachinery(['core']) // { browser: false, vue: false, output: true }
2027
2042
  viteMachinery([], ['core', 'browser']) // { browser: true, vue: true, output: true }
2043
+ renderViteTest([{ project: 'srcCore' }], false).includes('projects: [srcCore]') // true
2028
2044
  viteHeader(viteMachinery([], ['core', 'browser'])) // the shared header, with browser and Vue support
2029
2045
  coreViteConfig()
2030
2046
  srcViteConfig('browser')
@@ -51,6 +51,7 @@ export const DATA_SOURCE_FILES: readonly string[] = Object.freeze([
51
51
  'contracts.ts',
52
52
  'relations.ts',
53
53
  'schemas.ts',
54
+ 'shapers.ts',
54
55
  'templates.ts',
55
56
  'validators.ts',
56
57
  ])