@orkestrel/scaffold 0.0.39 → 0.0.41

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 (37) hide show
  1. package/dist/bin/main.js +8 -1
  2. package/dist/bin/main.js.map +1 -1
  3. package/dist/host/AGENTS.md +2 -2
  4. package/dist/host/agents/orchestration.md +33 -2
  5. package/dist/host/agents/skills/enterprise-bootstrap/references/bootstrap-reference.md +16 -16
  6. package/dist/host/agents/skills/enterprise-bootstrap/references/components.md +3 -3
  7. package/dist/host/agents/skills/orkestrel-align-packages/references/integration.md +1 -1
  8. package/dist/host/agents/skills/orkestrel-build-application/SKILL.md +7 -2
  9. package/dist/host/claude/agents/builder.md +2 -2
  10. package/dist/host/claude/agents/orkestrel.md +48 -48
  11. package/dist/host/claude/rules/application.md +6 -4
  12. package/dist/host/claude/rules/architecture.md +2 -0
  13. package/dist/host/claude/rules/documentation.md +6 -0
  14. package/dist/host/claude/rules/tests.md +11 -1
  15. package/dist/host/claude/rules/typescript.md +15 -1
  16. package/dist/host/claude/rules/workspace.md +43 -13
  17. package/dist/host/claude/rules/writing.md +125 -0
  18. package/dist/host/claude/skills/enterprise-bootstrap/SKILL.md +10 -1
  19. package/dist/host/claude/skills/orkestrel-align-packages/SKILL.md +1 -1
  20. package/dist/host/claude/skills/orkestrel-build-application/SKILL.md +1 -1
  21. package/dist/host/claude/skills/orkestrel-harden-package/SKILL.md +1 -1
  22. package/dist/host/configs/policy.ts +185 -0
  23. package/dist/host/dotfiles/oxlintrc.json +13 -1
  24. package/dist/host/dotfiles/prettierignore +3 -0
  25. package/dist/host/guides/scaffold.md +13 -7
  26. package/dist/host/manifest.json +11 -7
  27. package/dist/host/tests/config.test.ts +195 -4
  28. package/dist/host/tests/policy.test.ts +82 -0
  29. package/dist/host/tests/setupPolicy.ts +863 -21
  30. package/dist/src/core/index.cjs +68 -6
  31. package/dist/src/core/index.cjs.map +1 -1
  32. package/dist/src/core/index.d.cts +11 -9
  33. package/dist/src/core/index.d.ts +11 -9
  34. package/dist/src/core/index.js +68 -6
  35. package/dist/src/core/index.js.map +1 -1
  36. package/package.json +2 -2
  37. package/dist/host/agents/skills/orkestrel-build-application/references/application.md +0 -129
@@ -0,0 +1,125 @@
1
+ # Developer-facing writing rules
2
+
3
+ These rules govern prose a developer reads, including chat replies, reports, guides, README files,
4
+ and commit messages.
5
+ `AGENTS.md` § Writing governs prose everywhere, and this file does not restate it; this file adds
6
+ only what a developer audience decides. An instruction file follows `AGENTS.md` § Instruction files
7
+ first, and these rules wherever a rule here names no different form for it.
8
+
9
+ ## Voice and actor
10
+
11
+ - Write `must` for a requirement, `can` for an option or an ability, and `might` for a possibility.
12
+ A recommendation takes the imperative, the same form `AGENTS.md` § Writing fixes for instructions.
13
+ Never write `should`, and never soften a recommendation into `We recommend`.
14
+ - Address the developer as `you`. Name the software component that acts, and make it the subject of
15
+ the sentence. Reserve `user` for someone using software the developer builds. Never write `we`,
16
+ `our`, or `let's` about agent work.
17
+ - Give software no human faculties. A component reports, returns, detects, or refuses; it never
18
+ knows, thinks, wants, or sees.
19
+ - Use the passive voice only where naming the actor adds blame and nothing else, such as a defect
20
+ count. Name the actor wherever the reader needs it.
21
+ - Use negative contractions (`don't`, `isn't`, `can't`) in a reply or a guide. Do not use them in an
22
+ instruction file.
23
+
24
+ ## Sentence and paragraph order
25
+
26
+ - Put the condition, the goal, or the location before the instruction, so a reader the instruction
27
+ does not apply to stops at the first clause. Put the result or the reason after it. This governs a
28
+ sentence, not a document: a report still opens with its finding.
29
+ - Put the key point in the first sentence of every paragraph and every list item, not only in the
30
+ opening of the reply or the section.
31
+ - Keep the helper words `that`, `then`, `of`, `a`, and `the`. Do not drop one for brevity.
32
+ - Name the noun after `this`, `these`, or `it` wherever the reader could attach the pronoun to
33
+ another referent.
34
+ - State what the reader can do. Do not write a double negative.
35
+
36
+ ## Claims and time
37
+
38
+ - Claim only what the reader can check. Never write `ensure`, `guarantee`, a superlative, or an
39
+ effort adjective as a claim about behavior, and cite the run behind every number. `ensure`
40
+ addressed to an executor as a directive is outside this ban.
41
+ - Write the present tense for what exists. Do not write `currently`, `now`, `new`, `latest`, or
42
+ `soon`; where time matters, give the version or the date.
43
+ - Recommend one path, the shortest one you proved. Rule on every option you list, and drop an option
44
+ equivalent to the one you recommend.
45
+
46
+ ## Code tokens, references, and links
47
+
48
+ - Put a code token in backticks and follow it with a noun: the `parse` method, the `vite.config.ts`
49
+ file, the `--check` flag. Never inflect, pluralize, or possessivize a code token, and never use one
50
+ as an English verb.
51
+ - Point to other material with `preceding`, `following`, `earlier`, or `later`, never with `above` or
52
+ `below`. Use `earlier` and `later` for a version range too.
53
+ - Write link text as the destination's title or a descriptive phrase, introduced by `see`. Never
54
+ write `here`, `this document`, or a bare URL in prose.
55
+ - Paraphrase third-party content and link its source; never paste it into prose you author. A
56
+ vendored mirror is fetched bytes rather than authored prose, and `.claude/rules/documentation.md`
57
+ governs it.
58
+
59
+ ## Structure
60
+
61
+ - Keep a required fact in the main flow. A note or a notice carries only what the reader can skip,
62
+ never a prerequisite, a step, or a warning the task depends on.
63
+ - In a reply or a guide, introduce every list, table, and code fence with a complete sentence naming
64
+ what follows; a rule file's list sits bare under its heading. Number a list only where order or
65
+ rank matters. Use a table only for rows with comparable fields.
66
+ - Write a heading in sentence case, verb first for a task and a noun phrase for a concept. Identity
67
+ numbering — a claim, an audit verdict, a plan unit — is data rather than a heading style, and
68
+ stays.
69
+
70
+ ## Examples, numbers, and abbreviations
71
+
72
+ - Build an example from fictional data with descriptive names and no personally identifiable
73
+ information. Write a placeholder in `UPPER_SNAKE_CASE` and explain it on first use. Never write
74
+ `foo`, `bar`, or `baz`.
75
+ - Expand an abbreviation the reader may not know on first use, with the short form in parentheses.
76
+ Skip the expansion for one this audience reads daily, such as `API`, `CLI`, `JSON`, `URL`, or a
77
+ file format.
78
+ - Write a numeral for a technical quantity, a version, or a count. Write a date as `YYYY-MM-DD` in
79
+ evidence, commit messages, and reports.
80
+ - Use the serial comma. Mark omitted code with a comment in the sample's language, never with `...`.
81
+
82
+ ## Substitutions
83
+
84
+ Replace each term in this table with its replacement. Quote a literal code identifier as itself; it
85
+ is exempt from every row.
86
+
87
+ | Term | Replacement |
88
+ | ------------------------ | ----------------------------------------- |
89
+ | `should` | `must`, `can`, `might`, or the imperative |
90
+ | `simply`, `easy`, `just` | Delete |
91
+ | `currently`, `now` | Delete, or give the date |
92
+ | `new`, `latest` | Delete, or give the version |
93
+ | `utilize`, `leverage` | `use` |
94
+ | `via` | `through`, `by using` |
95
+ | `in order to` | `to` |
96
+ | `e.g.`, `i.e.` | `for example`, `that is` |
97
+ | `etc.` | Bound the list, or recast the sentence |
98
+ | `performant`, `robust` | The measured property |
99
+ | `allows you to` | `lets you` |
100
+ | `and/or` | `and`, `or`, or `both` |
101
+ | `since` (causal) | `because` |
102
+ | `once` (temporal) | `after` |
103
+ | `please` | Delete |
104
+ | `sanity check` | `quick check` |
105
+ | `dummy` | `placeholder` |
106
+ | `blacklist`, `whitelist` | `denylist`, `allowlist` |
107
+ | `master`, `slave` | `primary`, `replica` |
108
+
109
+ - Write singular `they` for a person of unstated gender.
110
+ - This table carries no row for `execute`, `abort`, `kill`, `terminate`, or `run`:
111
+ `.claude/rules/names.md` § Fixed lifecycle vocabulary owns those words, and no row here overrides
112
+ it.
113
+
114
+ ## Not adopted
115
+
116
+ - Do not add conversational personality, warmth, or memorability to a reply; the prose stays plain.
117
+ - Do not import a license to break these rules where a departure reads better; an exception exists
118
+ only where a rule states it.
119
+ - `We recommend` as a recommendation form — refused in § Voice and actor.
120
+ - Do not apply a source guide's sample indentation or line-length chrome; the repository formatter
121
+ and `.claude/rules/typescript.md` decide code presentation.
122
+ - Do not write an unspaced em dash; this project spaces it.
123
+ - Do not cap a sentence at a word count; `AGENTS.md` § Writing owns sentence length.
124
+ - Do not treat an external word list as vocabulary law; the preceding substitution table is the
125
+ adopted set.
@@ -1,6 +1,15 @@
1
1
  ---
2
2
  name: enterprise-bootstrap
3
- description: Design and build distinctive, production-grade user interfaces with Bootstrap 5.3 and intentional frontend craft. Use for ANY UI work — pages, screens, components, layouts, app shells, dashboards, data tables, filter bars, forms, wizards, navigation, modals, empty/loading/error states, dark mode, marketing surfaces — whenever the task touches HTML/CSS/visual design, mentions Bootstrap or its components, or must look professional and avoid templated defaults.
3
+ description: >-
4
+ Design and build distinctive, production-grade user interfaces with Bootstrap
5
+ 5.3 and intentional frontend craft. Use for ANY UI work — creating, restyling,
6
+ reviewing, or extending pages, screens, components, layouts, app shells,
7
+ dashboards, admin panels, SaaS tools, data tables, filter bars, forms,
8
+ wizards, navigation, modals, empty/loading/error states, dark mode, marketing
9
+ surfaces — whenever the task touches HTML/CSS/visual design, mentions
10
+ Bootstrap or its components, or must look professional and avoid templated
11
+ defaults. Covers aesthetics, typography, color modes, design tokens,
12
+ accessibility (WCAG 2.2 AA), responsive layout, and enterprise app patterns.
4
13
  ---
5
14
 
6
15
  # Load the canonical workflow
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: orkestrel-align-packages
3
- description: Audit and improve how multiple Orkestrel packages or their core, server, browser, and app environments fit together. Use for coordinated extraction/refactoring, developer ergonomics, real round-trip integration, fleet alignment, dependency/guide readiness, and topological package campaigns.
3
+ description: Audit and improve how two or more Orkestrel packages, or their core, server, browser, and app environments, fit together. Use for coordinated package-stack refactors, cross-package extraction, developer-ergonomics reviews, end-to-end or live integration testing, dependency and guide alignment, and fleet/package-manager campaigns. Preserve host-independent core boundaries, update dependents topologically, and use the package-hardening workflow for each implementation unit.
4
4
  ---
5
5
 
6
6
  # Load the canonical workflow
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: orkestrel-build-application
3
- description: Design, scaffold, extend, or harden Orkestrel app environments and their isolation, builds, tests, and guide parity.
3
+ description: Design, scaffold, extend, or harden Orkestrel `app/core`, `app/browser`, and `app/server` environments. Use for app-only or mixed src/app workspaces, app environment isolation, Vue browser entries, Node server entries, app aliases/configs/scripts/tests, cross-environment contracts, and application guide parity.
4
4
  ---
5
5
 
6
6
  # Load the canonical workflow
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: orkestrel-harden-package
3
- description: Research, audit, refactor, implement, centralize, test, document, and locally verify an individual Orkestrel TypeScript package to enterprise-grade production readiness. Use for missing/deferred capabilities, upstream or legacy comparisons, centralization, wrapper cleanup, declared @orkestrel dependency adoption, and rigorous real/live tests.
3
+ description: Research, audit, refactor, implement, centralize, test, document, and locally verify an individual Orkestrel TypeScript package to enterprise-grade production readiness under the repository's current AGENTS.md. Use when asked to fill missing or deferred capabilities, compare upstream or legacy implementations, salvage prior art, centralize source or test declarations, eliminate nested functions or superfluous wrappers, maximize declared @orkestrel dependencies—especially @orkestrel/contract—or add rigorous real-implementation and live-service tests. Select only the phases required by a narrow request; run the full workflow for production readiness or comprehensive hardening.
4
4
  ---
5
5
 
6
6
  # Load the canonical workflow
@@ -0,0 +1,185 @@
1
+ /** The expression fields inspected by the policy rules. */
2
+ export interface PolicyExpression {
3
+ readonly type: string
4
+ readonly range: [number, number]
5
+ readonly name?: unknown
6
+ readonly value?: unknown
7
+ readonly object?: PolicyExpression
8
+ readonly property?: PolicyExpression
9
+ readonly computed?: boolean
10
+ readonly callee?: PolicyExpression
11
+ readonly quasis?: readonly PolicyExpression[]
12
+ readonly expressions?: readonly PolicyExpression[]
13
+ readonly accessibility?: 'private' | 'protected' | 'public' | null
14
+ }
15
+
16
+ /** One diagnostic emitted by a policy rule. */
17
+ export interface PolicyDiagnostic {
18
+ readonly node: PolicyExpression
19
+ readonly messageId: string
20
+ readonly data?: Readonly<Record<string, string>>
21
+ }
22
+
23
+ /** The Oxlint context operations used by the policy rules. */
24
+ export interface PolicyContext {
25
+ report(diagnostic: PolicyDiagnostic): void
26
+ }
27
+
28
+ /** The rule documentation fields supplied to Oxlint. */
29
+ export interface PolicyDocs {
30
+ readonly [key: string]: unknown
31
+ readonly description: string
32
+ }
33
+
34
+ /** The rule metadata fields supplied to Oxlint. */
35
+ export interface PolicyMeta {
36
+ readonly type: 'problem'
37
+ readonly docs: PolicyDocs
38
+ readonly messages: Readonly<Record<string, string>>
39
+ }
40
+
41
+ /** The Oxlint visitor entries used by the policy rules. */
42
+ export interface PolicyVisitor {
43
+ readonly [key: string]: ((node: PolicyExpression) => void) | undefined
44
+ readonly CallExpression?: (node: PolicyExpression) => void
45
+ readonly MethodDefinition?: (node: PolicyExpression) => void
46
+ readonly PropertyDefinition?: (node: PolicyExpression) => void
47
+ readonly AccessorProperty?: (node: PolicyExpression) => void
48
+ readonly TSAbstractMethodDefinition?: (node: PolicyExpression) => void
49
+ readonly TSAbstractPropertyDefinition?: (node: PolicyExpression) => void
50
+ readonly TSAbstractAccessorProperty?: (node: PolicyExpression) => void
51
+ }
52
+
53
+ /** The complete behavior exposed by one policy rule. */
54
+ export interface PolicyRuleInterface {
55
+ readonly meta: PolicyMeta
56
+ create(context: PolicyContext): PolicyVisitor
57
+ }
58
+
59
+ /** Report banned calls on the named Vitest and Jest framework objects. */
60
+ export function reportMocking(context: PolicyContext, node: PolicyExpression): void {
61
+ const callee = node.callee
62
+ if (
63
+ callee === undefined ||
64
+ callee.type !== 'MemberExpression' ||
65
+ callee.object === undefined ||
66
+ callee.property === undefined ||
67
+ callee.computed === undefined
68
+ ) {
69
+ return
70
+ }
71
+
72
+ const object = callee.object
73
+ if (object.type !== 'Identifier' || (object.name !== 'vi' && object.name !== 'jest')) {
74
+ return
75
+ }
76
+
77
+ const property = callee.property
78
+ let member: string | undefined
79
+ if (callee.computed) {
80
+ if (property.type === 'Literal' && typeof property.value === 'string') {
81
+ member = property.value
82
+ } else if (
83
+ property.type === 'TemplateLiteral' &&
84
+ property.quasis?.length === 1 &&
85
+ property.expressions?.length === 0
86
+ ) {
87
+ const quasi = property.quasis[0]
88
+ const value = quasi?.value
89
+ if (typeof value === 'object' && value !== null) {
90
+ const cooked: unknown = Object.getOwnPropertyDescriptor(value, 'cooked')?.value
91
+ const raw: unknown = Object.getOwnPropertyDescriptor(value, 'raw')?.value
92
+ member = typeof cooked === 'string' ? cooked : typeof raw === 'string' ? raw : undefined
93
+ }
94
+ }
95
+ } else if (property.type === 'Identifier' && typeof property.name === 'string') {
96
+ member = property.name
97
+ }
98
+
99
+ switch (member) {
100
+ case 'mock':
101
+ case 'doMock':
102
+ case 'unstable_mockModule':
103
+ context.report({ node, messageId: 'mock' })
104
+ break
105
+ case 'fn':
106
+ case 'spyOn':
107
+ context.report({ node, messageId: 'spy' })
108
+ break
109
+ case 'useFakeTimers':
110
+ case 'setSystemTime':
111
+ context.report({ node, messageId: 'clock' })
112
+ break
113
+ case 'stubGlobal':
114
+ case 'stubEnv':
115
+ context.report({ node, messageId: 'stub' })
116
+ break
117
+ }
118
+ }
119
+
120
+ /** Report TypeScript privacy keywords on class members. */
121
+ export function reportPrivacy(context: PolicyContext, node: PolicyExpression): void {
122
+ if (node.accessibility === 'private' || node.accessibility === 'protected') {
123
+ context.report({
124
+ node,
125
+ messageId: 'keyword',
126
+ data: { keyword: node.accessibility },
127
+ })
128
+ }
129
+ }
130
+
131
+ /** Ban framework mocking, spying, fake clocks, and global or environment stubs. */
132
+ export const MOCKING_RULE: PolicyRuleInterface = {
133
+ meta: {
134
+ type: 'problem',
135
+ docs: {
136
+ description:
137
+ 'Disallow named vi and jest mocking APIs; a renamed import alias escapes this name-based rule.',
138
+ },
139
+ messages: {
140
+ mock: 'Replace module mocking with a real injected collaborator; a missing seam is a missing injection point, not an untestable truth.',
141
+ spy: 'Use createRecorder from @orkestrel/test; framework spies and mock functions are banned.',
142
+ clock:
143
+ 'Use real short timers and waitForDelay from @orkestrel/test; never replace the host clock.',
144
+ stub: 'Drive the real implementation or a protocol-faithful fixture; never stub globals or environment.',
145
+ },
146
+ },
147
+ create(context) {
148
+ return {
149
+ CallExpression: (node) => reportMocking(context, node),
150
+ }
151
+ },
152
+ }
153
+
154
+ /** Ban compile-time-only TypeScript privacy keywords on class members. */
155
+ export const PRIVACY_RULE: PolicyRuleInterface = {
156
+ meta: {
157
+ type: 'problem',
158
+ docs: {
159
+ description:
160
+ 'Disallow private and protected class members in favor of runtime-enforced # privacy.',
161
+ },
162
+ messages: {
163
+ keyword: 'Use runtime-enforced # privacy; TypeScript {{keyword}} is compile-time-only.',
164
+ },
165
+ },
166
+ create(context) {
167
+ return {
168
+ MethodDefinition: (node) => reportPrivacy(context, node),
169
+ PropertyDefinition: (node) => reportPrivacy(context, node),
170
+ AccessorProperty: (node) => reportPrivacy(context, node),
171
+ TSAbstractMethodDefinition: (node) => reportPrivacy(context, node),
172
+ TSAbstractPropertyDefinition: (node) => reportPrivacy(context, node),
173
+ TSAbstractAccessorProperty: (node) => reportPrivacy(context, node),
174
+ }
175
+ },
176
+ }
177
+
178
+ /** The workspace Oxlint plugin. */
179
+ export default {
180
+ meta: { name: 'policy' },
181
+ rules: {
182
+ 'no-mocking': MOCKING_RULE,
183
+ 'no-keyword-privacy': PRIVACY_RULE,
184
+ },
185
+ }
@@ -1,12 +1,15 @@
1
1
  {
2
2
  "$schema": "https://raw.githubusercontent.com/oxc-project/oxc/main/npm/oxlint/configuration_schema.json",
3
3
  "plugins": ["import", "typescript", "vitest"],
4
+ "jsPlugins": [{ "name": "policy", "specifier": "./configs/policy.ts" }],
4
5
  "rules": {
5
6
  "@typescript-eslint/no-explicit-any": "error",
6
7
  "@typescript-eslint/no-non-null-assertion": "error",
7
8
  "typescript/consistent-type-assertions": ["error", { "assertionStyle": "never" }],
8
9
  "typescript/no-require-imports": "error",
9
10
  "typescript/array-type": ["error", { "default": "array-simple" }],
11
+ "typescript/parameter-properties": "error",
12
+ "typescript/explicit-member-accessibility": ["error", { "accessibility": "no-public" }],
10
13
  "typescript/ban-ts-comment": [
11
14
  "error",
12
15
  {
@@ -50,7 +53,10 @@
50
53
  "no-underscore-dangle": "warn",
51
54
 
52
55
  "vitest/no-alias-methods": "error",
53
- "vitest/warn-todo": "off"
56
+ "vitest/warn-todo": "off",
57
+
58
+ "policy/no-mocking": "error",
59
+ "policy/no-keyword-privacy": "error"
54
60
  },
55
61
  "categories": {
56
62
  "correctness": "error",
@@ -67,6 +73,12 @@
67
73
  "import/no-default-export": "off"
68
74
  }
69
75
  },
76
+ {
77
+ "files": ["configs/policy.ts"],
78
+ "rules": {
79
+ "import/no-default-export": "off"
80
+ }
81
+ },
70
82
  {
71
83
  "files": ["*.vue"],
72
84
  "rules": {
@@ -6,3 +6,6 @@ dist/
6
6
 
7
7
  # Generated single-file application showcase.
8
8
  demo/showcase.html
9
+
10
+ # Campaign records under the orchestration folder are verbatim evidence, not formatted source.
11
+ .orkestrel/
@@ -465,7 +465,8 @@ the registry, so `new` fails when the registry names no release for a package it
465
465
  workspace would otherwise declare a dependency that does not resolve.
466
466
 
467
467
  `new --bin` creates the executable entry, its test, and its scoped Vite and TypeScript wrappers. The
468
- other structural facts do not need creation flags. Add `tests/guides.test.ts` for `guides`,
468
+ other structural facts do not need creation flags. Add a root `tests/setup*.test.ts` proof for
469
+ `setup`, `tests/guides.test.ts` for `guides`,
469
470
  `tests/distribution.test.ts` for `distribution`, `tests/integration.test.ts` for `integration`,
470
471
  `tests/conformance.test.ts` for `conformance`, `tests/setupService.ts` for `service`,
471
472
  `tests/setupGlobal.ts` for `global`, and `configs/app/vite.showcase.config.ts` for `showcase`;
@@ -478,8 +479,9 @@ vendor list from edited text.
478
479
  `audit`, `repair`, `catalog`, and `overwrite` derive the blueprint from the target itself. The name
479
480
  and the declared `@orkestrel/*` packages come from `package.json`. The two environment axes come
480
481
  from the directories the target actually ships, because a directory is the fact and a declaration
481
- beside it could disagree. Eight more facts come from exact-case files: `src/bin/main.ts` selects
482
- `bin`, `tests/guides.test.ts` selects `guides`, `tests/distribution.test.ts` selects `distribution`,
482
+ beside it could disagree. Nine more facts come from exact-case files: `src/bin/main.ts` selects
483
+ `bin`, each root `tests/setup*.test.ts` match selects `setup`, `tests/guides.test.ts` selects
484
+ `guides`, `tests/distribution.test.ts` selects `distribution`,
483
485
  `tests/integration.test.ts` selects `integration`, `tests/conformance.test.ts` selects
484
486
  `conformance`, `tests/setupService.ts` selects `service`, `tests/setupGlobal.ts` selects `global`,
485
487
  and `configs/app/vite.showcase.config.ts` selects `showcase`. A containing directory does not select
@@ -596,10 +598,14 @@ because the shape is chosen once and read afterwards: `new` refuses the advisory
596
598
  `repair` need the plan to describe and restore a target that already has that shape. A library
597
599
  caller creating a workspace holds the same refusal, and the Compile section below states it.
598
600
 
599
- `bin`, `guides`, `distribution`, `integration`, `conformance`, `service`, `vendors`, `global`, and
600
- `showcase` are structural facts. Each is set only when the workspace physically ships the directory
601
- or exact-case file that defines it, never because of the workspace's name and never because a
602
- sibling fact is set.
601
+ `bin`, `setup`, `guides`, `distribution`, `integration`, `conformance`, `service`, `vendors`,
602
+ `global`, and `showcase` are structural facts. Each is set only when the workspace physically ships
603
+ the directory or exact-case file that defines it, never because of the workspace's name and never
604
+ because a sibling fact is set.
605
+
606
+ `setup` registers every root `tests/setup*.test.ts` proof in one Node project that loads
607
+ `tests/setup.ts`. A nested or wrong-case match does not set the fact. The generated manifest emits
608
+ `test:setup` and invokes it from `test` only while the fact is set.
603
609
 
604
610
  A structural fact is read when a verb runs, not when the file appears. Writing
605
611
  `tests/integration.test.ts` into a workspace sets the fact, but the root configuration on disk was
@@ -80,11 +80,6 @@
80
80
  "destination": ".agents/skills/orkestrel-build-application/agents/openai.yaml",
81
81
  "executable": false
82
82
  },
83
- {
84
- "storage": "agents/skills/orkestrel-build-application/references/application.md",
85
- "destination": ".agents/skills/orkestrel-build-application/references/application.md",
86
- "executable": false
87
- },
88
83
  {
89
84
  "storage": "agents/skills/orkestrel-debrief/SKILL.md",
90
85
  "destination": ".agents/skills/orkestrel-debrief/SKILL.md",
@@ -315,6 +310,11 @@
315
310
  "destination": ".claude/rules/workspace.md",
316
311
  "executable": false
317
312
  },
313
+ {
314
+ "storage": "claude/rules/writing.md",
315
+ "destination": ".claude/rules/writing.md",
316
+ "executable": false
317
+ },
318
318
  {
319
319
  "storage": "claude/settings.json",
320
320
  "destination": ".claude/settings.json",
@@ -440,6 +440,11 @@
440
440
  "destination": "configs/helpers.ts",
441
441
  "executable": false
442
442
  },
443
+ {
444
+ "storage": "configs/policy.ts",
445
+ "destination": "configs/policy.ts",
446
+ "executable": false
447
+ },
443
448
  {
444
449
  "storage": "cursor/mcp.json",
445
450
  "destination": ".cursor/mcp.json",
@@ -546,7 +551,6 @@
546
551
  ".agents/skills/orkestrel-align-packages/references",
547
552
  ".agents/skills/orkestrel-build-application",
548
553
  ".agents/skills/orkestrel-build-application/agents",
549
- ".agents/skills/orkestrel-build-application/references",
550
554
  ".agents/skills/orkestrel-debrief",
551
555
  ".agents/skills/orkestrel-debrief/agents",
552
556
  ".agents/skills/orkestrel-debrief/references",
@@ -576,5 +580,5 @@
576
580
  ".codex/agents",
577
581
  ".cursor/rules"
578
582
  ],
579
- "digest": "f01b63a454ea972776d7385db831f69dfcc1c888c5df2822870d2fe207c76aac"
583
+ "digest": "cdc9d27a693c15833702e2afe0a7ef1da3f4cdec10dccfb3d5f4a6920d57acd8"
580
584
  }