@orkestrel/scaffold 0.0.54 → 0.0.56
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.
- package/README.md +21 -6
- package/dist/bin/main.js +2 -2
- package/dist/bin/main.js.map +1 -1
- package/dist/host/AGENTS.md +1 -0
- package/dist/host/agents/orchestration.md +6 -3
- package/dist/host/agents/skills/orkestrel-publish/references/wave.md +28 -2
- package/dist/host/claude/agents/orkestrel.md +12 -8
- package/dist/host/claude/rules/architecture.md +11 -0
- package/dist/host/claude/rules/portability.md +98 -0
- package/dist/host/claude/rules/quality.md +1 -0
- package/dist/host/guides/scaffold.md +187 -68
- package/dist/host/manifest.json +16 -10
- package/dist/host/scripts/codex.sh +0 -0
- package/dist/host/scripts/cursor.sh +0 -0
- package/dist/host/scripts/deps.sh +0 -0
- package/dist/host/scripts/ollama.sh +0 -0
- package/dist/host/tests/policy.test.ts +154 -3
- package/dist/host/tests/setupPolicy.ts +540 -4
- package/dist/src/core/index.cjs +199 -43
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +113 -12
- package/dist/src/core/index.d.ts +113 -12
- package/dist/src/core/index.js +198 -44
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +140 -12
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +108 -9
- package/dist/src/server/index.d.ts +108 -9
- package/dist/src/server/index.js +141 -15
- package/dist/src/server/index.js.map +1 -1
- package/package.json +4 -4
package/dist/host/AGENTS.md
CHANGED
|
@@ -128,6 +128,7 @@ Every file in the following table is a normative extension of this root. Read ev
|
|
|
128
128
|
| `.claude/rules/application.md` | App composition, entries, manifest safety, lifecycle, integration |
|
|
129
129
|
| `.claude/rules/browser.md` | Vue/browser architecture and platform usage |
|
|
130
130
|
| `.claude/rules/styles.md` | SCSS/CSS centralization, tokens, mixins, layers, naming |
|
|
131
|
+
| `.claude/rules/portability.md` | Host branching, paths, line endings, processes, terminals, OS claims |
|
|
131
132
|
| `.claude/rules/documentation.md` | Guides, parity, roadmap, showcase, examples |
|
|
132
133
|
| `.claude/rules/writing.md` | Developer prose: reports, replies, vocabulary, claims, structure |
|
|
133
134
|
| `.claude/rules/quality.md` | Research, dependency reuse, hardening, completion, package inspection |
|
|
@@ -161,9 +161,12 @@ when the role file already pins it.
|
|
|
161
161
|
- `implementer` names the harness's native implementation lane, so the token means Opus in Claude
|
|
162
162
|
Code and Sol in Codex. An engine-named bridge — `sol`, `opus` — names the other engine. Read a
|
|
163
163
|
role name against the harness you are running in, and state the engine anyway.
|
|
164
|
-
- Give every role a file
|
|
165
|
-
|
|
166
|
-
|
|
164
|
+
- Give every role a file in the scaffold checkout, under `.claude/agents/` and under
|
|
165
|
+
`.codex/agents/`. The role file is where engine, effort, tools, permissions, and charter are
|
|
166
|
+
pinned, and the tool allowlist is what makes the read-only floor real. A role with no file has
|
|
167
|
+
nowhere to pin either. The requirement is the canon repository's alone: a fleet target holds the
|
|
168
|
+
catalog agent and no other role, and a session that dispatches roles starts on scaffold and
|
|
169
|
+
attaches the target.
|
|
167
170
|
- Reach every role by its own name. Do not rely on a remembered route.
|
|
168
171
|
- `researcher`, `scout`, and `checker` are native lanes for jobs that belong to Grok first.
|
|
169
172
|
Dispatch `grok` with their brief before using them, and use the native role only once the ladder
|
|
@@ -12,7 +12,24 @@ step that writes it.
|
|
|
12
12
|
|
|
13
13
|
1. Re-pin the target's `@orkestrel/scaffold` devDependency and install, so the overwrite runs the
|
|
14
14
|
current vendored host.
|
|
15
|
-
2. Run `scaffold overwrite`.
|
|
15
|
+
2. Run `scaffold overwrite`. One run repairs the `AGENTS.md` and `CLAUDE.md` pointers and deletes
|
|
16
|
+
every tracked copy the target still holds at an instruction-canon path. Prove the sweep with a
|
|
17
|
+
second `scaffold audit` that exits `0`.
|
|
18
|
+
- Where the target's `.claude/agents/orkestrel.md` carries a body outside the marker-bounded
|
|
19
|
+
table that differs from the floor copy the installed scaffold stages, delete the file and
|
|
20
|
+
commit the deletion before the run. `repair` restores the floor body and `catalog` refills the
|
|
21
|
+
table, so one visit leaves the current file and the committed deletion keeps the
|
|
22
|
+
uncommitted-work refusal from firing. Presence ownership never replaces present bytes and the
|
|
23
|
+
table rewrite touches only the marker-bounded region, which is why the deletion is the
|
|
24
|
+
migration.
|
|
25
|
+
- The deletion draws on what git tracks, so an untracked copy survives it, and the verb refuses
|
|
26
|
+
the whole run as uncommitted work while an unignored one stands. Commit that copy or delete it
|
|
27
|
+
by hand before re-running. `--dirty` clears the refusal and leaves the copy standing, and a
|
|
28
|
+
kept `.claude/rules` copy then reddens the target's own policy sweep: the pointer `AGENTS.md`
|
|
29
|
+
carries no rule map, so the copy has no row there and the sweep reports it. Delete the copy
|
|
30
|
+
rather than waiving past it.
|
|
31
|
+
- A copy the target git-ignores stays a `foreign` finding, so that target never reaches exit `0`
|
|
32
|
+
again. Keep a local MCP server registration outside the repository rather than at `.mcp.json`.
|
|
16
33
|
3. Force-verify every `@orkestrel` range against a registry sweep taken after the previous layer
|
|
17
34
|
published.
|
|
18
35
|
4. Run the full install.
|
|
@@ -22,7 +39,16 @@ step that writes it.
|
|
|
22
39
|
|
|
23
40
|
Restore any unpublished tarball the target is holding before the quality gates run, per
|
|
24
41
|
`.agents/orchestration.md` § Fixing a dependency before it publishes. A distribution proof run
|
|
25
|
-
against a local tarball proves the local tarball.
|
|
42
|
+
against a local tarball proves the local tarball. Stage an unpublished tarball with
|
|
43
|
+
`npm install --no-save`, because a `file:` pin refuses the blueprint and the manifest keeps a
|
|
44
|
+
registry range.
|
|
45
|
+
|
|
46
|
+
Where a visit runs before scaffold itself publishes, run `scaffold overwrite --offline` and prove
|
|
47
|
+
the sweep with `scaffold audit --offline`. The online verbs read vendored bytes from the published
|
|
48
|
+
package, so an unpublished scaffold's visit otherwise writes the registry's older floor, and an
|
|
49
|
+
online audit reports the floor-restored files as stale until the release. The `--offline` overwrite
|
|
50
|
+
skips the catalog step and exits `1` with a note naming that refusal, so run the full
|
|
51
|
+
`scaffold overwrite` after the release.
|
|
26
52
|
|
|
27
53
|
Run visits in parallel slices of disjoint repositories, each slice strictly serial inside itself,
|
|
28
54
|
reporting per target. Refuse a failed target, name it, repair it, and re-run it alone.
|
|
@@ -9,8 +9,12 @@ permissionMode: dontAsk
|
|
|
9
9
|
|
|
10
10
|
You are the read-only Orkestrel ecosystem reconciler. Spawn nothing and edit nothing.
|
|
11
11
|
|
|
12
|
-
Read
|
|
13
|
-
dispatch contract.
|
|
12
|
+
Read the orchestration contract first. It owns the role set, the routing, and the
|
|
13
|
+
dispatch contract. Resolve it against scaffold. In the scaffold checkout it sits at
|
|
14
|
+
`.agents/orchestration.md`. A repository that installs scaffold reads it at
|
|
15
|
+
`node_modules/@orkestrel/scaffold/dist/host/agents/orchestration.md`, or in a scaffold
|
|
16
|
+
checkout beside that repository, as that repository's own `AGENTS.md` pointer names. Then
|
|
17
|
+
read `AGENTS.md` itself, the applicable rules it names, the dispatch-named skill and its
|
|
14
18
|
references, and the governing guides.
|
|
15
19
|
|
|
16
20
|
Your job is reconciliation over supplied evidence, never collection. You have no shell
|
|
@@ -44,9 +48,9 @@ so network-controlled descriptions never enter agent instruction context.
|
|
|
44
48
|
| `@orkestrel/abort` | `0.0.8` | L1 | `@orkestrel/contract` `^0.0.13` |
|
|
45
49
|
| `@orkestrel/agent` | `0.0.18` | L5 | `@orkestrel/abort` `^0.0.7`, `@orkestrel/budget` `^0.0.7`, `@orkestrel/contract` `^0.0.13`, `@orkestrel/database` `^0.0.11`, `@orkestrel/emitter` `^0.0.7`, `@orkestrel/queue` `^0.0.10`, `@orkestrel/timeout` `^0.0.7`, `@orkestrel/tool` `^0.0.11`, `@orkestrel/workflow` `^0.0.14`, `@orkestrel/workspace` `^0.0.5` |
|
|
46
50
|
| `@orkestrel/brief` | `0.0.6` | L4 | `@orkestrel/contract` `^0.0.13`, `@orkestrel/emitter` `^0.0.8`, `@orkestrel/interpret` `^0.0.11`, `@orkestrel/reason` `^0.0.8` |
|
|
47
|
-
| `@orkestrel/browser` | `0.0.
|
|
51
|
+
| `@orkestrel/browser` | `0.0.14` | L3 | `@orkestrel/contract` `^0.0.13`, `@orkestrel/emitter` `^0.0.8`, `@orkestrel/html` `^0.0.7`, `@orkestrel/websocket` `^0.0.10` |
|
|
48
52
|
| `@orkestrel/budget` | `0.0.8` | L1 | `@orkestrel/contract` `^0.0.13` |
|
|
49
|
-
| `@orkestrel/console` | `0.0.
|
|
53
|
+
| `@orkestrel/console` | `0.0.11` | L2 | `@orkestrel/contract` `^0.0.13`, `@orkestrel/emitter` `^0.0.8` |
|
|
50
54
|
| `@orkestrel/contract` | `0.0.13` | L0 | |
|
|
51
55
|
| `@orkestrel/csv` | `0.0.5` | L1 | `@orkestrel/contract` `^0.0.13` |
|
|
52
56
|
| `@orkestrel/database` | `0.0.12` | L2 | `@orkestrel/contract` `^0.0.13`, `@orkestrel/emitter` `^0.0.8`, `@orkestrel/indexeddb` `^0.0.9`, `@orkestrel/sqlite` `^0.0.9` |
|
|
@@ -56,7 +60,7 @@ so network-controlled descriptions never enter agent instruction context.
|
|
|
56
60
|
| `@orkestrel/html` | `0.0.7` | L1 | `@orkestrel/contract` `^0.0.13` |
|
|
57
61
|
| `@orkestrel/indexeddb` | `0.0.9` | L1 | `@orkestrel/contract` `^0.0.13` |
|
|
58
62
|
| `@orkestrel/interpret` | `0.0.11` | L3 | `@orkestrel/reason` `^0.0.8`, `@orkestrel/emitter` `^0.0.8`, `@orkestrel/contract` `^0.0.13`, `@orkestrel/template` `^0.0.5` |
|
|
59
|
-
| `@orkestrel/lsp` | `0.0.
|
|
63
|
+
| `@orkestrel/lsp` | `0.0.3` | L3 | `@orkestrel/contract` `^0.0.13`, `@orkestrel/emitter` `^0.0.8`, `@orkestrel/process` `^0.0.6` |
|
|
60
64
|
| `@orkestrel/markdown` | `0.0.12` | L2 | `@orkestrel/contract` `^0.0.13`, `@orkestrel/html` `^0.0.7` |
|
|
61
65
|
| `@orkestrel/mcp` | `0.0.25` | L3 | `@orkestrel/contract` `^0.0.13`, `@orkestrel/emitter` `^0.0.8`, `@orkestrel/process` `^0.0.6`, `@orkestrel/sse` `^0.0.5`, `@orkestrel/tool` `^0.0.12`, `@orkestrel/websocket` `^0.0.10` |
|
|
62
66
|
| `@orkestrel/middleware` | `0.0.17` | L2 | `@orkestrel/abort` `^0.0.7`, `@orkestrel/budget` `^0.0.7`, `@orkestrel/contract` `^0.0.13`, `@orkestrel/timeout` `^0.0.7` |
|
|
@@ -64,7 +68,7 @@ so network-controlled descriptions never enter agent instruction context.
|
|
|
64
68
|
| `@orkestrel/ndjson` | `0.0.8` | L1 | `@orkestrel/contract` `^0.0.13` |
|
|
65
69
|
| `@orkestrel/ollama` | `0.0.12` | L6 | `@orkestrel/agent` `^0.0.18`, `@orkestrel/budget` `^0.0.8`, `@orkestrel/contract` `^0.0.13`, `@orkestrel/ndjson` `^0.0.8`, `@orkestrel/timeout` `^0.0.8`, `@orkestrel/tool` `^0.0.12` |
|
|
66
70
|
| `@orkestrel/pool` | `0.0.8` | L2 | `@orkestrel/emitter` `^0.0.7` |
|
|
67
|
-
| `@orkestrel/probe` | `0.0.
|
|
71
|
+
| `@orkestrel/probe` | `0.0.9` | L4 | `@orkestrel/contract` `^0.0.13`, `@orkestrel/emitter` `^0.0.8`, `@orkestrel/lsp` `^0.0.3`, `@orkestrel/mcp` `^0.0.25`, `@orkestrel/queue` `^0.0.10`, `@orkestrel/timeout` `^0.0.8`, `@orkestrel/tool` `^0.0.12` |
|
|
68
72
|
| `@orkestrel/process` | `0.0.6` | L2 | `@orkestrel/contract` `^0.0.13`, `@orkestrel/emitter` `^0.0.7` |
|
|
69
73
|
| `@orkestrel/program` | `0.0.10` | L4 | `@orkestrel/contract` `^0.0.13`, `@orkestrel/emitter` `^0.0.7`, `@orkestrel/qualifier` `^0.0.11`, `@orkestrel/rater` `^0.0.11`, `@orkestrel/reason` `^0.0.7` |
|
|
70
74
|
| `@orkestrel/qualifier` | `0.0.11` | L3 | `@orkestrel/contract` `^0.0.13`, `@orkestrel/emitter` `^0.0.7`, `@orkestrel/reason` `^0.0.7` |
|
|
@@ -73,7 +77,7 @@ so network-controlled descriptions never enter agent instruction context.
|
|
|
73
77
|
| `@orkestrel/reason` | `0.0.8` | L2 | `@orkestrel/contract` `^0.0.13`, `@orkestrel/emitter` `^0.0.8` |
|
|
74
78
|
| `@orkestrel/relation` | `0.0.10` | L3 | `@orkestrel/contract` `^0.0.13`, `@orkestrel/database` `^0.0.12`, `@orkestrel/emitter` `^0.0.8` |
|
|
75
79
|
| `@orkestrel/router` | `0.0.11` | L2 | `@orkestrel/abort` `^0.0.7`, `@orkestrel/contract` `^0.0.13`, `@orkestrel/emitter` `^0.0.7` |
|
|
76
|
-
| `@orkestrel/scaffold` | `0.0.
|
|
80
|
+
| `@orkestrel/scaffold` | `0.0.54` | L3 | `@orkestrel/console` `^0.0.10`, `@orkestrel/contract` `^0.0.13`, `@orkestrel/emitter` `^0.0.8`, `@orkestrel/markdown` `^0.0.12`, `@orkestrel/process` `^0.0.6`, `@orkestrel/template` `^0.0.5` |
|
|
77
81
|
| `@orkestrel/sea` | `0.0.11` | L3 | `@orkestrel/contract` `^0.0.13`, `@orkestrel/emitter` `^0.0.8`, `@orkestrel/process` `^0.0.6` |
|
|
78
82
|
| `@orkestrel/server` | `0.0.15` | L3 | `@orkestrel/abort` `^0.0.8`, `@orkestrel/contract` `^0.0.13`, `@orkestrel/emitter` `^0.0.8`, `@orkestrel/router` `^0.0.11`, `@orkestrel/timeout` `^0.0.8` |
|
|
79
83
|
| `@orkestrel/sqlite` | `0.0.9` | L1 | `@orkestrel/contract` `^0.0.13` |
|
|
@@ -81,7 +85,7 @@ so network-controlled descriptions never enter agent instruction context.
|
|
|
81
85
|
| `@orkestrel/supervisor` | `0.0.1` | L5 | `@orkestrel/contract` `^0.0.11`, `@orkestrel/database` `^0.0.9`, `@orkestrel/emitter` `^0.0.6`, `@orkestrel/workflow` `^0.0.12` |
|
|
82
86
|
| `@orkestrel/table` | `0.0.3` | L2 | `@orkestrel/contract` `^0.0.13`, `@orkestrel/emitter` `^0.0.8` |
|
|
83
87
|
| `@orkestrel/template` | `0.0.5` | L2 | `@orkestrel/contract` `^0.0.13`, `@orkestrel/emitter` `^0.0.8` |
|
|
84
|
-
| `@orkestrel/terminal` | `0.0.
|
|
88
|
+
| `@orkestrel/terminal` | `0.0.13` | L3 | `@orkestrel/console` `^0.0.11`, `@orkestrel/contract` `^0.0.13`, `@orkestrel/database` `^0.0.12`, `@orkestrel/emitter` `^0.0.8`, `@orkestrel/form` `^0.0.3`, `@orkestrel/sse` `^0.0.5` |
|
|
85
89
|
| `@orkestrel/test` | `0.0.11` | L0 | |
|
|
86
90
|
| `@orkestrel/timeout` | `0.0.8` | L1 | `@orkestrel/contract` `^0.0.13` |
|
|
87
91
|
| `@orkestrel/tool` | `0.0.12` | L1 | `@orkestrel/contract` `^0.0.13` |
|
|
@@ -106,6 +106,17 @@ kind. It reads declaration syntax and file name, never meaning.
|
|
|
106
106
|
no bare collection literal.
|
|
107
107
|
- It proves that no source, test, config, or script file carries an `eslint-disable` or
|
|
108
108
|
`oxlint-disable` directive.
|
|
109
|
+
- It proves that every `.claude/rules/*.md` file has a rule-map row in `AGENTS.md` and that every
|
|
110
|
+
row resolves to a file.
|
|
111
|
+
- It proves the host portability rules that are path- or text-shaped over the populations
|
|
112
|
+
`POLICY_PORTABILITY_GLOB` and `POLICY_PORTABILITY_SOURCE_GLOB` name: no path segment carries a
|
|
113
|
+
Windows reserved device name, a character Windows refuses, a trailing dot or space, or a sibling
|
|
114
|
+
differing only by case; no `package.json` script names a `.sh` file; and no source in the parsed
|
|
115
|
+
population trims a payload before splitting it on `'\n'`, reads `os.EOL`, or imports `EOL` from
|
|
116
|
+
`node:os`.
|
|
117
|
+
- It cannot write a filename the host refuses. A Windows host rejects `<`, folds a case collision
|
|
118
|
+
into one file, and turns `:` into an alternate data stream, so those boundaries are proven from a
|
|
119
|
+
path population rather than from written files.
|
|
109
120
|
- It does not prove a collection is frozen. It reads the declaration, never the value a call
|
|
110
121
|
returns, so `Object.freeze([…])` and any other call initializer are one syntax to it. The freeze
|
|
111
122
|
obligation in the earlier kind-purity rules binds regardless; only the bare literal is mechanical.
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- 'src/**/*'
|
|
4
|
+
- 'app/**/*'
|
|
5
|
+
- 'configs/**/*'
|
|
6
|
+
- 'tests/**/*'
|
|
7
|
+
- 'scripts/**/*'
|
|
8
|
+
- 'guides/**/*'
|
|
9
|
+
- 'package.json'
|
|
10
|
+
- '.gitattributes'
|
|
11
|
+
- '.github/workflows/*'
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Host portability rules
|
|
15
|
+
|
|
16
|
+
Published source runs on Windows and Linux. Write one implementation that is correct on each host,
|
|
17
|
+
or gate the host-specific branch on the host that needs it.
|
|
18
|
+
|
|
19
|
+
Take the test half from `.claude/rules/tests.md`: it governs a host-varying property inside a test
|
|
20
|
+
and the form of a conditional skip.
|
|
21
|
+
|
|
22
|
+
## Host branching
|
|
23
|
+
|
|
24
|
+
- Branch on a capability a runtime probe answers — a returned value, a thrown code, a present
|
|
25
|
+
member — wherever the difference is detectable.
|
|
26
|
+
- Branch on `process.platform` only where the behavior is platform-defined, and name that fact in
|
|
27
|
+
the symbol's `@remarks`.
|
|
28
|
+
- Put a platform-literal table — install root, executable suffix, toolchain name — inside a
|
|
29
|
+
`process.platform` branch, and read it on that platform alone.
|
|
30
|
+
- Never flatten a correctly-gated host branch into a single path, and never relax a fail-closed
|
|
31
|
+
check to make one host pass.
|
|
32
|
+
|
|
33
|
+
## Line endings
|
|
34
|
+
|
|
35
|
+
- Split arrived text on `/\r\n|\n/`. Never split on `\n` alone, and never split on a bare `\r`.
|
|
36
|
+
- Split first, then trim each line; trimming the whole payload leaves a `\r` on every line but the
|
|
37
|
+
last.
|
|
38
|
+
- Frame a named protocol — HTTP, LSP, RFC 6455, NDJSON — with the terminator that protocol fixes,
|
|
39
|
+
and leave that terminator alone.
|
|
40
|
+
- Emit `\n` from code this package owns. Never emit `os.EOL`.
|
|
41
|
+
|
|
42
|
+
## Paths
|
|
43
|
+
|
|
44
|
+
- Normalize each operand of a path comparison with the same normalizer before comparing.
|
|
45
|
+
- Never case-fold a containment check. Fold a lookup key only by the file-name case sensitivity the
|
|
46
|
+
consumer declares, and fold the whole key when you fold at all.
|
|
47
|
+
- Compose, split, and relativize a host path with `node:path`. Never concatenate a separator
|
|
48
|
+
literal.
|
|
49
|
+
- Keep a storage key, an archive key, and a URI path slash-separated, and refuse `\` and a drive
|
|
50
|
+
prefix inside one.
|
|
51
|
+
- Refuse the Windows reserved device names and the filename characters Windows rejects, on every
|
|
52
|
+
host.
|
|
53
|
+
- Read the temporary directory from `os.tmpdir()`. Never write a `/tmp` literal in source.
|
|
54
|
+
- Build a `file:` URI with `pathToFileURL`. Never format one from a path string.
|
|
55
|
+
|
|
56
|
+
## Processes and executables
|
|
57
|
+
|
|
58
|
+
- Resolve, spawn, and terminate a child through `@orkestrel/process` where the package declares it.
|
|
59
|
+
- Where it is not declared, spawn `process.execPath` with a JavaScript entry. Never spawn a `.bin`
|
|
60
|
+
shim, and never add `shell: true` to reach one.
|
|
61
|
+
- Take a resolver's first match only after splitting its output into lines and trimming each one.
|
|
62
|
+
`where` prints a match per line and can name a file that is not an executable.
|
|
63
|
+
- Treat `fs.constants.X_OK` as an existence check on Windows, where `accessSync` passes on a plain
|
|
64
|
+
file. Confirm an executable by its name and its file type instead.
|
|
65
|
+
- Read an `fs.constants` member before putting it in a flag word. Windows leaves `O_NOFOLLOW`
|
|
66
|
+
undefined, so `O_WRONLY | O_NOFOLLOW` refuses nothing there. Never polyfill the missing member:
|
|
67
|
+
compensate with a check the host supports, or record the limit.
|
|
68
|
+
- Read `PROGRAMFILES`, `LOCALAPPDATA`, and `APPDATA` inside the win32 branch and `HOME` inside the
|
|
69
|
+
POSIX branch. Never read one host's root on the other.
|
|
70
|
+
- Terminate a Windows child by its process tree. A `SIGTERM` handler never runs there, so gate every
|
|
71
|
+
cooperative-shutdown path on POSIX.
|
|
72
|
+
- Treat a permission bit as advisory on Windows: a written mode does not round-trip
|
|
73
|
+
(`chmodSync(dir, 0o500)` reads back `0444` there), so assert modes only where a probe reports they
|
|
74
|
+
round-trip.
|
|
75
|
+
- Retry an `EBUSY`, `ENOTEMPTY`, or `EPERM` removal inside a bounded budget, and report the failure
|
|
76
|
+
when the budget ends.
|
|
77
|
+
|
|
78
|
+
## Terminals
|
|
79
|
+
|
|
80
|
+
- Gate styling and interactivity on `isTTY`, `NO_COLOR`, and `FORCE_COLOR`, never on the platform.
|
|
81
|
+
- Decode `\r`, `\n`, and `\r\n` from a key stream as the same key.
|
|
82
|
+
- Never call a Windows console-mode API. Node exposes none, so record the unreached behavior as a
|
|
83
|
+
limit.
|
|
84
|
+
|
|
85
|
+
## Scripts and packaging
|
|
86
|
+
|
|
87
|
+
- Write every `package.json` script as a portable command: a Node invocation or an installed binary.
|
|
88
|
+
Never name a `.sh` file there.
|
|
89
|
+
- Keep `#!/usr/bin/env node` on an npm bin. npm writes the Windows shim from it.
|
|
90
|
+
- Keep an agent hook under `scripts/` in bash, and keep `.gitattributes` `eol=lf`.
|
|
91
|
+
|
|
92
|
+
## Claims
|
|
93
|
+
|
|
94
|
+
- Never describe the suite, the host, or CI as POSIX. Name the host and the date behind a reading.
|
|
95
|
+
- Run the gate chain on each host a change claims, and record a reading that could not run as a
|
|
96
|
+
limit naming the host it needs.
|
|
97
|
+
- Keep a POSIX-shaped `file:///` literal in a guide only as an opaque fictional identifier. Build
|
|
98
|
+
any example a reader executes with `pathToFileURL`.
|
|
@@ -60,6 +60,7 @@ A review that reads a diff finds what the diff shows. A review that tries to bre
|
|
|
60
60
|
|
|
61
61
|
- An instrument is not evidence until it has failed. Pair every probe, comparison, or matrix with a negative control that must report failure, run under the same conditions. An identity check whose control reports "same" has measured nothing.
|
|
62
62
|
- When a question about a TypeScript edit can supply a workspace project, a case of workspace files with a test, and a negative control naming its files, its test, the stage it must fail at, and why, call the `prove` tool the `probe` MCP server registers before relying on the answer. When the question supplies no project, no case, or no control, follow `.claude/rules/tests.md` § Probes and report the fallback instrument's own control and coverage.
|
|
63
|
+
- When no `probe` server is registered in the session, register one outside the repository, in the harness's own local or user MCP scope — in Claude Code, `claude mcp add` outside project scope — naming the installed `node_modules/@orkestrel/probe/dist/bin/main.js` entry, and start it in the repository whose projects the question names, because the server fixes its workspace from its own working directory. The registration cannot live in the tree: a scaffold target holds no `.mcp.json` file, that path is instruction canon, and a copy at it reports as foreign drift on every `scaffold audit` run. Where the harness registers no server at all, treat the question as supplying no project and take the preceding rule's fallback.
|
|
63
64
|
- Quote the closing line of the `prove` answer verbatim in every report, brief, and audit verdict that rests on the claim: the `receipt probe:<digest>:…` line when the case ran clean and the control broke exactly where the claim declared it would, and the `no receipt` line otherwise. A `no receipt` line leaves the claim unproved — report it with the stage that refused.
|
|
64
65
|
- Read a receipt as evidence about its claim, never as a gate result. The gate chain still runs, and `verifier` still owns its result.
|
|
65
66
|
- Draw the negative control from outside the population the instrument covers. Name the instrument's membership rule first, then pick a control that rule excludes. A control sampled from constructs the instrument already handles proves only that it discriminates among those constructs, and says nothing about the class it silently cannot reach.
|