@orkestrel/scaffold 0.0.19 → 0.0.21

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.
Files changed (31) hide show
  1. package/dist/bin/scaffold.js +15 -9
  2. package/dist/bin/scaffold.js.map +1 -1
  3. package/dist/host/CLAUDE.md +51 -24
  4. package/dist/host/agents/skills/orkestrel-debrief/SKILL.md +69 -59
  5. package/dist/host/agents/skills/orkestrel-debrief/references/field-testing.md +2 -2
  6. package/dist/host/agents/skills/orkestrel-debrief/references/instruction-audit.md +82 -0
  7. package/dist/host/claude/agents/application.md +34 -0
  8. package/dist/host/claude/agents/codex.md +7 -0
  9. package/dist/host/claude/agents/orkestrel.md +3 -3
  10. package/dist/host/claude/agents/researcher.md +31 -0
  11. package/dist/host/claude/agents/reviewer.md +5 -0
  12. package/dist/host/claude/agents/scout.md +25 -0
  13. package/dist/host/claude/rules/quality.md +10 -0
  14. package/dist/host/claude/rules/tests.md +10 -0
  15. package/dist/host/claude/skills/orkestrel-debrief/SKILL.md +1 -1
  16. package/dist/host/codex/agents/analyst.toml +5 -1
  17. package/dist/host/codex/agents/application.toml +23 -0
  18. package/dist/host/codex/agents/researcher.toml +22 -0
  19. package/dist/host/codex/agents/reviewer.toml +3 -1
  20. package/dist/host/codex/agents/scout.toml +18 -0
  21. package/dist/host/codex/config.toml +15 -6
  22. package/dist/host/guides/src/scaffold.md +120 -29
  23. package/dist/host/manifest.json +35 -0
  24. package/dist/host/tests/setupPolicy.ts +49 -11
  25. package/dist/src/core/index.cjs +1661 -856
  26. package/dist/src/core/index.cjs.map +1 -1
  27. package/dist/src/core/index.d.cts +84 -7
  28. package/dist/src/core/index.d.ts +84 -7
  29. package/dist/src/core/index.js +1656 -857
  30. package/dist/src/core/index.js.map +1 -1
  31. package/package.json +4 -2
@@ -0,0 +1,23 @@
1
+ name = "application"
2
+ description = "Terra executor for one fully specified app-layer unit — contracts, isolated config, entries, real host tests, guide parity; stops on any plan deviation."
3
+ model = "gpt-5.6-terra"
4
+ model_reasoning_effort = "low"
5
+ sandbox_mode = "workspace-write"
6
+ developer_instructions = """
7
+ The app-environment counterpart of builder. Accept work only when owned files, the
8
+ transformation, and mechanical acceptance criteria are complete enough that correct
9
+ implementations cannot differ meaningfully; a unit with open contracts, composition, or
10
+ host boundaries belongs to implementer — stop and say so.
11
+
12
+ Read AGENTS.md, .claude/rules/application.md, .claude/rules/workspace.md, every other
13
+ applicable rule, the dispatch-named skill and required references, and the governing
14
+ guide/spec before writing; they bind and are not restated here. Write only dispatch-owned
15
+ files; shared and off-limits files are report-only and return as exact patches. Validate
16
+ read-only and scoped to the owned app environment. Never install, commit, push, publish,
17
+ read credentials, run a destructive command, or run a tree-wide mutating command.
18
+
19
+ On divergence, stop and report expected, found, exact evidence, done/not done, and one
20
+ short hypothesis. Otherwise return changes, actual scoped validation, and exact
21
+ shared-file patches. The result is an untrusted proposal requiring independent checker
22
+ and reviewer passes.
23
+ """
@@ -0,0 +1,22 @@
1
+ name = "researcher"
2
+ description = "Terra read-only primary-source research: external capabilities, upstream comparisons, installed dependency surfaces, capability/defect matrices with citations."
3
+ model = "gpt-5.6-terra"
4
+ model_reasoning_effort = "medium"
5
+ sandbox_mode = "read-only"
6
+ developer_instructions = """
7
+ The native research lane for the quality-rules research job. Gather and distill; never
8
+ design, implement, or decide. Read AGENTS.md and .claude/rules/quality.md first; they
9
+ bind and are not restated here.
10
+
11
+ Use current primary sources for external capabilities and the exact installed
12
+ declarations for dependencies. Separate verified fact from inference on every line; a
13
+ claim without a citation (URL, file:line, or installed declaration) is inference and must
14
+ say so. When the dispatch asks for a decision input, return the capability/defect matrix
15
+ the quality rules require — every row ending in evidence — never a recommendation dressed
16
+ as fact. Return the distillate only: findings with citations, contradictions surfaced,
17
+ gaps named as gaps; no raw dumps, no process diary, nothing applied.
18
+
19
+ Heavy repository-scale absorption belongs to the grok bench when it is live; this role is
20
+ the bounded-question lane and the fallback when that bench is dark. If a dispatch exceeds
21
+ a bounded question, say so instead of absorbing it.
22
+ """
@@ -15,7 +15,9 @@ Verify that the `claude` CLI is available before dispatch. If it is absent or th
15
15
  dispatch fails, return the failure immediately so the Sol main session can run the
16
16
  design-audit pass itself and record that Opus was unavailable for this round.
17
17
  Require PASS/FAIL, design-fit blockers with file:line evidence, nonblocking
18
- advisories, and acceptance-criterion confirmations. For a rendered or externally
18
+ advisories, and acceptance-criterion confirmations. Require each design claim to be
19
+ tested by asking whether the shipped artifact still matches it, and anything not
20
+ settleable on subjective grounds to come back as an Analyst referral. For a rendered or externally
19
21
  driven surface, require capture citations as primary evidence and the verdict shape
20
22
  of the dispatch-named skill. Forbid edits, commands, orchestration, reconciliation,
21
23
  and acceptance. Never invoke Fable, read credentials,
@@ -0,0 +1,18 @@
1
+ name = "scout"
2
+ description = "Terra read-only repository reconnaissance: locate files, symbols, seams, and structures; return file:line pointers and shape summaries, never judgment."
3
+ model = "gpt-5.6-terra"
4
+ model_reasoning_effort = "low"
5
+ sandbox_mode = "read-only"
6
+ developer_instructions = """
7
+ The cheap reconnaissance lane: answer where things live, what shape they are, and what
8
+ touches them so the Orchestrator can write a precise dispatch. Read AGENTS.md first for
9
+ the repository model and rule map; nothing it owns is restated here.
10
+
11
+ Locate, do not absorb: read excerpts sufficient to identify a seam, an owner, or a
12
+ shape — deep reading and synthesis belong to the grok bench, quality judgment to the
13
+ review roles; if the question needs either, say so instead of drifting into it. Return
14
+ pointers, not prose: file:line for every claim, the minimal shape summary the question
15
+ needs, and an explicit list of searched-and-empty places — an absence claim is only as
16
+ good as its named search. Never edit, never run commands, never speculate past the
17
+ evidence.
18
+ """
@@ -32,8 +32,11 @@ objective and realistic analysis, correctness audit, and all nontrivial
32
32
  implementation. Cursor Grok owns research, scouting, context-heavy reading, and
33
33
  distillation, read-only, through the grok bridge. Claude Opus 5 owns subjective and
34
34
  creative design and design-fit review, read-only, through the planner and reviewer
35
- bridges. Terra drives bridges and explicitly mechanical evidence roles only; it is
36
- never the default implementation route.
35
+ bridges. Terra drives bridges, fully specified units (builder, application), and read-only
36
+ evidence roles (checker, verifier, orkestrel, researcher, scout) only; it is
37
+ never the default implementation route. researcher and scout are the native lanes
38
+ for bounded primary-source questions and repository reconnaissance, and the
39
+ fallback when the Grok bench is dark — never repository-scale absorption.
37
40
 
38
41
  Work directly for trivial tasks. For non-trivial work: send the reading to grok; run
39
42
  planner (Opus 5, subjective) and analyst (Sol, objective) on the
@@ -50,10 +53,16 @@ concurrently.
50
53
 
51
54
  Every dispatch includes objective, context, AGENTS.md, applicable rules, governing
52
55
  skill name/path and required references (or explicit none), guide/spec, owned and
53
- off-limits files, permissions, exact output, deviation behavior, and independently
54
- checkable acceptance criteria. Writers stop when reality diverges; they do not re-plan
55
- or debug beyond scope. After reconciling findings into briefs, every retained finding
56
- names the brief item that carries it; a finding with no carrier is a dropped finding.
56
+ off-limits files, permissions, exact output, deviation behavior, declared unknowns
57
+ with how the unit reports them, the requirement that the executor spawns nothing,
58
+ and independently checkable acceptance criteria. Every brief is a file under tmp/
59
+ written before its unit launches, with the unit's report captured beside it; a
60
+ re-run amends the brief in a successor file rather than restating it; both are
61
+ swept at campaign acceptance, so anything that must outlive the campaign is
62
+ promoted into a durable artifact first. Writers stop when reality diverges; they do
63
+ not re-plan or debug beyond scope. After reconciling findings into briefs, every
64
+ retained finding names the brief item that carries it; a finding with no carrier is
65
+ a dropped finding.
57
66
 
58
67
  A claim about a rendered or externally driven surface is evidenced by its capture
59
68
  portfolio or a real foreign client driving it, never by source alone; the campaign
@@ -67,11 +67,41 @@ than aspirational:
67
67
  - `app/browser` reaches server behavior only through shared `app/core` contracts and transports,
68
68
  never through a server implementation import.
69
69
 
70
- A generated `app/server` owns strict `APP_HOST`, `APP_PORT`, and `APP_START_TIMEOUT` parsing, a
71
- repeat-safe HTTP lifecycle, bounded connection behavior, and process signal cleanup. Its exported
70
+ A generated `app/server` owns strict grouped `server.host`, `server.port`, and `server.timeout`
71
+ options plus the `APP_HOST`, `APP_PORT`, and `APP_START_TIMEOUT` environment boundaries. It
72
+ composes the installed router, server, and boundary/security/deadline middleware substrates around
73
+ a fresh `GET /health` dispatcher from `createApplicationDispatcher`, supports repeated start/stop
74
+ cycles and terminal destroy of both the server and its owned dispatcher, and writes exactly one
75
+ `[READY] <name> <url>` diagnostic after process-owned readiness. The process runner owns an emitter
76
+ whose `ApplicationServerRunnerEventMap` publishes `ready(url)` and `fail(error)`; initial
77
+ `ApplicationServerRunnerOptions.on` hooks run before the runner's own announcement and reporting
78
+ listeners; a synchronous fail hook sees an otherwise-unset `process.exitCode` as `undefined` before
79
+ the default reporter sets it to `1`. Concurrent stops join one substrate shutdown. In-process tests park on those events,
80
+ while child-process tests still observe the readiness line across the process boundary. Its exported
72
81
  `reportApplicationServerError` handler writes only a stable configuration, lifecycle, or unknown
73
- failure code; process-owned diagnostics never serialize a rejected value, nested cause, stack, or
74
- other error context.
82
+ failure code; process-owned failures never serialize a rejected value, nested cause, stack,
83
+ secret, or other error context. `ApplicationState` extends middleware's `IdentifierState` and adds
84
+ only the connection fact. `ApplicationServer.url` is `undefined` until a real port is bound and
85
+ again after stop or destroy; the redundant `listening` projection is not part of the generated
86
+ interface. The runner narrows the post-start URL before writing `[READY]`, so it never announces a
87
+ stale or unbound address, and it stops the server as part of failing that narrowing rather than
88
+ leaving a bound listener without a shutdown owner. It also serializes every start and stop on one
89
+ lifecycle queue, so a stop waits for the startup it aborted to settle before closing the server,
90
+ and a restart issued during that shutdown is honoured after it rather than lost.
91
+
92
+ The health contract belongs to whichever layer both hosts can reach. While the server alone reads
93
+ it, `ApplicationRecord`, `APP_HEALTH_METHOD`, and `APP_HEALTH_PATH` stay declared in `app/server`.
94
+ The moment a blueprint declares `app/browser` beside `app/server` — a combination that already
95
+ requires `app/core` — those three declarations move to `app/core` and gain `APP_HEALTH_TIMEOUT`,
96
+ the `isApplicationRecord` guard, and `readApplicationHealth`. That one asynchronous read is the
97
+ whole browser/server boundary: it fetches the running server's health route, reads the body as
98
+ `unknown`, narrows it with the shared guard, and returns the shared `Application` identity or
99
+ `undefined` for an unreachable, slow, or off-contract answer. Nothing is duplicated by the move —
100
+ `app/server` imports the relocated contract from `@app/core`, and `app/browser` still never imports
101
+ a server module. The generated browser entry then mounts `mountBrowserApplication`, which performs
102
+ that single read before mounting and falls back to the locally configured identity when the
103
+ boundary yields `undefined`. A rejected mount reports the context-free
104
+ `[ERROR] Browser application failed`, the browser twin of that server-side discipline.
75
105
 
76
106
  Every environment barrel is an export-star barrel: `index.ts` contains only `export * from './x.js'`
77
107
  rows and nothing else. Named, default, namespace, and type-only barrel rows are absent by design,
@@ -416,7 +446,9 @@ From [`constants.ts`](../../src/core/constants.ts).
416
446
  | `SCAFFOLD_RANGE` | const |
417
447
  | `BASE_DEV_DEPENDENCIES` | const |
418
448
  | `SOURCE_BROWSER_DEV_DEPENDENCIES` | const |
449
+ | `APP_DEV_DEPENDENCIES` | const |
419
450
  | `APP_BROWSER_DEV_DEPENDENCIES` | const |
451
+ | `APP_SERVER_DEV_DEPENDENCIES` | const |
420
452
  | `CHECKOUT_ACTION_SHA` | const |
421
453
  | `SETUP_NODE_ACTION_SHA` | const |
422
454
  | `COMPILER_ID` | const |
@@ -464,8 +496,11 @@ form. `HEX_PATTERN` requires whole lowercase byte pairs, and `SYNC_BASELINE_PATT
464
496
  `MINIMUM_NODE_VERSION` is `22.12.0`, `DEFAULT_ENGINES` derives from it, and `DEFAULT_VERSION` is
465
497
  `0.0.1`. `BASE_DEV_DEPENDENCIES` is the host-neutral tooling baseline every generated workspace
466
498
  gets; `SOURCE_BROWSER_DEV_DEPENDENCIES` adds the real browser providers a published browser environment
467
- needs, and `APP_BROWSER_DEV_DEPENDENCIES` extends that with the Vue toolchain a private browser
468
- application needs. Vite is minor-pinned at `~8.2.0`: the generated boundary consumes the reviewed
499
+ needs; `APP_DEV_DEPENDENCIES` is the baseline every private application environment gets;
500
+ `APP_BROWSER_DEV_DEPENDENCIES` adds the Vue toolchain and `@orkestrel/html` start-tag parser a
501
+ private browser application needs;
502
+ and `APP_SERVER_DEV_DEPENDENCIES` adds the emitter, middleware, router, and server packages a private
503
+ server application needs. Vite is minor-pinned at `~8.2.0`: the generated boundary consumes the reviewed
469
504
  8.2 `CSSOptions`, `preprocessCSS`, and `isCSSRequest` surface, while the selected
470
505
  `css.transformer` / `lightningcss` path is experimental and must not float into an unreviewed minor.
471
506
  `SCAFFOLD_RANGE` is the range generated workspaces pin this package at.
@@ -788,6 +823,8 @@ From [`helpers.ts`](../../src/core/helpers.ts).
788
823
  | `pascalCase` | function |
789
824
  | `escapeHtmlText` | function |
790
825
  | `serializeTypeScriptString` | function |
826
+ | `hasApplicationBoundary` | function |
827
+ | `hasApplicationShowcase` | function |
791
828
  | `blueprintToMembers` | function |
792
829
  | `catalogNames` | function |
793
830
  | `alignTable` | function |
@@ -824,6 +861,7 @@ From [`helpers.ts`](../../src/core/helpers.ts).
824
861
  | `renderArray` | function |
825
862
  | `renderObject` | function |
826
863
  | `renderValue` | function |
864
+ | `renderStringArray` | function |
827
865
  | `formatJson` | function |
828
866
  | `pinPlan` | function |
829
867
 
@@ -836,7 +874,9 @@ guard. `blueprint` fills the defaults: `version` and `engines` from their consta
836
874
  derives the entity name from a lowercase-hyphen package name, and `blueprintToMembers` derives the
837
875
  declared public `Member[]` — a full entity, options type, interface, and factory per published
838
876
  environment, plus the exact declaration inventory each selected application environment
839
- contributes.
877
+ contributes. `hasApplicationBoundary` recognizes exactly app/core + app/browser + app/server,
878
+ while `hasApplicationShowcase` requires showcase intent beside app/browser; plan assembly, tests,
879
+ guides, and member inventory share those predicates.
840
880
 
841
881
  `escapeHtmlText` and `serializeTypeScriptString` are the two escaping leaves used when a
842
882
  caller-supplied name reaches generated HTML or generated TypeScript source; the latter preserves
@@ -888,7 +928,12 @@ id is already registered: an identical plan is idempotent, while a distinct payl
888
928
  `formatJson` and its leaves — `renderValue`,
889
929
  `renderArray`, `renderObject`, `computeColumnWidth`, and `fitsPrintWidth` — emit JSON that matches the fleet
890
930
  formatter byte for byte, collapsing a short array onto one line and breaking a long one, so
891
- computed configuration JSON is format-stable by construction.
931
+ computed configuration JSON is format-stable by construction. `renderStringArray` applies the same
932
+ inline-or-broken width rule to single-quoted TypeScript string-array literals — with a trailing
933
+ comma on every broken line, matching `oxfmt`'s `trailingComma: "all"` for non-JSON files — so
934
+ generated TypeScript configuration is format-stable too. It serializes every string element through
935
+ `serializeTypeScriptString`, so quotes, backslashes, controls, and line separators remain inert in
936
+ both layouts.
892
937
 
893
938
  ### Helpers — server
894
939
 
@@ -1049,6 +1094,7 @@ From [`compilers.ts`](../../src/core/compilers.ts).
1049
1094
  | `renderViteTest` | function |
1050
1095
  | `viteHeader` | function |
1051
1096
  | `policyViteProject` | function |
1097
+ | `configViteProject` | function |
1052
1098
  | `guidesViteProject` | function |
1053
1099
  | `binViteProject` | function |
1054
1100
  | `integrationViteProject` | function |
@@ -1136,7 +1182,7 @@ formatter's 100-column fixed point: a complete registration-array line, includin
1136
1182
  its trailing comma, stays collapsed when it fits and expands one entry per line otherwise.
1137
1183
  `viteProjectRegistrations` is the one registration derivation every root shape consumes: it derives
1138
1184
  the selected source and application projects from the canonical environment order, then appends
1139
- `policy`, `guides`, and the optional `srcBin`, `integration`, and `service` projects.
1185
+ `policy`, `config`, `guides`, and the optional `srcBin`, `integration`, and `service` projects.
1140
1186
  `viteProjectDefinitions` renders the standalone proof and structural-fact definitions in that same
1141
1187
  order with one blank line between declarations. Both consume `ViteFacts`, so each optional project
1142
1188
  is controlled only by its matching `bin`, `integration`, or `service` blueprint fact; the same
@@ -1149,8 +1195,9 @@ the root `srcCore` factory and its wrapper stay host-independent even when the w
1149
1195
  browser target. `binTsconfig` emits the executable declaration scope; `rootViteConfig`,
1150
1196
  `singleSrcViteConfig`, and `applicationViteConfig` emit the root configuration for a library-only,
1151
1197
  single non-core `src` environment, and application-bearing workspace respectively; and
1152
- `policyViteProject`, `guidesViteProject`, `integrationViteProject`, and `serviceViteProject` emit
1153
- the standalone Node proof projects, with `binViteProject` the single executable-project emitter. A
1198
+ `policyViteProject`, `configViteProject`, `guidesViteProject`, `integrationViteProject`, and
1199
+ `serviceViteProject` emit the standalone Node proof projects, with `binViteProject` the single
1200
+ executable-project emitter. A
1154
1201
  proof project is structurally derived from the directory holding its tests and never wraps a source
1155
1202
  or application environment project. The guides project therefore uses only `tests/setup.ts`, never
1156
1203
  `setupServer.ts`, `setupBrowser.ts`, or `setupService.ts`; and its `tests/src/**/*.test.ts` and
@@ -1540,13 +1587,13 @@ a fixed, interleaved order so aggregates sit immediately before their per-enviro
1540
1587
  - `format`, `format:check`, `lint:check`
1541
1588
  - `test`, then `test:src` and its per-environment scopes, the optional `test:integration`,
1542
1589
  `test:equivalence`, and `test:service` proofs, `test:app` and its per-environment scopes, then
1543
- `test:policy` and `test:guides`
1590
+ `test:policy`, `test:config`, and `test:guides`
1544
1591
  - `build`, then `build:src` and its per-environment targets, `build:app` and its runtime targets, and
1545
1592
  `build:host` for a bin workspace
1546
1593
  - `dev` when a browser application is selected; `serve` and `serve:build` when a server application
1547
1594
  is selected
1548
1595
  - `showcase`, `build:showcase`, and `show` only when the physical showcase wrapper is present;
1549
- `show` builds and copies `dist/showcase/index.html` to `demo/showcase.html`
1596
+ `show` formats, then builds, then copies `dist/showcase/index.html` to `demo/showcase.html`
1550
1597
  - `prepublishOnly` chaining `format:check → lint:check → check → build → test`, followed by
1551
1598
  `test:integration` when the integration axis is selected
1552
1599
 
@@ -1560,8 +1607,9 @@ only where `bin` and `integration` are both set:
1560
1607
  | `test:equivalence` | no | no | no |
1561
1608
  | `test:service` | no | never | after `scripts/service.sh` |
1562
1609
 
1563
- No proof joins the default chain: `npm test` runs the source, application, policy, and guide
1564
- projects, and nothing there needs a build artifact or a foreign process. Publication is the one
1610
+ No opt-in proof joins the default chain: `npm test` runs the source, application, policy,
1611
+ configuration, and guide projects, and nothing there needs a build artifact or a foreign process.
1612
+ Publication is the one
1565
1613
  asymmetry — `prepublishOnly` appends `test:integration`, because a package about to be published
1566
1614
  should prove itself against its own built output, while `test:service` is never in that chain.
1567
1615
  Neither default testing nor publication starts or requires a foreign process.
@@ -1633,10 +1681,16 @@ comments, text, raw blocks, attributes, adjacent tokens, casing, and user-author
1633
1681
  byte-stable. The trusted preparation hook owns the final pre-parse phase; inline proxy code is
1634
1682
  restored before module analysis, and the first normal post-parse hook restores the original HTML
1635
1683
  spelling. The browser entry begins with a generated, byte-stable security prologue: the doctype,
1636
- document and head opening, and a `Content-Security-Policy` meta element are one required prefix.
1637
- Preparation rejects a missing, moved, or changed prologue before Vite parses the document, and the
1638
- final trusted post-hook verifies that Vite retained the policy. CRLF and LF files are both accepted;
1639
- the prologue's markup and ordering are otherwise exact. Vite's `%ENV%` HTML substitution is rejected
1684
+ head opening, and `Content-Security-Policy` meta markup, ordering, and indentation are exact. The
1685
+ opening `html` start tag is parsed by `@orkestrel/html`'s fail-closed `parseStartTag` boundary,
1686
+ so ASCII case and well-formed attributes such as `lang`, `data-bs-theme`, and `data-bs-core`
1687
+ may vary without weakening the position of the following head and policy. A malformed, incomplete,
1688
+ duplicate-attribute, wrong-name, or syntactically slashed root still fails closed. Preparation owns
1689
+ that positional check while the document is still generated bytes; the final trusted post-hook
1690
+ checks only that the exact
1691
+ policy survived because Vite may legitimately inject into the head. CRLF and LF files are both
1692
+ accepted. Vite's
1693
+ `%ENV%` HTML substitution is rejected
1640
1694
  before parsing because Vite performs that expansion after every plugin pre-hook, where it could
1641
1695
  otherwise create a late control attribute. The guard walks the exact left-to-right `%(\S+?)%`
1642
1696
  tokens Vite recognizes instead of performing a substring search, and each preparation plugin owns
@@ -1685,15 +1739,31 @@ still rejects public directories, browser asset inlining, and output path overri
1685
1739
  post-factory composition as defense in depth; that narrow check is not a general extension seam.
1686
1740
 
1687
1741
  When the showcase fact is present, the generated root also exports closed
1688
- `appShowcase(...config: never[])`; both factories reject every argument at runtime and
1689
- share one fixed internal browser configuration. The ordinary factory retains its strict
1742
+ `appShowcase(...config: never[])`; both factories reject every argument at runtime. The
1743
+ ordinary factory retains its strict
1690
1744
  `script-src 'self'` policy, external asset auditing, and `dist/app/browser` output. The showcase
1691
- factory alone writes `dist/showcase`, applies `viteSingleFile` with
1745
+ factory is a standalone configuration with `base: './'`, unlimited asset inlining, and
1746
+ `dist/showcase` output. It applies `viteSingleFile` with
1692
1747
  `removeViteModuleLoader: true` and `useRecommendedBuildConfig: true`, uses Oxc and Lightning CSS
1693
- minification for an `esnext` build without source maps or module preload, and inserts a non-empty ISO
1694
- `build-id` meta. Its generated CSP admits only the inline script and style required by the
1695
- self-contained `file://` artifact while retaining `script-src-attr 'none'`, `object-src 'none'`, and
1696
- `base-uri 'none'`.
1748
+ minification for an `esnext` build without source maps or module preload, and inserts a SHA-256
1749
+ `build-id` derived from the secured, fully inlined document. An unchanged document therefore keeps
1750
+ the same id, while any changed byte changes it. The showcase development CSP keeps scripts
1751
+ same-origin and permits Vue's injected inline styles. Its built CSP swaps that script permission to
1752
+ inline and admits only inline styles plus data images and fonts, while both policies retain
1753
+ `default-src 'none'`, `script-src-attr 'none'`, `object-src 'none'`, and `base-uri 'none'`.
1754
+
1755
+ The showcase fact also emits its own entry pair, `app/browser/showcase.html` and
1756
+ `app/browser/showcase.ts`, beside the application's `index.html` and `main.ts`. Both HTML entries
1757
+ open with a generated security prologue: the application carries the ordinary strict policy and the
1758
+ showcase carries its development policy. The boundary plugins select and validate the matching
1759
+ prologue; the showcase build alone swaps in the self-contained policy before hashing and renames its
1760
+ single HTML output to `index.html`, which is what `show` copies to `demo/showcase.html`. The showcase entry
1761
+ mounts `mountShowcaseApplication`, and `app/browser/seeders.ts` exports exactly one seeder,
1762
+ `seedApplication`, returning a frozen identity of the same shape the shipped root view receives.
1763
+ The two mount factories differ in the seed expression alone. Both explicitly pass
1764
+ `{ name: seed.name }` to the same `createBrowserApplication` root: the showcase seed comes from
1765
+ `seedApplication()`, while the shipped application seed comes from `readApplicationHealth` with
1766
+ the configured identity as its fallback.
1697
1767
 
1698
1768
  The browser development server applies the same trust boundary before Vite's internal middleware.
1699
1769
  Its explicit filesystem allowlist contains only browser/core source roots, browser tests, their
@@ -1756,12 +1826,26 @@ it is not a general-purpose source analyzer. Generated workspaces receive the sa
1756
1826
  module as a host-origin file and run it as a dedicated Node-only `policy` test project over
1757
1827
  `tests/policy.test.ts`.
1758
1828
 
1829
+ **The configuration suite.** Policy reads source, the `config` project exercises the root
1830
+ configuration, and integration builds for real. Every generated workspace therefore receives a
1831
+ universal Node-only
1832
+ `config` project over `tests/config/**/*.test.ts`. Its base cases execute the root module's physical
1833
+ workspace containment and environment-direction helpers; conditional cases exercise output
1834
+ containment when the workspace builds, managed/system browser discovery when a browser environment
1835
+ exists, and the HTML/CSP boundary only for an application browser. Those cases import the generated
1836
+ root `vite.config.ts` itself, so a failure is repaired in the generator rather than patched into a
1837
+ consumer. The generated-consumer integration matrix remains the fidelity boundary for real builds;
1838
+ the configuration suite supplies deterministic edge coverage without duplicating build orchestration.
1839
+ When scaffold changes a generated configuration invariant, an existing consumer's `vite.config.ts`
1840
+ is intentionally reported stale until that consumer accepts the regenerated configuration and its
1841
+ matching config test.
1842
+
1759
1843
  **Real browser capability.** Browser test projects are gated on one centralized discovery chain:
1760
1844
  Playwright's pinned Chromium executable first, then a managed Chromium alias or cached revision,
1761
1845
  then stable system Chrome, then stable system Edge. Managed candidates must be executable regular
1762
1846
  files. System channels are selected only when their executable exists at Playwright's standard
1763
1847
  Linux, macOS, or Windows installation location; custom installations are not guessed. The generated
1764
- policy test consumes the same discovery helpers and accepts either an executable managed path or the
1848
+ configuration test consumes the same discovery helpers and accepts either an executable managed path or the
1765
1849
  stable `chrome` / `msedge` channel, so it does not maintain a second heuristic.
1766
1850
 
1767
1851
  A browser suite runs when any one of those real browser capabilities is available and is skipped
@@ -1900,7 +1984,10 @@ renderer behind the table and blockquote work; the template engine behind every
1900
1984
  artifact; and, consumed only at the executable boundary, the terminal prompt toolkit and the console
1901
1985
  reporter. The core face uses the first four and stays pure; the server face adds only `node:*`
1902
1986
  builtins. Development dependencies are the shared tooling baseline plus the guide-parity toolkit
1903
- that drives [`parity.test.ts`](../../tests/guides/src/parity.test.ts). The engines floor is Node
1987
+ that drives [`parity.test.ts`](../../tests/guides/src/parity.test.ts) and `@orkestrel/html`,
1988
+ which this package's real emitted-configuration tests execute. Generated manifests keep that HTML
1989
+ dependency scoped to `app/browser`; source-only, `app/core`, and `app/server` workspaces do not
1990
+ receive it. The engines floor is Node
1904
1991
  `>=22.12.0`, and the build emits ES and CJS for both library faces plus an ES executable.
1905
1992
 
1906
1993
  ## Patterns
@@ -2245,6 +2332,7 @@ import {
2245
2332
  appViteConfig,
2246
2333
  applicationViteConfig,
2247
2334
  binViteProject,
2335
+ configViteProject,
2248
2336
  coreTsconfig,
2249
2337
  coreViteConfig,
2250
2338
  guidesViteProject,
@@ -2276,13 +2364,14 @@ coreViteConfig()
2276
2364
  srcViteConfig('browser')
2277
2365
  appViteConfig('server')
2278
2366
  policyViteProject()
2367
+ configViteProject()
2279
2368
  guidesViteProject()
2280
2369
  binViteProject()
2281
2370
  integrationViteProject({ bin: true, integration: true, global: true })
2282
2371
  serviceViteProject()
2283
2372
  viteProjectDefinitions({ integration: true }).includes('export const integration =') // true
2284
2373
  viteProjectRegistrations(['core'], [], { integration: true }).map(({ project }) => project)
2285
- // ['srcCore', 'policy', 'guides', 'integration']
2374
+ // ['srcCore', 'policy', 'config', 'guides', 'integration']
2286
2375
 
2287
2376
  rootViteConfig(['core', 'server'], { bin: true })
2288
2377
  singleSrcViteConfig('server').includes('srcServer') // true
@@ -2576,6 +2665,8 @@ isMissingPathError(caught) // true only for an ENOENT error
2576
2665
  ids, the batch-overload semantics, and all-or-nothing list removal.
2577
2666
  - [`tests/src/core/policy.test.ts`](../../tests/src/core/policy.test.ts) — the repository coding-law
2578
2667
  policy module against this workspace and against deliberately hostile fixtures.
2668
+ - [`tests/config/vite.test.ts`](../../tests/config/vite.test.ts) — the executable root Vite
2669
+ invariants for workspace, environment, and output containment.
2579
2670
  - [`tests/src/server/helpers.test.ts`](../../tests/src/server/helpers.test.ts) — containment,
2580
2671
  digests, host staging, hydration, derivation, prune scanning, and the local catalog.
2581
2672
  - [`tests/src/server/validators.test.ts`](../../tests/src/server/validators.test.ts) — the portable
@@ -75,6 +75,11 @@
75
75
  "destination": ".agents/skills/orkestrel-debrief/references/field-testing.md",
76
76
  "executable": false
77
77
  },
78
+ {
79
+ "storage": "agents/skills/orkestrel-debrief/references/instruction-audit.md",
80
+ "destination": ".agents/skills/orkestrel-debrief/references/instruction-audit.md",
81
+ "executable": false
82
+ },
78
83
  {
79
84
  "storage": "agents/skills/orkestrel-harden-package/SKILL.md",
80
85
  "destination": ".agents/skills/orkestrel-harden-package/SKILL.md",
@@ -120,6 +125,11 @@
120
125
  "destination": ".agents/skills/orkestrel-polish-surface/references/capture-harness.md",
121
126
  "executable": false
122
127
  },
128
+ {
129
+ "storage": "claude/agents/application.md",
130
+ "destination": ".claude/agents/application.md",
131
+ "executable": false
132
+ },
123
133
  {
124
134
  "storage": "claude/agents/builder.md",
125
135
  "destination": ".claude/agents/builder.md",
@@ -155,11 +165,21 @@
155
165
  "destination": ".claude/agents/planner.md",
156
166
  "executable": false
157
167
  },
168
+ {
169
+ "storage": "claude/agents/researcher.md",
170
+ "destination": ".claude/agents/researcher.md",
171
+ "executable": false
172
+ },
158
173
  {
159
174
  "storage": "claude/agents/reviewer.md",
160
175
  "destination": ".claude/agents/reviewer.md",
161
176
  "executable": false
162
177
  },
178
+ {
179
+ "storage": "claude/agents/scout.md",
180
+ "destination": ".claude/agents/scout.md",
181
+ "executable": false
182
+ },
163
183
  {
164
184
  "storage": "claude/agents/verifier.md",
165
185
  "destination": ".claude/agents/verifier.md",
@@ -260,6 +280,11 @@
260
280
  "destination": ".codex/agents/analyst.toml",
261
281
  "executable": false
262
282
  },
283
+ {
284
+ "storage": "codex/agents/application.toml",
285
+ "destination": ".codex/agents/application.toml",
286
+ "executable": false
287
+ },
263
288
  {
264
289
  "storage": "codex/agents/builder.toml",
265
290
  "destination": ".codex/agents/builder.toml",
@@ -295,11 +320,21 @@
295
320
  "destination": ".codex/agents/planner.toml",
296
321
  "executable": false
297
322
  },
323
+ {
324
+ "storage": "codex/agents/researcher.toml",
325
+ "destination": ".codex/agents/researcher.toml",
326
+ "executable": false
327
+ },
298
328
  {
299
329
  "storage": "codex/agents/reviewer.toml",
300
330
  "destination": ".codex/agents/reviewer.toml",
301
331
  "executable": false
302
332
  },
333
+ {
334
+ "storage": "codex/agents/scout.toml",
335
+ "destination": ".codex/agents/scout.toml",
336
+ "executable": false
337
+ },
303
338
  {
304
339
  "storage": "codex/agents/verifier.toml",
305
340
  "destination": ".codex/agents/verifier.toml",
@@ -18,6 +18,7 @@ export const CENTRAL_SOURCE_FILES: readonly string[] = Object.freeze([
18
18
  'middlewares.ts',
19
19
  'parsers.ts',
20
20
  'relations.ts',
21
+ 'routes.ts',
21
22
  'schemas.ts',
22
23
  'seeders.ts',
23
24
  'shapers.ts',
@@ -39,6 +40,7 @@ export const FUNCTION_SOURCE_FILES: readonly string[] = Object.freeze([
39
40
  'middlewares.ts',
40
41
  'parsers.ts',
41
42
  'relations.ts',
43
+ 'routes.ts',
42
44
  'schemas.ts',
43
45
  'seeders.ts',
44
46
  'shapers.ts',
@@ -51,6 +53,7 @@ export const DATA_SOURCE_FILES: readonly string[] = Object.freeze([
51
53
  'constants.ts',
52
54
  'contracts.ts',
53
55
  'relations.ts',
56
+ 'routes.ts',
54
57
  'schemas.ts',
55
58
  'shapers.ts',
56
59
  'templates.ts',
@@ -90,6 +93,22 @@ export const WORKER_SCOPE_VALUE_GLOBALS: readonly string[] = Object.freeze([
90
93
  'removeEventListener',
91
94
  ])
92
95
 
96
+ /** Source extensions inspected by the repository coding-law sweep. */
97
+ export const CODING_SOURCE_EXTENSIONS: readonly string[] = Object.freeze([
98
+ 'cjs',
99
+ 'cts',
100
+ 'js',
101
+ 'jsx',
102
+ 'mjs',
103
+ 'mts',
104
+ 'ts',
105
+ 'tsx',
106
+ 'vue',
107
+ ])
108
+
109
+ /** Production-source glob derived from the complete inspected extension vocabulary. */
110
+ export const CODING_SOURCE_GLOB = `{app,src}/**/*.{${CODING_SOURCE_EXTENSIONS.join(',')}}`
111
+
93
112
  /** Virtual source text used while binding one policy-inspected module. */
94
113
  export const POLICY_SOURCE_TEXTS: Map<string, string> = new Map()
95
114
 
@@ -109,6 +128,17 @@ export function normalizePolicyPath(path: string): string {
109
128
  return path.replaceAll('\\', '/').replace(/\/+/gu, '/')
110
129
  }
111
130
 
131
+ /** Whether a path belongs to the production-source coding-law corpus. */
132
+ export function isCodingSourcePath(path: string): boolean {
133
+ const normalized = normalizePolicyPath(path)
134
+ const extension = normalized.split('.').pop()
135
+ return (
136
+ (normalized.startsWith('app/') || normalized.startsWith('src/')) &&
137
+ extension !== undefined &&
138
+ CODING_SOURCE_EXTENSIONS.includes(extension)
139
+ )
140
+ }
141
+
112
142
  /** Whether a declaration carries an explicit export modifier. */
113
143
  export function hasExportModifier(node: ts.Node): boolean {
114
144
  return (
@@ -416,6 +446,22 @@ export function inspectVueCodingLaw(
416
446
  return violations
417
447
  }
418
448
 
449
+ /** Inspect one production source through the shared coding-law route. */
450
+ export function inspectCodingSource(
451
+ path: string,
452
+ content: string,
453
+ vueScripts?: VueScriptExtractorInterface,
454
+ ): readonly string[] {
455
+ const normalizedPath = normalizePolicyPath(path)
456
+ if (!normalizedPath.endsWith('.vue')) return inspectCodingLaw(normalizedPath, content)
457
+ const violations: string[] = []
458
+ if (!normalizedPath.startsWith('app/browser/')) {
459
+ violations.push(`${normalizedPath} Vue components belong in app/browser`)
460
+ }
461
+ violations.push(...inspectVueCodingLaw(normalizedPath, vueScripts?.(normalizedPath, content)))
462
+ return violations
463
+ }
464
+
419
465
  /** Add syntax-wide coding-law violations while traversing one source tree. */
420
466
  export function inspectCodingNode(
421
467
  path: string,
@@ -627,25 +673,17 @@ export function inspectCodingLaw(path: string, content: string): readonly string
627
673
  return violations
628
674
  }
629
675
 
630
- /** Inspect every production TypeScript module under one workspace. */
676
+ /** Inspect every production source under one workspace. */
631
677
  export function inspectCodingWorkspace(
632
678
  root: string,
633
679
  vueScripts?: VueScriptExtractorInterface,
634
680
  ): readonly string[] {
635
681
  const violations: string[] = []
636
- for (const path of globSync('{app,src}/**/*.{cjs,cts,js,jsx,mjs,mts,ts,tsx,vue}', {
682
+ for (const path of globSync(CODING_SOURCE_GLOB, {
637
683
  cwd: root,
638
684
  })) {
639
685
  const content = readFileSync(join(root, path), 'utf8')
640
- const normalizedPath = normalizePolicyPath(path)
641
- if (path.endsWith('.vue') && !normalizedPath.startsWith('app/browser/')) {
642
- violations.push(`${normalizedPath} Vue components belong in app/browser`)
643
- }
644
- violations.push(
645
- ...(path.endsWith('.vue')
646
- ? inspectVueCodingLaw(normalizedPath, vueScripts?.(normalizedPath, content))
647
- : inspectCodingLaw(normalizedPath, content)),
648
- )
686
+ violations.push(...inspectCodingSource(path, content, vueScripts))
649
687
  }
650
688
  return violations
651
689
  }