@orkestrel/scaffold 0.0.103 → 0.0.105

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 (94) hide show
  1. package/dist/agents/skills/orkestrel-dispatch/scripts/helpers.js +84 -1
  2. package/dist/agents/skills/orkestrel-dispatch/scripts/launch.js +21 -6
  3. package/dist/agents/skills/orkestrel-harden/scripts/titles.js +338 -0
  4. package/dist/agents/skills/orkestrel-publish/scripts/swap.js +3 -39
  5. package/dist/agents/skills/orkestrel-publish/scripts/wave.js +433 -47
  6. package/dist/agents/skills/orkestrel-publish/scripts/window.js +2 -1
  7. package/dist/bin/main.js +17 -10
  8. package/dist/bin/main.js.map +1 -1
  9. package/dist/host/agents/orchestration.md +6 -6
  10. package/dist/host/agents/skills/enterprise-bootstrap/references/components.md +2 -2
  11. package/dist/host/agents/skills/enterprise-bootstrap/references/inspection.md +1 -1
  12. package/dist/host/agents/skills/orkestrel-build/SKILL.md +2 -2
  13. package/dist/host/agents/skills/orkestrel-debrief/SKILL.md +2 -2
  14. package/dist/host/agents/skills/orkestrel-debrief/references/field-testing.md +1 -1
  15. package/dist/host/agents/skills/orkestrel-debrief/references/instruction-audit.md +3 -3
  16. package/dist/host/agents/skills/orkestrel-dispatch/SKILL.md +10 -10
  17. package/dist/host/agents/skills/orkestrel-dispatch/references/launch.md +1 -0
  18. package/dist/host/agents/skills/orkestrel-dispatch/scripts/helpers.ts +100 -1
  19. package/dist/host/agents/skills/orkestrel-dispatch/scripts/launch.ts +27 -6
  20. package/dist/host/agents/skills/orkestrel-falsify/SKILL.md +4 -4
  21. package/dist/host/agents/skills/orkestrel-falsify/agents/openai.yaml +1 -1
  22. package/dist/host/agents/skills/orkestrel-falsify/references/brief.md +8 -7
  23. package/dist/host/agents/skills/orkestrel-falsify/references/reconcile.md +6 -6
  24. package/dist/host/agents/skills/orkestrel-harden/SKILL.md +6 -1
  25. package/dist/host/agents/skills/orkestrel-harden/references/bindings.md +1700 -0
  26. package/dist/host/agents/skills/orkestrel-harden/references/contract.md +2 -2
  27. package/dist/host/agents/skills/orkestrel-harden/references/equivalence.md +48 -0
  28. package/dist/host/agents/skills/orkestrel-harden/references/hardening.md +4 -2
  29. package/dist/host/agents/skills/orkestrel-harden/scripts/titles.ts +425 -0
  30. package/dist/host/agents/skills/orkestrel-journey/SKILL.md +2 -2
  31. package/dist/host/agents/skills/orkestrel-journey/references/captures.md +9 -8
  32. package/dist/host/agents/skills/orkestrel-parallel/SKILL.md +72 -0
  33. package/dist/host/agents/skills/orkestrel-parallel/agents/openai.yaml +4 -0
  34. package/dist/host/agents/skills/orkestrel-parallel/references/harnesses.md +12 -0
  35. package/dist/host/agents/skills/orkestrel-polish/SKILL.md +3 -3
  36. package/dist/host/agents/skills/orkestrel-publish/SKILL.md +2 -2
  37. package/dist/host/agents/skills/orkestrel-publish/references/release.md +1 -0
  38. package/dist/host/agents/skills/orkestrel-publish/references/wave.md +56 -13
  39. package/dist/host/agents/skills/orkestrel-publish/references/window.md +6 -6
  40. package/dist/host/agents/skills/orkestrel-publish/scripts/swap.ts +5 -49
  41. package/dist/host/agents/skills/orkestrel-publish/scripts/wave.ts +646 -49
  42. package/dist/host/agents/skills/orkestrel-publish/scripts/window.ts +2 -1
  43. package/dist/host/agents/transports/codex.md +1 -1
  44. package/dist/host/claude/agents/orkestrel.md +54 -53
  45. package/dist/host/claude/agents/reviewer.md +4 -4
  46. package/dist/host/claude/agents/verifier.md +1 -1
  47. package/dist/host/claude/rules/documentation.md +2 -1
  48. package/dist/host/claude/rules/patterns.md +1 -1
  49. package/dist/host/claude/rules/quality.md +2 -2
  50. package/dist/host/claude/rules/styles.md +1 -1
  51. package/dist/host/claude/rules/tests.md +34 -8
  52. package/dist/host/claude/rules/typescript.md +29 -0
  53. package/dist/host/claude/rules/workspace.md +32 -22
  54. package/dist/host/claude/rules/writing.md +34 -26
  55. package/dist/host/claude/settings.json +2 -0
  56. package/dist/host/claude/skills/orkestrel-debrief/SKILL.md +1 -1
  57. package/dist/host/claude/skills/orkestrel-falsify/SKILL.md +1 -1
  58. package/dist/host/claude/skills/orkestrel-parallel/SKILL.md +11 -0
  59. package/dist/host/codex/agents/analyst.toml +3 -3
  60. package/dist/host/codex/agents/reviewer.toml +4 -4
  61. package/dist/host/codex/agents/verifier.toml +3 -1
  62. package/dist/host/configs/policy.ts +13 -2
  63. package/dist/host/dotfiles/editorconfig +0 -1
  64. package/dist/host/dotfiles/gitattributes +0 -1
  65. package/dist/host/dotfiles/gitignore +0 -1
  66. package/dist/host/dotfiles/oxlintrc.json +24 -0
  67. package/dist/host/guides/agent.md +1674 -598
  68. package/dist/host/guides/budget.md +89 -29
  69. package/dist/host/guides/form.md +485 -99
  70. package/dist/host/guides/mcp.md +14 -2
  71. package/dist/host/guides/ollama.md +367 -86
  72. package/dist/host/guides/probe.md +1 -1
  73. package/dist/host/guides/scaffold.md +158 -101
  74. package/dist/host/guides/study.md +3185 -0
  75. package/dist/host/guides/table.md +239 -29
  76. package/dist/host/guides/terminal.md +22 -20
  77. package/dist/host/guides/test.md +776 -315
  78. package/dist/host/manifest.json +117 -65
  79. package/dist/host/tests/config.test.ts +136 -82
  80. package/dist/host/tests/policy.test.ts +41 -3
  81. package/dist/host/tests/setupPolicy.ts +87 -29
  82. package/dist/src/core/index.cjs +1389 -612
  83. package/dist/src/core/index.cjs.map +1 -1
  84. package/dist/src/core/index.d.cts +35 -20
  85. package/dist/src/core/index.d.ts +35 -20
  86. package/dist/src/core/index.js +1387 -613
  87. package/dist/src/core/index.js.map +1 -1
  88. package/dist/src/server/index.cjs +12 -12
  89. package/dist/src/server/index.cjs.map +1 -1
  90. package/dist/src/server/index.d.cts +12 -12
  91. package/dist/src/server/index.d.ts +12 -12
  92. package/dist/src/server/index.js +12 -12
  93. package/dist/src/server/index.js.map +1 -1
  94. package/package.json +5 -5
@@ -60,19 +60,19 @@ The harness's own engine orchestrates: Claude Fable 5.1 or Claude Opus 5.5 in Cl
60
60
  | ------ | ----------------------------------------------------------------------------------------------- | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | ---------------------------------- |
61
61
  | small | none | direct or `builder` | none; the touched test is the review | touched file |
62
62
  | medium | one opinion (`planner` or `analyst`) only when the shape is open | `opus`, `astra`, or `builder` by judgment load | one pass by an independent reviewer per § Engines, on numbered claims about the contract and the risky seams | `verifier` on the touched projects |
63
- | large | one adversarial round: `planner` and `analyst`, same brief, clean contexts, blind to each other | disjoint units in parallel | one `orkestrel-falsify` round on the integrated result | `verifier` tree-wide, once |
63
+ | large | one independent round: `planner` and `analyst`, same brief, clean contexts, blind to each other | disjoint units in parallel | one `orkestrel-falsify` round on the integrated result | `verifier` tree-wide, once |
64
64
 
65
65
  - Never run a review on a small change. Never run a second design round on the same brief.
66
66
  - A fix round re-audits the repaired claim only. A fix that adopted the reviewer's prescription verbatim closes with a mutation probe (disable the load-bearing line, watch the test fail, restore it). A fix that departs from it gets one pass by an independent reviewer per § Engines.
67
67
  - When review rounds at one seam keep surfacing defects without converging on their source, follow `.agents/skills/orkestrel-falsify/SKILL.md` § End the depth search.
68
- - An all-confirmed round ends the audit. A round needs an added or repaired claim to attack; reviewer appetite is not a subject.
68
+ - An all-confirmed round ends the audit. A round needs an added or repaired claim to test; reviewer appetite is not a subject.
69
69
 
70
70
  ## Campaign
71
71
 
72
72
  A large change runs these phases once each, in order, and ends when the exit criterion written at the start is met.
73
73
 
74
74
  1. **Absorb.** Map the terrain with the `orkestrel-scout` skill's `map.ts`, then `grok` distills it and the prior art. In an Orkestrel repository, `verifier` or another tool-capable role collects manifests, lockfiles, installed declarations, and registry readings, and `orkestrel` reconciles them.
75
- 2. **Design.** One adversarial round: `planner` (subjective) and `analyst` (objective) on one brief, clean contexts, blind to each other. Reconcile into one plan: units, owned files, dependencies, parallel and serial order, acceptance criteria, exit criterion, routing ledger.
75
+ 2. **Design.** One independent round: `planner` (subjective) and `analyst` (objective) on one brief, clean contexts, blind to each other. Reconcile into one plan: units, owned files, dependencies, parallel and serial order, acceptance criteria, exit criterion, routing ledger.
76
76
  3. **Implement.** Dispatch units per § Routing and § Parallelism.
77
77
  4. **Integrate.** Apply returned patches to shared files serially. A type, mechanism, or criterion found here is a successor unit, never an integration edit.
78
78
  5. **Audit.** One `orkestrel-falsify` round on the integrated result, an independent reviewer per § Engines in each lane; add `checker` when the criteria are mechanical.
@@ -84,9 +84,9 @@ A large change runs these phases once each, in order, and ends when the exit cri
84
84
 
85
85
  - Fan out when the work is many small, fully specified, disjoint units: one cheap agent per unit with minimal context. Give the agents the same model, effort, agent type, tools, schema, and working directory when isolation and routing allow it, so their prompts share one cache prefix.
86
86
  - Judgment stays narrow: a design or review pass is at most the two lanes the size gate names, each in a clean context, blind to the other, and it runs once. Never fan judgment out further, and never run it as a loop.
87
- - One writer per checkout. Give parallel writers disjoint owned files; give a writer its own worktree under `tmp/worktrees/` only when two units must write the same files at once. Commit a checkpoint before a writing dispatch.
88
- - Shared files are report-only; a unit returns an exact patch.
89
- - Concurrent units validate read-only and scoped to their owned files. Never run tree-wide `format`, lint `--fix`, or `build` beside a live unit.
87
+ - One writer per checkout, except under `orkestrel-parallel`: there, at most three writers share one checkout, each owns disjoint files and disjoint regions of shared files, and one runner lane owns every test, check, and build process. Otherwise give parallel writers disjoint owned files, and give a writer its own worktree under `tmp/worktrees/` only when two units must write the same files at once. Commit a checkpoint before a writing dispatch.
88
+ - Shared files are report-only; a unit returns an exact patch. Under `orkestrel-parallel`, a writer edits its owned regions of a shared file directly.
89
+ - Concurrent units validate read-only and scoped to their owned files; under `orkestrel-parallel`, the runner also runs read-only root checks and reports each finding to the lane that owns its file. Never run tree-wide `format`, lint `--fix`, or `build` beside a live unit.
90
90
  - One Grok lane at a time; queue the rest. An empty lane beside a live probe is starvation, not darkness.
91
91
  - The Orchestrator's own sweep is a writing dispatch: run it before or after the units, never beside them.
92
92
 
@@ -748,7 +748,7 @@ Always wrap skeletons in `aria-hidden="true"` — they are visual scaffolding, n
748
748
  </button>
749
749
  ```
750
750
 
751
- Popovers are **opt-in**: they do nothing until initialized in JS (see [JavaScript initialization](#javascript-initialization)). Only attach them to focusable elements; wrap disabled elements in a `<span tabindex="0">`. `data-bs-html="true"` with untrusted content is an XSS vector.
751
+ Popovers are **opt-in**: they do nothing until initialized in JS (see [JavaScript initialization](#javascript-initialization)). Only attach them to focusable elements; wrap disabled elements in a `<span tabindex="0">`. `data-bs-html="true"` renders untrusted content as unescaped HTML.
752
752
 
753
753
  ### Progress
754
754
 
@@ -980,7 +980,7 @@ Toasts are **opt-in** — hidden until `.show()` is called (or shown through a t
980
980
  </button>
981
981
  ```
982
982
 
983
- Tooltips are **opt-in** (JS init required; see [JavaScript initialization](#javascript-initialization)). Only attach to focusable elements so keyboard users can trigger them; never put essential information _only_ in a tooltip, and never report form errors through a tooltip. `data-bs-html` with untrusted content is an XSS vector.
983
+ Tooltips are **opt-in** (JS init required; see [JavaScript initialization](#javascript-initialization)). Only attach to focusable elements so keyboard users can trigger them; never put essential information _only_ in a tooltip, and never report form errors through a tooltip. `data-bs-html` renders untrusted content as unescaped HTML.
984
984
 
985
985
  ## JavaScript Initialization
986
986
 
@@ -96,7 +96,7 @@ a pass label alone.
96
96
  definition locations, and custom-painted properties reached in each theme and state.
97
97
  - **Reading.** Parse declarations, not color-looking text in comments or strings. Permit raw colors
98
98
  only in the named primitive definitions; reject literals in component paint, unresolved or cyclic
99
- references, and a component bypassing semantic tokens. Check RGB partners where consumed. A theme
99
+ references, and a component skipping semantic tokens. Check RGB partners where consumed. A theme
100
100
  pair may resolve identically unless the design contract requires it to differ.
101
101
  - **Negative control.** Accept a valid primitive definition as a positive fixture. Feed a literal
102
102
  component fill and an undefined token reference; append both to a harness stylesheet through the
@@ -45,7 +45,7 @@ includes app/core so the shared transport contracts have one host-independent ow
45
45
  5. **Own the shutdown contract.**
46
46
  - Serialize lifecycle transitions in call order.
47
47
  - Re-request port zero on an ephemeral restart.
48
- - Close hostile active connections deterministically on stop.
48
+ - Close lingering active connections deterministically on stop.
49
49
  - Release the runner's signal listeners idempotently on stop.
50
50
  - Isolate asynchronous failures by runner generation, so an older transition cannot
51
51
  release a newer run's listeners.
@@ -70,7 +70,7 @@ includes app/core so the shared transport contracts have one host-independent ow
70
70
  compiler for `.vue` blocks, Vite's HTML parser callbacks, its bundled Lightning CSS
71
71
  dependency analyzer, and the TypeScript compiler API for the narrow coding-law pass.
72
72
  - Disable the browser application's public directory, so an unmanaged file copy cannot
73
- bypass the module graph.
73
+ ship outside the module graph.
74
74
  - Keep browser-only runtime tooling development-only.
75
75
  - Require explicit authorization before adding a Sass compiler.
76
76
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: orkestrel-debrief
3
- description: Look back at a long campaign to learn from its mistakes and successes and improve the agents, rules, skills, and processes that ran it. Use after a campaign or milestone closes to run the retrospective - field evidence, layer and boundary audits, package promotion, an adversarial audit of the instruction set itself, process doctrine - and to land every learning as a refinement that propagates, then retire the campaign folder.
3
+ description: Look back at a long campaign to learn from its mistakes and successes and improve the agents, rules, skills, and processes that ran it. Use after a campaign or milestone closes to run the retrospective - field evidence, layer and boundary audits, package promotion, an independent audit of the instruction set itself, process doctrine - and to land every learning as a refinement that propagates, then retire the campaign folder.
4
4
  ---
5
5
 
6
6
  # Debrief a closed campaign
@@ -66,7 +66,7 @@ practice that worked as a refinement, so it repeats.
66
66
  defects versus rounds that churned; anything the orchestrator absorbed that a dispatch
67
67
  owned, or dispatched that the orchestrator owned.
68
68
  5. **Instruction-set audit.** Audit the agents, rules, skills, and orchestration
69
- contract themselves against the campaign record, using the adversarial method in
69
+ contract themselves against the campaign record, using the blind-pass method in
70
70
  [instruction-audit.md](references/instruction-audit.md). What confused an executor is
71
71
  a defect in the instruction, not the executor.
72
72
  6. **Reconcile into the campaign folder.** Number the findings, attach verbatim
@@ -61,7 +61,7 @@ What the field passes repeatedly prove:
61
61
  runs; a refusal that names everything converges even a 2B model.
62
62
  - **Strictness with teaching beats tolerance.** Never coerce, never silently drop;
63
63
  refuse with the correction in the message. Encode untrusted identifiers (JSON-encoded,
64
- length-capped) so hostile input cannot forge or balloon a diagnostic.
64
+ length-capped) so malformed input cannot fake or balloon a diagnostic.
65
65
  - **Acknowledge or state, never both.** Mutations return acknowledgements; reads return
66
66
  state; the split is stated in both tools' descriptions so neither is polled for the
67
67
  other's job.
@@ -1,7 +1,7 @@
1
1
  # Auditing the instruction set
2
2
 
3
3
  The method for judging the agents, rules, skills, and orchestration contract against a
4
- campaign's record. The instruction layer is code — it gets the same adversarial,
4
+ campaign's record. The instruction layer is code — it gets the same skeptical,
5
5
  evidence-first treatment as any surface.
6
6
 
7
7
  ## Blind passes, one brief
@@ -21,8 +21,8 @@ into the brief. A copied list drops a lens silently, and the lane that lost it r
21
21
  full coverage.
22
22
 
23
23
  Reconcile into rulings; every divergence gets a ruled row with the reason. Convergent
24
- findings adopt without contest; a finding neither lane can substantiate dies on the
25
- record.
24
+ findings adopt without contest; a finding neither lane can substantiate is dropped on
25
+ the record.
26
26
 
27
27
  ## The subjective lens list
28
28
 
@@ -10,16 +10,16 @@ description: >-
10
10
 
11
11
  ## Scripts
12
12
 
13
- | Script | Does |
14
- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
15
- | `scripts/bench.ts` | `--cursor [--resolve]`, `--codex [--sandbox MODE]`, or `--claude`, each with `[--model ID] [--cap SECONDS]`: resolves the bench entry, reads its version and login, runs one bounded round trip into `tmp/<bench>/bench.jsonl`, and prints JSON with `live`; `--resolve` prints the Cursor entry alone. Exit 3 when the bench is dark. |
16
- | `scripts/brief.ts` | `--unit UNIT --lane units\|cursor\|codex\|claude [--subject TEXT]` writes the brief from `.agents/templates/brief.md` and never overwrites a launched one; `--check PATH` lists every slash-bearing path the brief names that does not resolve from the root. Exit 3 when one is missing. |
17
- | `scripts/launch.ts` | `--journal PATH --errors PATH --cap SECONDS [--status] -- COMMAND [ARGS...]` runs the command with no shell and closed stdin, kills it at the cap (its process tree on Windows), records `git status --porcelain` before and after with `--status`, prints a spawn line carrying the `pid` when the command starts, writes that pid to `<journal>.pid`, and ends the errors file with `exit=`. Exit 124 when capped; 64 on usage, including a cap above 2147483 seconds. |
18
- | `scripts/login.ts` | `--codex [--cap SECONDS]` reads `codex login status`, runs `codex login --device-auth` journaled to `tmp/codex/login.log` when it is not logged in, prints the URL and the one-time code as they appear, and polls the status until it answers or the cap ends; `--claude` reads `claude auth status`. Exit 0 logged in, 3 not. |
19
- | `scripts/result.ts` | `--cursor\|--claude\|--codex JOURNAL [--out PATH]` prints the session id, the answer length, the run's `exit`, `capped`, and `durationMs` from the errors file, and the journal's `bytes`, `ageMs`, and `lastEvent`. Exit 3 when the journal carries no session or answer. |
20
- | `scripts/cite.ts` | `PATH [--root DIR] [--json]` lists every `file:line` citation in a report whose file does not exist or whose line is past the end. Exit 3 when one does not resolve. |
21
- | `scripts/helpers.ts` | What every skill script shares: `readOption`, `readOptions`, `readList`, `listFiles`, `readJsonObject`, `readString`, `readNumber`, `normalizeSlashes`, `resolveNpm`, `runNpm`. It runs nothing; import it with the `.ts` extension. |
22
- | `scripts/sweep.ts` | `--report` lists leftovers under `tmp/` and `.orkestrel/` by age and deletes nothing; `--tmp [--older-than MINUTES]` deletes stale launch files and refuses while a journal is changing; `--unit UNIT [--delete]` lists or deletes one accepted unit's brief, report, claims, journal, errors, status, pid, and last-message files. |
13
+ | Script | Does |
14
+ | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
15
+ | `scripts/bench.ts` | `--cursor [--resolve]`, `--codex [--sandbox MODE]`, or `--claude`, each with `[--model ID] [--cap SECONDS]`: resolves the bench entry, reads its version and login, runs one bounded round trip into `tmp/<bench>/bench.jsonl`, and prints JSON with `live`; `--resolve` prints the Cursor entry alone. Exit 3 when the bench is dark. |
16
+ | `scripts/brief.ts` | `--unit UNIT --lane units\|cursor\|codex\|claude [--subject TEXT]` writes the brief from `.agents/templates/brief.md` and never overwrites a launched one; `--check PATH` lists every slash-bearing path the brief names that does not resolve from the root. Exit 3 when one is missing. |
17
+ | `scripts/launch.ts` | `--journal PATH --errors PATH --cap SECONDS [--status] -- COMMAND [ARGS...]` runs the command with no shell and closed stdin, kills it at the cap (its process tree on Windows), records `git status --porcelain` before and after with `--status`, prints a spawn line carrying the `pid` when the command starts, writes that pid to `<journal>.pid`, and ends the errors file with `exit=`. Exit 124 when capped; 127 when the command cannot start (the errors file names why); 64 on usage, including a cap above 2147483 seconds. |
18
+ | `scripts/login.ts` | `--codex [--cap SECONDS]` reads `codex login status`, runs `codex login --device-auth` journaled to `tmp/codex/login.log` when it is not logged in, prints the URL and the one-time code as they appear, and polls the status until it answers or the cap ends; `--claude` reads `claude auth status`. Exit 0 logged in, 3 not. |
19
+ | `scripts/result.ts` | `--cursor\|--claude\|--codex JOURNAL [--out PATH]` prints the session id, the answer length, the run's `exit`, `capped`, and `durationMs` from the errors file, and the journal's `bytes`, `ageMs`, and `lastEvent`. Exit 3 when the journal carries no session or answer. |
20
+ | `scripts/cite.ts` | `PATH [--root DIR] [--json]` lists every `file:line` citation in a report whose file does not exist or whose line is past the end. Exit 3 when one does not resolve. |
21
+ | `scripts/helpers.ts` | Import with `.ts`: `readOption`, `readOptions`, `readList`, `listFiles`, `readJsonObject`, `readString`, `readNumber`, `normalizeSlashes`, `resolveNpm`, `runNpm`, `SPEC_FIELDS`, `LOCAL_SPEC_PATTERN`, `ARCHIVE_SPEC_PATTERN`, `SHORTHAND_SPEC_PATTERN`, `matchesLocalSpec`, `collectSpecs`, `scanLocalSpecs`, `removeTree`, `isRecord`. Runs nothing. |
22
+ | `scripts/sweep.ts` | `--report` lists leftovers under `tmp/` and `.orkestrel/` by age and deletes nothing; `--tmp [--older-than MINUTES]` deletes stale launch files and refuses while a journal is changing; `--unit UNIT [--delete]` lists or deletes one accepted unit's brief, report, claims, journal, errors, status, pid, and last-message files. |
23
23
 
24
24
  ## Write the brief
25
25
 
@@ -5,6 +5,7 @@ Apply these rules to every command that outlives the turn that starts it: a benc
5
5
  ## Launch
6
6
 
7
7
  - Launch as a harness-tracked background command through `scripts/launch.ts` under a hard cap. Never detach a run from inside a dispatched agent; an unowned run has no completion signal and no death notice.
8
+ - On Windows, launch npm through its JavaScript entry, `node <directory of node>/node_modules/npm/bin/npm-cli.js ARGS`: `launch.ts` spawns with no shell, a `.cmd` shim cannot start that way, and the launcher reports exit `127`.
8
9
  - Write a multi-step chain as a TypeScript file run by `node`, with an opening comment naming its log, its cap, and what changed from the file it supersedes. Never edit a script while it runs: copy, edit the copy, launch the copy.
9
10
  - On Windows, keep every program-carrying command in a file: a heredoc, `node -e`, an `&&` chain, or a `${...}` argument trips the approval classifier.
10
11
  - Run the first use of any flag, subcommand, or quoting form in a throwaway probe, never inside a unit.
@@ -3,7 +3,7 @@
3
3
  // `.ts` extension, for example `import { readOption } from '../../orkestrel-dispatch/scripts/helpers.ts'`.
4
4
  import type { SpawnSyncReturns } from 'node:child_process'
5
5
  import { spawnSync } from 'node:child_process'
6
- import { existsSync, readdirSync, statSync } from 'node:fs'
6
+ import { existsSync, readdirSync, rmSync, statSync } from 'node:fs'
7
7
  import { dirname, join } from 'node:path'
8
8
 
9
9
  /** Names the directories every tree walk in a skill script skips. */
@@ -16,6 +16,24 @@ export const SKIPPED_DIRECTORIES: ReadonlySet<string> = new Set([
16
16
  '.idea',
17
17
  ])
18
18
 
19
+ /** Names the manifest fields that hold specs, including nested overrides. */
20
+ export const SPEC_FIELDS: readonly string[] = Object.freeze([
21
+ 'dependencies',
22
+ 'devDependencies',
23
+ 'peerDependencies',
24
+ 'optionalDependencies',
25
+ 'overrides',
26
+ ])
27
+
28
+ /** Matches npm local prefixes and path starts, including drive-relative paths. */
29
+ export const LOCAL_SPEC_PATTERN = /^(?:file:|link:|\.|~[\\/]|[\\/]|[A-Za-z]:)/iu
30
+
31
+ /** Matches archive specs with no protocol and a tgz, tar.gz, or tar extension. */
32
+ export const ARCHIVE_SPEC_PATTERN = /^[^:]+\.(?:tgz|tar\.gz|tar)$/iu
33
+
34
+ /** Matches hosted user/repository shorthand even when its name ends in an archive extension. */
35
+ export const SHORTHAND_SPEC_PATTERN = /^[^:@%/\s.-][^:@%/\s]*\/[^:@\s/%]+$/u
36
+
19
37
  /** Describes one file a tree walk found, with the modification time the sweep reads. */
20
38
  export interface WalkedFile {
21
39
  readonly path: string
@@ -29,6 +47,87 @@ export interface NpmCommand {
29
47
  readonly shell: boolean
30
48
  }
31
49
 
50
+ /**
51
+ * Checks whether a value is a non-null, non-array object.
52
+ *
53
+ * @param value - The value to inspect.
54
+ * @returns True if the value is an object other than null or an array; false otherwise.
55
+ * @example
56
+ * isRecord({ dependencies: {} }) // true
57
+ * isRecord([]) // false
58
+ */
59
+ export function isRecord(value: unknown): value is Record<string, unknown> {
60
+ return typeof value === 'object' && value !== null && !Array.isArray(value)
61
+ }
62
+
63
+ /**
64
+ * Checks whether npm resolves a spec from the local host.
65
+ *
66
+ * @param spec - The package spec, with leading whitespace ignored.
67
+ * @returns True if the spec names a local path or archive; false otherwise.
68
+ * @example
69
+ * matchesLocalSpec('file:../other') // true
70
+ * matchesLocalSpec('owner/package.tgz') // false
71
+ */
72
+ export function matchesLocalSpec(spec: string): boolean {
73
+ const text = spec.trimStart()
74
+ return (
75
+ LOCAL_SPEC_PATTERN.test(text) ||
76
+ (ARCHIVE_SPEC_PATTERN.test(text) && !SHORTHAND_SPEC_PATTERN.test(text))
77
+ )
78
+ }
79
+
80
+ /**
81
+ * Collects string specs with the dotted path of each nested record member.
82
+ *
83
+ * @param path - The field path that prefixes each finding.
84
+ * @param value - A string or finite, acyclic manifest record; other values contribute no specs.
85
+ * @returns The path and spec pairs in record order.
86
+ * @example
87
+ * collectSpecs('overrides', { a: { b: 'file:../other' } })
88
+ * // [['overrides.a.b', 'file:../other']]
89
+ */
90
+ export function collectSpecs(
91
+ path: string,
92
+ value: unknown,
93
+ ): ReadonlyArray<readonly [string, string]> {
94
+ if (typeof value === 'string') return [[path, value]]
95
+ if (!isRecord(value)) return []
96
+ return Object.entries(value).flatMap(([key, child]) => collectSpecs(`${path}.${key}`, child))
97
+ }
98
+
99
+ /**
100
+ * Finds local specs in the manifest's spec fields, including nested overrides.
101
+ *
102
+ * @param manifest - A finite, acyclic package manifest record.
103
+ * @returns Each local spec's dotted field path and spec, in field and record order.
104
+ * @example
105
+ * scanLocalSpecs({ overrides: { a: { b: 'file:../other' } } })
106
+ * // [['overrides.a.b', 'file:../other']]
107
+ */
108
+ export function scanLocalSpecs(
109
+ manifest: Readonly<Record<string, unknown>>,
110
+ ): ReadonlyArray<readonly [string, string]> {
111
+ return SPEC_FIELDS.flatMap((field) =>
112
+ collectSpecs(field, manifest[field]).filter(([, spec]) => matchesLocalSpec(spec)),
113
+ )
114
+ }
115
+
116
+ /**
117
+ * Removes a tree with bounded retries for transient host removal errors.
118
+ *
119
+ * @param path - The directory to remove; a missing path succeeds.
120
+ * @returns Nothing after the removal succeeds.
121
+ * @throws Thrown when removal fails after the bounded retries or the host refuses the path.
122
+ * @remarks
123
+ * Uses Node's recursive removal with five retries and a 100 ms retry delay.
124
+ * @example
125
+ * removeTree(scratch.path)
126
+ */
127
+ export function removeTree(path: string): void {
128
+ rmSync(path, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 })
129
+ }
130
+
32
131
  /**
33
132
  * Reads the value that follows a flag.
34
133
  *
@@ -51,6 +51,23 @@ interface Exit {
51
51
  readonly error: string | undefined
52
52
  }
53
53
 
54
+ function startCommand(
55
+ command: string,
56
+ args: readonly string[],
57
+ journal: number,
58
+ errors: number,
59
+ ): ReturnType<typeof spawn> | Exit {
60
+ try {
61
+ return spawn(command, args, { stdio: ['ignore', journal, errors], windowsHide: true })
62
+ } catch (error) {
63
+ return {
64
+ code: null,
65
+ signal: null,
66
+ error: error instanceof Error ? error.message : String(error),
67
+ }
68
+ }
69
+ }
70
+
54
71
  function waitForExit(child: ReturnType<typeof spawn>): Promise<Exit> {
55
72
  return new Promise((resolve) => {
56
73
  child.on('error', (error) => resolve({ code: null, signal: null, error: error.message }))
@@ -94,25 +111,29 @@ async function main(argv: readonly string[]): Promise<number> {
94
111
  const errorsFd = openSync(errors, 'w')
95
112
  rmSync(`${journal}.pid`, { force: true })
96
113
  const started = Date.now()
97
- const child = spawn(command, args, { stdio: ['ignore', journalFd, errorsFd], windowsHide: true })
98
- if (child.pid !== undefined) {
114
+ const launched = startCommand(command, args, journalFd, errorsFd)
115
+ const child = 'error' in launched ? undefined : launched
116
+ if (child?.pid !== undefined) {
99
117
  writeFileSync(`${journal}.pid`, `${child.pid}\n`)
100
118
  console.log(JSON.stringify({ pid: child.pid, journal, errors }))
101
119
  }
102
120
  // The signal aborts once the cap elapses, so whether it aborted is whether the cap ended the run.
103
121
  // The timer cannot be cleared, so a cap that elapses after the child exited kills nothing: a
104
122
  // reused pid is not this command's.
105
- const deadline = capMilliseconds === undefined ? undefined : AbortSignal.timeout(capMilliseconds)
123
+ const deadline =
124
+ child === undefined || capMilliseconds === undefined
125
+ ? undefined
126
+ : AbortSignal.timeout(capMilliseconds)
106
127
  deadline?.addEventListener(
107
128
  'abort',
108
129
  () => {
109
- if (child.pid !== undefined && child.exitCode === null && child.signalCode === null) {
130
+ if (child?.pid !== undefined && child.exitCode === null && child.signalCode === null) {
110
131
  killTree(child.pid)
111
132
  }
112
133
  },
113
134
  { once: true },
114
135
  )
115
- const exit = await waitForExit(child)
136
+ const exit = 'error' in launched ? launched : await waitForExit(launched)
116
137
  const capped = deadline?.aborted === true
117
138
  closeSync(journalFd)
118
139
  closeSync(errorsFd)
@@ -124,7 +145,7 @@ async function main(argv: readonly string[]): Promise<number> {
124
145
  if (status) writeFileSync(`${journal}.status-after.txt`, readStatus())
125
146
  console.log(
126
147
  JSON.stringify({
127
- pid: child.pid,
148
+ pid: child?.pid,
128
149
  exit: exit.error === undefined ? exit.code : 127,
129
150
  signal: exit.signal,
130
151
  capped,
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: orkestrel-falsify
3
3
  description: >-
4
- Run one adversarial audit round against finished work: write the subject as numbered falsifiable claims, dispatch independent auditors instructed to break them, reconcile their evidence, and rule. Use when the size gate in `.agents/orchestration.md` names a review, before a fix round is accepted, before a version bump or publication, or when a defect has recurred across rounds. Do not use it for a small change, a mechanical rename, or a round with no added or repaired claim to attack.
4
+ Run one skeptical audit round against finished work: write the subject as numbered falsifiable claims, dispatch independent auditors instructed to falsify them, reconcile their evidence, and rule. Use when the size gate in `.agents/orchestration.md` names a review, before a fix round is accepted, before a version bump or publication, or when a defect has recurred across rounds. Do not use it for a small change, a mechanical rename, or a round with no added or repaired claim to test.
5
5
  ---
6
6
 
7
7
  # Falsify
@@ -22,7 +22,7 @@ Do not run one for a small change, a rename, or work whose failure the touched t
22
22
  Write `tmp/units/<unit>-claims.md` and point every lane at it. Read `references/brief.md` for the claim form.
23
23
 
24
24
  - State the subject as numbered falsifiable claims: properties a concrete input, state, or interleaving could show false. Never "review this diff".
25
- - Derive claims from adverse conditions: cancellation, restart, concurrency, partial failure, hostile input, resource exhaustion, orderings the happy path never reaches.
25
+ - Derive claims from adverse conditions: cancellation, restart, concurrency, partial failure, malformed or unexpected input, resource exhaustion, orderings the happy path never reaches.
26
26
  - Limit claims to the public contract and the risky seams. A claim about a comment or a name is not a claim.
27
27
  - Supply the evidence the subject type requires: a code change carries the actual diff and `git status --porcelain`; a rendered surface carries its capture portfolio with source as corroboration; a proposal carries the proposal, the canon it must satisfy, and its motivation.
28
28
  - Name where a lane may run a probe (`tmp/probes/` through the `probe` project) and that it deletes the probe before returning.
@@ -40,9 +40,9 @@ Write `tmp/units/<unit>-claims.md` and point every lane at it. Read `references/
40
40
 
41
41
  Every lane returns exactly this:
42
42
 
43
- 1. Numbered verdicts in claim order, one value each: `CONFIRMED` (attacked and held, with the attack), `BROKEN` (the failing input, state, or interleaving plus the smallest correct fix), `UNRESOLVED` (what would settle it; a claim whose only evidence is the writer's report), `NOT-EVIDENCED` (the capture that is missing).
43
+ 1. Numbered verdicts in claim order, one value each: `CONFIRMED` (held against a falsification attempt, with the attempt), `BROKEN` (the failing input, state, or interleaving plus the smallest correct fix), `UNRESOLVED` (what would settle it; a claim whose only evidence is the writer's report), `NOT-EVIDENCED` (the capture that is missing).
44
44
  2. Findings outside the claims, each substantiated to the `BROKEN` standard. After them, list each cost finding that `.claude/rules/quality.md` § Performance rules advisory, marked `ADVISORY`; an advisory never enters the terminal line.
45
- 3. Attacked and held: attacks no verdict line carries, and the adjacent behavior that looks like the defect and is correct.
45
+ 3. Tested and held: tests no verdict line carries, and the adjacent behavior that looks like the defect and is correct.
46
46
  4. One terminal line: `VERDICT: PASS` or `VERDICT: FAIL <claim numbers>; outside the claims: <finding ids or none>`. `PASS` needs every claim `CONFIRMED` and no substantiated outside finding.
47
47
 
48
48
  Before confirming a claim about a proof, the lane names the mutation that would make the proof fail and states whether the assertions distinguish it. No process diary.
@@ -1,4 +1,4 @@
1
1
  interface:
2
2
  display_name: 'Falsify Finished Work'
3
- short_description: 'Run an adversarial audit round that tries to break named claims'
3
+ short_description: 'Run a skeptical audit round that tries to falsify named claims'
4
4
  default_prompt: 'Use $orkestrel-falsify to audit the work that looks finished: numbered falsifiable claims, blind lanes, independent refutation, reconciliation, one ruling.'
@@ -1,6 +1,6 @@
1
1
  # Writing the claims brief
2
2
 
3
- Write every claim sharply enough to be broken. A claim too vague to attack returns a confirmation that proves nothing.
3
+ Write every claim sharply enough to be shown false. A claim too vague to test returns a confirmation that proves nothing.
4
4
 
5
5
  ## Rows
6
6
 
@@ -10,7 +10,7 @@ Give every claims brief these rows.
10
10
  - **What the round decides.** One sentence, such as "this decides whether the package is bumped and consumed downstream" or "this decides whether the fix is accepted".
11
11
  - **Already established.** What the Orchestrator verified directly, so no lane re-derives it or re-reports it. State that the Orchestrator verified each item itself.
12
12
  - **Review evidence.** The actual diff and the actual `git status --porcelain` output, by path. For a rendered or externally driven surface, the capture; source is corroboration.
13
- - **Numbered falsifiable claims.** Written to `tmp/units/<unit>-claims.md`, one file both lanes read. Each claim names a property a concrete input, state, or interleaving could show false. Assign a primary lane where the lanes differ in strength; no lane skips a claim. The claim set is the round's scope: cover what the subject owns, then hold it closed. An attack against something no claim names enters the verdict only when substantiated to the `BROKEN` standard; otherwise it is a claim for the successor brief.
13
+ - **Numbered falsifiable claims.** Written to `tmp/units/<unit>-claims.md`, one file both lanes read. Each claim names a property a concrete input, state, or interleaving could show false. Assign a primary lane where the lanes differ in strength; no lane skips a claim. The claim set is the round's scope: cover what the subject owns, then hold it closed. A finding against something no claim names enters the verdict only when substantiated to the `BROKEN` standard; otherwise it is a claim for the successor brief.
14
14
  - **Unknowns.** What the Orchestrator does not know that the round needs, and how the lane reports on it.
15
15
  - **The threshold.** State that a finding is worth more than a clean pass: the alternative is a consumer finding it after publication.
16
16
 
@@ -27,21 +27,22 @@ A re-run takes a successor brief named per `.agents/orchestration.md` § Dispatc
27
27
  - Add the successor round to the chain table.
28
28
  - Move the closed findings into "already established".
29
29
  - State what changed in the brief itself.
30
- - Add a claim for each ruling the previous round made: an input refused rather than carried, a widening called deliberate, a site called sound and unchanged. Attack those first.
30
+ - Add a claim for each ruling the previous round made: an input refused rather than carried, a widening called deliberate, a site called sound and unchanged. Test those first.
31
31
 
32
32
  ## Claims that find defects
33
33
 
34
- - "The containment has no remaining door." Require the lane to enumerate the surface itself, never a registry, table, or sweep the writer produced.
34
+ - "The containment covers every entry point." Require the lane to enumerate the surface itself, never a registry, table, or sweep the writer produced.
35
35
  - "No refusal was widened into a regression." Require the broken legitimate caller pattern to be named.
36
- - "The instruments bind." Attack the instrument's rule: name a change it would not catch.
36
+ - "The instruments bind." Test the instrument's rule: name a change it would not catch.
37
37
  - "No instrument is vacuous." Require a control that cannot produce its failing verdict; name a tautology a previous round shipped.
38
38
  - "The guide is true." Ask whether a false universal was replaced by an unfalsifiable one.
39
39
  - "The package is coherent as a whole. Would you ship this?"
40
- - "The self-declared sound-and-unchanged verdicts are sound." Require the lane to attack the ones it judges most likely wrong.
40
+ - "The self-declared sound-and-unchanged verdicts are sound." Require the lane to test the ones it judges most likely wrong.
41
+ - "The rewrite preserves behavior." Judge it by `.agents/skills/orkestrel-harden/references/equivalence.md`, and require a differential row for each class it names that the changed code admits.
41
42
 
42
43
  ## Sentences that change lane behavior
43
44
 
44
- - "CONFIRMED requires naming the attack you tried that failed."
45
+ - "CONFIRMED requires naming the falsification you tried that failed."
45
46
  - "A claim you cannot decide is UNRESOLVED, not CONFIRMED; say what would settle it."
46
47
  - "Assume this chain has one more." Name the prior rounds and the defect a previous round believed closed.
47
48
  - "Do not hedge toward an imagined consensus."
@@ -5,9 +5,9 @@ The Orchestrator reconciles and accepts; no lane does. Run a finding rather than
5
5
  ## Reproduce before acting
6
6
 
7
7
  - Treat a lane's finding as a hypothesis until you have run it against the built output. Reproduce every `BROKEN` and every outside finding by hand before it enters a fix brief.
8
- - Construct the hostile input outside the `try` and guard only the call under test, so a harness fault (a missing import, a wrong arity, a `require` in ESM) crashes loudly instead of reading as the finding.
8
+ - Construct the finding's input outside the `try` and guard only the call under test, so a harness fault (a missing import, a wrong arity, a `require` in ESM) crashes loudly instead of reading as the finding.
9
9
  - Record which outcome the reproduction produced: confirmed and wider than reported; confirmed and bounded smaller; or evaporated because the input could not exercise what it claimed.
10
- - Separate a dead finding from a dead vector: a vector the compiler rejects refutes the vector alone. Re-derive one the types admit and record which vector was tested.
10
+ - Separate a dead finding from a dead input: an input the compiler rejects refutes that input alone. Re-derive one the types admit and record which input was tested.
11
11
  - Apply the same discipline to your own probes; a probe whose input cannot reach the code under test reads exactly like a real pass.
12
12
 
13
13
  ## Resolve a disagreement
@@ -25,13 +25,13 @@ Record which engine was right and on what.
25
25
 
26
26
  - Never edit a returned verdict, whoever wrote it.
27
27
  - Write anything a lane says after seeing another lane's report as a separate file beside the verdict under `.orkestrel/<package>/`, named for the unit and the exposure, recording what was shown and to whom. That file is a durable record, never a journal: it survives the campaign sweep, and its contents are promoted into the acceptance record before the folder retires.
28
- - Reach for such an exchange only when a specific factual question survives reproduction; scope it to that question, initiate it yourself, and run it once. Ask the lane to attack the other's evidence on that question; never ask it to resolve the disagreement, reconsider its position, or say whether the other changed its mind.
28
+ - Reach for such an exchange only when a specific factual question survives reproduction; scope it to that question, initiate it yourself, and run it once. Ask the lane to test the other's evidence on that question; never ask it to resolve the disagreement, reconsider its position, or say whether the other changed its mind.
29
29
 
30
30
  ## Bound the finding
31
31
 
32
32
  - State what is not broken and why the adjacent behavior that looks identical is correct.
33
- - List the hostile inputs adjacent to the hole that are correctly contained.
34
- - Where several exports answer a hostile input the same way and one is wrong, name what makes the difference.
33
+ - List the malformed or unexpected inputs adjacent to the defect that are correctly contained.
34
+ - Where several exports answer a malformed or unexpected input the same way and one is wrong, name what makes the difference.
35
35
 
36
36
  ## Bound the fix before briefing it
37
37
 
@@ -54,4 +54,4 @@ Record which engine was right and on what.
54
54
  - Drop, on the record, anything no lane can substantiate against the evidence.
55
55
  - Promote anything that must outlive the round into a durable artifact before the working files are swept.
56
56
  - Assign the fix round's lane to an independent reviewer per `.agents/orchestration.md` § Engines. The next round's brief is this round's successor.
57
- - Accept when the claims are satisfied on evidence (`VERDICT: PASS` against a claim set covering what the subject owns), never on green gates alone. Bound the claim set at the brief, rule on what it returned, and close; never re-run because an attack can still be imagined.
57
+ - Accept when the claims are satisfied on evidence (`VERDICT: PASS` against a claim set covering what the subject owns), never on green gates alone. Bound the claim set at the brief, rule on what it returned, and close; never re-run because a counterexample can still be imagined.
@@ -14,6 +14,7 @@ description: Research, audit, refactor, implement, centralize, test, document, a
14
14
  | Script | Does |
15
15
  | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
16
16
  | `scripts/discovery.ts` | `[--config vite.config.ts] [--projects a,b] [--json]`, run from the checkout root: let Vitest select each gate. Follow root npm script chains and forwarded arguments. Collect an unfiltered universe per config, mode, root, and directory, including the base config. For a root or directory without an explicit config, let Vitest resolve its config. Pass gate arguments verbatim and in order, including separator tokens; remove only reporter, output-file, coverage, color, cache, silent, UI, watch, run-mode, inspector, and standalone options, reading their spellings and arity from installed Vitest help. A listing that outlasts its time limit exits 2 naming its gate. Reuse identical listings and the universe for a gate with no arguments. Use `--filesOnly` for file selection; collect in full for name, tag, line, shard, allow-only, and strict-tag options. Add `--includeTaskLocation` to full listings and compare file, project, name, line, and column without folding browser names. Merge identities across units and retain repeated entries within a listing. Ignore bench, list, mergeReports, listTags, and clearCache invocations as gates. Accept a non-Vitest command that runs a test file directly. Flag partly ungated rows and undiscovered test files. Classify empty rows from Vitest listings; flag an empty project when a chain containing `>` names it, otherwise report a workbench. With `--projects`, let Vitest select the reporting scope and omit the undiscovered-file census. Retry a census when test files change in the workspace, gate roots/directories, or their `tmp/probes` workbenches; refuse changes during the retry. Read files, tests, gates, units, and marker counts in the result. Expect exit 0 with no findings, 3 with findings, 2 for missing Vitest, unsupported related commands, CLI/help/argument/listing/output failures, repeated test-file changes, or filesystem/JSON errors, and 64 on usage. Read the named gate and arguments when Vitest refuses a gate listing. |
17
+ | `scripts/titles.ts` | `--base REV [--root DIR] [--json] [--out FILE]`, run from the checkout root: list every literal `describe`, `it`, and `test` title of the `tests/**/*.test.ts` files at `REV` that the working tree's `tests/**/*.test.ts` files no longer carry as often, comparing exact title text. Balance each-table arguments over code tokens, skipping strings, templates, comments, and regex. Report a missing title that a working-tree `tests/**/*.ts` file holds as a string literal as moved, with that file. Expect exit 0 when no title is missing, 3 when one is, 2 on git, filesystem, lexical, or unbalanced each-argument refusal, and 64 on usage. |
17
18
 
18
19
  ## Select the work lane
19
20
 
@@ -33,6 +34,10 @@ Load [centralization.md](references/centralization.md) for every structural lane
33
34
 
34
35
  Load [hardening.md](references/hardening.md) for the hardening lane and for any request involving concurrency, lifecycle pressure, security boundaries, real services/models, test discovery, or package inspection.
35
36
 
37
+ Load [bindings.md](references/bindings.md) for a census or a sweep under `.claude/rules/typescript.md` § Bindings, together with [equivalence.md](references/equivalence.md).
38
+
39
+ Load [equivalence.md](references/equivalence.md) for a structural lane whose rewrite claims unchanged behavior, and cite it in the claims of the review that judges one.
40
+
36
41
  ## Execute the workflow
37
42
 
38
43
  1. **Bound the campaign.** Record requested outcomes, in-scope environments/domains, explicit exclusions, supported hosts, dirty files, and evidence needed for acceptance.
@@ -42,7 +47,7 @@ Load [hardening.md](references/hardening.md) for the hardening lane and for any
42
47
  5. **Implement completely.** Finish every in-scope branch and reuse the exact installed Orkestrel primitives whose semantics match. The root completion law decides what may not be left behind.
43
48
  6. **Prove each defect before repairing it** per the defect rule in `AGENTS.md` § Work loop. A repair with no red-then-green record is unproven.
44
49
  7. **Consolidate.** Run the complete centralization and wrapper sweep. Update all call sites to the real symbol rather than leaving aliases or 1:1 delegates.
45
- 8. **Challenge seams.** Add deterministic tests for invariants, boundaries, failures, lifecycle, cleanup, cancellation, concurrency, hostile input, and resource pressure as applicable, under the test rules' real-implementation law.
50
+ 8. **Challenge seams.** Add deterministic tests for invariants, boundaries, failures, lifecycle, cleanup, cancellation, concurrency, malformed or unexpected input, and resource pressure as applicable, under the test rules' real-implementation law.
46
51
  9. **Use live services deliberately.** Put real external services/models in their dedicated project, require readiness, and make each request minimally sufficient, stable across the service's nondeterminism, and behaviorally meaningful. When the claim is that a foreign client can use this package, drive one representative real client end to end.
47
52
  10. **Document the final behavior.** Update the governing guide, examples, method tables, limitations, and parity coverage. Document architectural limits honestly.
48
53
  11. **Audit completion.** Run `node .agents/skills/orkestrel-harden/scripts/discovery.ts` and rule on every flag and marker it reports, then inspect source/test helper duplication, exports, environment isolation, unexpected text corruption, and the entire diff.